aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--.github/workflows/checklist.yml1
-rw-r--r--Makefile8
-rw-r--r--Makefile.inc124
-rw-r--r--ObsoleteFiles.inc21
-rw-r--r--RELNOTES8
-rw-r--r--UPDATING16
-rw-r--r--bin/cp/cp.151
-rw-r--r--bin/cp/cp.c90
-rw-r--r--bin/cp/extern.h2
-rwxr-xr-xbin/cp/tests/cp_test.sh195
-rw-r--r--bin/cp/utils.c4
-rw-r--r--bin/df/df.16
-rw-r--r--bin/ps/ps.16
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/dtrace.154
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ticks.d54
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c14
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c73
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h1
-rw-r--r--cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo.c1341
-rw-r--r--cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo_errors.c202
-rw-r--r--cddl/contrib/opensolaris/tests/os-tests/tests/oclo/ocloexec_verify.c154
-rw-r--r--cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile1
-rw-r--r--contrib/bmake/ChangeLog27
-rw-r--r--contrib/bmake/FILES8
-rw-r--r--contrib/bmake/VERSION2
-rw-r--r--contrib/bmake/arch.c6
-rw-r--r--contrib/bmake/bmake.179
-rw-r--r--contrib/bmake/bmake.cat145
-rw-r--r--contrib/bmake/compat.c11
-rw-r--r--contrib/bmake/cond.c89
-rw-r--r--contrib/bmake/for.c12
-rw-r--r--contrib/bmake/job.c42
-rw-r--r--contrib/bmake/job.h4
-rw-r--r--contrib/bmake/main.c54
-rw-r--r--contrib/bmake/make.179
-rw-r--r--contrib/bmake/make.c6
-rw-r--r--contrib/bmake/make.h5
-rw-r--r--contrib/bmake/make_malloc.c7
-rw-r--r--contrib/bmake/mk/ChangeLog4
-rw-r--r--contrib/bmake/mk/prog.mk8
-rw-r--r--contrib/bmake/parse.c19
-rw-r--r--contrib/bmake/str.c9
-rw-r--r--contrib/bmake/unit-tests/Makefile7
-rw-r--r--contrib/bmake/unit-tests/char-005c-reverse-solidus.exp13
-rw-r--r--contrib/bmake/unit-tests/char-005c-reverse-solidus.mk131
-rw-r--r--contrib/bmake/unit-tests/check-expect.lua219
-rw-r--r--contrib/bmake/unit-tests/cmd-errors-jobs.exp4
-rw-r--r--contrib/bmake/unit-tests/cmd-errors-jobs.mk6
-rw-r--r--contrib/bmake/unit-tests/cmd-errors-lint.exp2
-rw-r--r--contrib/bmake/unit-tests/cmd-errors-lint.mk4
-rw-r--r--contrib/bmake/unit-tests/cmd-errors.exp2
-rw-r--r--contrib/bmake/unit-tests/cmd-errors.mk4
-rw-r--r--contrib/bmake/unit-tests/cmdline-undefined.exp20
-rw-r--r--contrib/bmake/unit-tests/cmdline-undefined.mk26
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp4
-rwxr-xr-xcontrib/bmake/unit-tests/cond-cmp-numeric-eq.mk6
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-numeric.exp8
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-numeric.mk10
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-string.exp16
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-string.mk18
-rw-r--r--contrib/bmake/unit-tests/cond-eof.exp6
-rw-r--r--contrib/bmake/unit-tests/cond-eof.mk8
-rw-r--r--contrib/bmake/unit-tests/cond-func-defined.exp4
-rw-r--r--contrib/bmake/unit-tests/cond-func-defined.mk6
-rw-r--r--contrib/bmake/unit-tests/cond-func-make.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-func-make.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-func.exp12
-rw-r--r--contrib/bmake/unit-tests/cond-func.mk14
-rw-r--r--contrib/bmake/unit-tests/cond-late.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-late.mk16
-rw-r--r--contrib/bmake/unit-tests/cond-op-and-lint.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-op-and-lint.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-op-and.exp10
-rw-r--r--contrib/bmake/unit-tests/cond-op-and.mk12
-rw-r--r--contrib/bmake/unit-tests/cond-op-not.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-op-not.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-op-or-lint.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-op-or-lint.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-op-or.exp10
-rw-r--r--contrib/bmake/unit-tests/cond-op-or.mk12
-rw-r--r--contrib/bmake/unit-tests/cond-op-parentheses.exp8
-rw-r--r--contrib/bmake/unit-tests/cond-op-parentheses.mk10
-rw-r--r--contrib/bmake/unit-tests/cond-op.exp14
-rw-r--r--contrib/bmake/unit-tests/cond-op.mk16
-rw-r--r--contrib/bmake/unit-tests/cond-short.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-short.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-token-number.exp8
-rw-r--r--contrib/bmake/unit-tests/cond-token-number.mk10
-rw-r--r--contrib/bmake/unit-tests/cond-token-plain.exp24
-rw-r--r--contrib/bmake/unit-tests/cond-token-plain.mk50
-rw-r--r--contrib/bmake/unit-tests/cond-token-string.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-token-string.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-token-var.exp6
-rw-r--r--contrib/bmake/unit-tests/cond-token-var.mk8
-rw-r--r--contrib/bmake/unit-tests/dep-op-missing.exp2
-rw-r--r--contrib/bmake/unit-tests/deptgt-begin.exp2
-rw-r--r--contrib/bmake/unit-tests/deptgt-begin.mk6
-rw-r--r--contrib/bmake/unit-tests/deptgt-path-suffix.exp2
-rw-r--r--contrib/bmake/unit-tests/deptgt-path-suffix.mk4
-rw-r--r--contrib/bmake/unit-tests/deptgt.exp6
-rw-r--r--contrib/bmake/unit-tests/deptgt.mk8
-rwxr-xr-xcontrib/bmake/unit-tests/directive-dinclude.exp2
-rwxr-xr-xcontrib/bmake/unit-tests/directive-dinclude.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-export-gmake.exp2
-rw-r--r--contrib/bmake/unit-tests/directive-export-gmake.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-for-errors.exp6
-rw-r--r--contrib/bmake/unit-tests/directive-for-errors.mk8
-rw-r--r--contrib/bmake/unit-tests/directive-for-escape.exp10
-rw-r--r--contrib/bmake/unit-tests/directive-for-escape.mk12
-rw-r--r--contrib/bmake/unit-tests/directive-for-lines.exp12
-rw-r--r--contrib/bmake/unit-tests/directive-for-lines.mk20
-rwxr-xr-xcontrib/bmake/unit-tests/directive-for.exp22
-rwxr-xr-xcontrib/bmake/unit-tests/directive-for.mk23
-rwxr-xr-xcontrib/bmake/unit-tests/directive-hyphen-include.exp2
-rwxr-xr-xcontrib/bmake/unit-tests/directive-hyphen-include.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-if.exp2
-rw-r--r--contrib/bmake/unit-tests/directive-if.mk4
-rwxr-xr-xcontrib/bmake/unit-tests/directive-include.exp2
-rwxr-xr-xcontrib/bmake/unit-tests/directive-include.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-misspellings.exp8
-rw-r--r--contrib/bmake/unit-tests/directive-misspellings.mk10
-rwxr-xr-xcontrib/bmake/unit-tests/directive-sinclude.exp2
-rwxr-xr-xcontrib/bmake/unit-tests/directive-sinclude.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-unexport.exp2
-rw-r--r--contrib/bmake/unit-tests/directive-unexport.mk3
-rw-r--r--contrib/bmake/unit-tests/directive-warning.exp6
-rw-r--r--contrib/bmake/unit-tests/directive-warning.mk5
-rw-r--r--contrib/bmake/unit-tests/directive.exp4
-rw-r--r--contrib/bmake/unit-tests/directive.mk6
-rw-r--r--contrib/bmake/unit-tests/moderrs.exp14
-rw-r--r--contrib/bmake/unit-tests/moderrs.mk16
-rw-r--r--contrib/bmake/unit-tests/opt-debug-file.exp6
-rw-r--r--contrib/bmake/unit-tests/opt-debug-file.mk14
-rw-r--r--contrib/bmake/unit-tests/opt-debug-lint.exp4
-rw-r--r--contrib/bmake/unit-tests/opt-debug-lint.mk6
-rw-r--r--contrib/bmake/unit-tests/opt-jobs-internal.exp18
-rw-r--r--contrib/bmake/unit-tests/parse.exp6
-rw-r--r--contrib/bmake/unit-tests/parse.mk8
-rw-r--r--contrib/bmake/unit-tests/var-op-assign.exp2
-rw-r--r--contrib/bmake/unit-tests/var-op-assign.mk4
-rw-r--r--contrib/bmake/unit-tests/var-op-expand.exp14
-rw-r--r--contrib/bmake/unit-tests/var-op-expand.mk8
-rw-r--r--contrib/bmake/unit-tests/varmisc.exp2
-rw-r--r--contrib/bmake/unit-tests/varmisc.mk4
-rw-r--r--contrib/bmake/unit-tests/varmod-edge.exp4
-rw-r--r--contrib/bmake/unit-tests/varmod-edge.mk6
-rw-r--r--contrib/bmake/unit-tests/varmod-ifelse.exp43
-rw-r--r--contrib/bmake/unit-tests/varmod-ifelse.mk11
-rwxr-xr-xcontrib/bmake/unit-tests/varmod-match-escape.exp14
-rwxr-xr-xcontrib/bmake/unit-tests/varmod-match-escape.mk10
-rw-r--r--contrib/bmake/unit-tests/varmod-match.exp20
-rw-r--r--contrib/bmake/unit-tests/varmod-match.mk28
-rw-r--r--contrib/bmake/unit-tests/varmod-mtime.exp6
-rw-r--r--contrib/bmake/unit-tests/varmod-mtime.mk8
-rw-r--r--contrib/bmake/unit-tests/varmod-order.exp6
-rw-r--r--contrib/bmake/unit-tests/varmod-order.mk8
-rw-r--r--contrib/bmake/unit-tests/varmod-range.exp2
-rw-r--r--contrib/bmake/unit-tests/varmod-range.mk4
-rw-r--r--contrib/bmake/unit-tests/varmod.exp49
-rw-r--r--contrib/bmake/unit-tests/varmod.mk49
-rw-r--r--contrib/bmake/unit-tests/varname-circumflex.exp9
-rw-r--r--contrib/bmake/unit-tests/varname-circumflex.mk47
-rw-r--r--contrib/bmake/unit-tests/varname-vpath.exp8
-rw-r--r--contrib/bmake/unit-tests/varname.exp4
-rw-r--r--contrib/bmake/unit-tests/varname.mk6
-rw-r--r--contrib/bmake/unit-tests/varparse-errors.exp28
-rw-r--r--contrib/bmake/unit-tests/varparse-errors.mk30
-rw-r--r--contrib/bmake/var.c38
-rw-r--r--contrib/bsnmp/lib/snmpclient.c12
-rw-r--r--contrib/bsnmp/lib/snmpclient.h1
-rw-r--r--contrib/bsnmp/lib/snmppriv.h1
-rw-r--r--contrib/bsnmp/snmpd/main.c17
-rw-r--r--contrib/bsnmp/snmpd/trans_lsock.c2
-rw-r--r--contrib/elftoolchain/libelf/elf_open.35
-rw-r--r--contrib/elftoolchain/libelf/gelf_xlatetof.311
-rw-r--r--contrib/kyua/utils/fs/operations.cpp2
-rw-r--r--contrib/kyua/utils/fs/operations_test.cpp14
-rw-r--r--contrib/less/NEWS10
-rw-r--r--contrib/less/decode.c2
-rw-r--r--contrib/less/help.c2
-rw-r--r--contrib/less/less.h9
-rw-r--r--contrib/less/less.nro2
-rw-r--r--contrib/less/lessecho.nro2
-rw-r--r--contrib/less/lesskey.nro2
-rw-r--r--contrib/less/os.c6
-rw-r--r--contrib/less/version.c4
-rw-r--r--contrib/libbegemot/rpoll.c22
-rw-r--r--contrib/llvm-project/clang/include/clang/Sema/Sema.h9
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp23
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp10
-rw-r--r--contrib/sqlite3/INSTALL370
-rw-r--r--contrib/sqlite3/Makefile.am19
-rw-r--r--contrib/sqlite3/Makefile.in1326
-rw-r--r--contrib/sqlite3/Makefile.msc50
-rw-r--r--contrib/sqlite3/README.txt98
-rw-r--r--contrib/sqlite3/VERSION1
-rw-r--r--contrib/sqlite3/aclocal.m410204
-rw-r--r--contrib/sqlite3/auto.def25
-rw-r--r--contrib/sqlite3/autosetup/LICENSE35
-rw-r--r--contrib/sqlite3/autosetup/README.autosetup11
-rw-r--r--contrib/sqlite3/autosetup/README.md453
-rwxr-xr-xcontrib/sqlite3/autosetup/autosetup2540
-rwxr-xr-xcontrib/sqlite3/autosetup/autosetup-config.guess (renamed from contrib/sqlite3/config.guess)111
-rwxr-xr-xcontrib/sqlite3/autosetup/autosetup-config.sub (renamed from contrib/sqlite3/config.sub)942
-rwxr-xr-xcontrib/sqlite3/autosetup/autosetup-find-tclsh16
-rw-r--r--contrib/sqlite3/autosetup/autosetup-test-tclsh20
-rw-r--r--contrib/sqlite3/autosetup/cc-db.tcl15
-rw-r--r--contrib/sqlite3/autosetup/cc-lib.tcl187
-rw-r--r--contrib/sqlite3/autosetup/cc-shared.tcl113
-rw-r--r--contrib/sqlite3/autosetup/cc.tcl758
-rw-r--r--contrib/sqlite3/autosetup/find_tclconfig.tcl24
-rw-r--r--contrib/sqlite3/autosetup/jimsh0.c24519
-rw-r--r--contrib/sqlite3/autosetup/pkg-config.tcl168
-rw-r--r--contrib/sqlite3/autosetup/proj.tcl2236
-rw-r--r--contrib/sqlite3/autosetup/sqlite-config.tcl2174
-rw-r--r--contrib/sqlite3/autosetup/system.tcl420
-rw-r--r--contrib/sqlite3/autosetup/teaish/README.txt4
-rw-r--r--contrib/sqlite3/autosetup/teaish/core.tcl2539
-rw-r--r--contrib/sqlite3/autosetup/teaish/feature.tcl214
-rw-r--r--contrib/sqlite3/autosetup/teaish/tester.tcl228
-rwxr-xr-xcontrib/sqlite3/compile348
-rwxr-xr-xcontrib/sqlite3/configure16891
-rw-r--r--contrib/sqlite3/configure.ac270
-rwxr-xr-xcontrib/sqlite3/depcomp791
-rwxr-xr-xcontrib/sqlite3/install-sh541
-rwxr-xr-xcontrib/sqlite3/ltmain.sh11251
-rwxr-xr-xcontrib/sqlite3/missing215
-rw-r--r--contrib/sqlite3/shell.c7276
-rw-r--r--contrib/sqlite3/sqlite3.c17725
-rw-r--r--contrib/sqlite3/sqlite3.h618
-rw-r--r--contrib/sqlite3/sqlite3.pc.in2
-rw-r--r--contrib/sqlite3/sqlite3.rc2
-rw-r--r--contrib/sqlite3/sqlite3ext.h4
-rw-r--r--contrib/sqlite3/sqlite3rc.h2
-rw-r--r--contrib/sqlite3/tea/Makefile.in1006
-rw-r--r--contrib/sqlite3/tea/README36
-rw-r--r--contrib/sqlite3/tea/README.txt104
-rw-r--r--contrib/sqlite3/tea/_teaish.tester.tcl.in49
-rw-r--r--contrib/sqlite3/tea/aclocal.m49
-rw-r--r--contrib/sqlite3/tea/auto.def8
-rwxr-xr-xcontrib/sqlite3/tea/configure10186
-rw-r--r--contrib/sqlite3/tea/configure.ac227
-rw-r--r--contrib/sqlite3/tea/doc/sqlite3.n4
-rw-r--r--contrib/sqlite3/tea/generic/tclsqlite3.c231
-rw-r--r--contrib/sqlite3/tea/pkgIndex.tcl.in40
-rw-r--r--contrib/sqlite3/tea/tclconfig/install-sh528
-rw-r--r--contrib/sqlite3/tea/tclconfig/tcl.m44067
-rw-r--r--contrib/sqlite3/tea/teaish.tcl565
-rw-r--r--contrib/sqlite3/tea/teaish.test.tcl14
-rw-r--r--contrib/sqlite3/tea/win/makefile.vc430
-rw-r--r--contrib/sqlite3/tea/win/nmakehlp.c815
-rw-r--r--contrib/sqlite3/tea/win/rules.vc711
-rw-r--r--contrib/tzcode/localtime.c34
-rw-r--r--etc/mtree/BSD.usr.dist2
-rw-r--r--krb5/lib/crypto/Makefile1
-rw-r--r--krb5/lib/crypto/version.map108
-rw-r--r--krb5/lib/gssapi/Makefile1
-rw-r--r--krb5/lib/gssapi/version.map172
-rw-r--r--krb5/lib/kadm5clnt/Makefile3
-rw-r--r--krb5/lib/kadm5clnt/version.map118
-rw-r--r--krb5/lib/kadm5srv/Makefile1
-rw-r--r--krb5/lib/kadm5srv/version.map137
-rw-r--r--krb5/lib/kdb/Makefile1
-rw-r--r--krb5/lib/kdb/version.map111
-rw-r--r--krb5/lib/krad/Makefile1
-rw-r--r--krb5/lib/krad/version.map26
-rw-r--r--krb5/lib/krb5/Makefile1
-rw-r--r--krb5/lib/krb5/version.map617
-rw-r--r--krb5/lib/rpc/Makefile1
-rw-r--r--krb5/lib/rpc/version.map147
-rw-r--r--krb5/plugins/audit/Makefile1
-rw-r--r--krb5/plugins/audit/version.map10
-rw-r--r--krb5/plugins/k5tls/Makefile1
-rw-r--r--krb5/plugins/k5tls/version.map4
-rw-r--r--krb5/plugins/kdb/db2/Makefile1
-rw-r--r--krb5/plugins/kdb/db2/version.map109
-rw-r--r--krb5/plugins/preauth/otp/Makefile1
-rw-r--r--krb5/plugins/preauth/otp/version.map4
-rw-r--r--krb5/plugins/preauth/pkinit/Makefile1
-rw-r--r--krb5/plugins/preauth/pkinit/version.map5
-rw-r--r--krb5/plugins/preauth/spake/Makefile1
-rw-r--r--krb5/plugins/preauth/spake/version.map5
-rw-r--r--krb5/plugins/preauth/test/Makefile1
-rw-r--r--krb5/plugins/preauth/test/version.map5
-rw-r--r--krb5/util/et/Makefile1
-rw-r--r--krb5/util/et/version.map12
-rw-r--r--krb5/util/profile/Makefile1
-rw-r--r--krb5/util/profile/version.map33
-rw-r--r--krb5/util/support/Makefile1
-rw-r--r--krb5/util/support/version.map102
-rw-r--r--krb5/util/verto/Makefile1
-rw-r--r--krb5/util/verto/libverto.exports33
-rw-r--r--krb5/util/verto/version.map36
-rw-r--r--lib/clang/libclang/Makefile6
-rw-r--r--lib/lib80211/regdomain.xml44
-rw-r--r--lib/libc/gen/Makefile.inc1
-rw-r--r--lib/libc/gen/Symbol.map6
-rw-r--r--lib/libc/gen/dup3.315
-rw-r--r--lib/libc/gen/dup3.c9
-rw-r--r--lib/libc/gen/elf_utils.c26
-rw-r--r--lib/libc/gen/err.c51
-rw-r--r--lib/libc/gen/fdopendir.c17
-rw-r--r--lib/libc/gen/fts.32
-rw-r--r--lib/libc/gen/gen-private.h4
-rw-r--r--lib/libc/gen/inotify.c48
-rw-r--r--lib/libc/gen/libc_interposing_table.c1
-rw-r--r--lib/libc/gen/opendir.c7
-rw-r--r--lib/libc/gen/opendir2.c15
-rw-r--r--lib/libc/gen/readdir.c11
-rw-r--r--lib/libc/gen/scandir.c6
-rw-r--r--lib/libc/gen/telldir.c4
-rw-r--r--lib/libc/gen/telldir.h6
-rw-r--r--lib/libc/gen/uexterr_format.c14
-rw-r--r--lib/libc/gen/wordexp.c10
-rw-r--r--lib/libc/include/libc_private.h4
-rw-r--r--lib/libc/powerpc64/gen/_ctx_start.S14
-rw-r--r--lib/libc/powerpc64/gen/makecontext.c3
-rw-r--r--lib/libc/stdio/fdopen.c18
-rw-r--r--lib/libc/stdio/freopen.c10
-rw-r--r--lib/libc/stdio/mktemp.37
-rw-r--r--lib/libc/stdio/mktemp.c2
-rw-r--r--lib/libc/stdtime/Makefile.inc1
-rw-r--r--lib/libc/stdtime/Symbol.map6
-rw-r--r--lib/libc/string/memchr.316
-rw-r--r--lib/libc/tests/gen/Makefile1
-rw-r--r--lib/libc/tests/gen/opendir_test.c145
-rw-r--r--lib/libc/tests/gen/scandir_test.c12
-rw-r--r--lib/libc/tests/gen/wordexp_test.c26
-rw-r--r--lib/libc/tests/stdtime/Makefile5
-rw-r--r--lib/libc/tests/stdtime/detect_tz_changes_test.c281
-rw-r--r--lib/libc/tests/sys/Makefile4
-rw-r--r--lib/libc/tests/sys/swapcontext_test.c63
-rw-r--r--lib/libcasper/services/cap_dns/tests/dns_test.c37
-rw-r--r--lib/libfetch/common.c7
-rw-r--r--lib/libifconfig/libifconfig.h2
-rw-r--r--lib/libifconfig/libifconfig_bridge.c54
-rw-r--r--lib/libnvmf/libnvmf.h6
-rw-r--r--lib/libnvmf/nvmf_host.c21
-rw-r--r--lib/libopenbsd/Makefile3
-rw-r--r--lib/libopenbsd/recallocarray.c82
-rw-r--r--lib/libprocstat/libprocstat.c5
-rw-r--r--lib/libprocstat/libprocstat.h1
-rw-r--r--lib/libsecureboot/h/libsecureboot.h1
-rw-r--r--lib/libsys/Makefile.sys6
-rw-r--r--lib/libsys/Symbol.sys.map2
-rw-r--r--lib/libsys/_libsys.h4
-rw-r--r--lib/libsys/accept.214
-rw-r--r--lib/libsys/closefrom.29
-rw-r--r--lib/libsys/execve.27
-rw-r--r--lib/libsys/fcntl.245
-rw-r--r--lib/libsys/fhopen.24
-rw-r--r--lib/libsys/fork.212
-rw-r--r--lib/libsys/getdirentries.210
-rw-r--r--lib/libsys/inotify.2379
-rw-r--r--lib/libsys/open.229
-rw-r--r--lib/libsys/pathconf.211
-rw-r--r--lib/libsys/pipe.29
-rw-r--r--lib/libsys/recv.23
-rw-r--r--lib/libsys/socket.213
-rw-r--r--lib/libsys/socketpair.25
-rw-r--r--lib/libsys/statfs.26
-rw-r--r--lib/libsys/syscalls.map4
-rw-r--r--lib/libsysdecode/Makefile1
-rw-r--r--lib/libsysdecode/flags.c22
-rw-r--r--lib/libsysdecode/mktables1
-rw-r--r--lib/libsysdecode/sysdecode.h1
-rw-r--r--lib/libsysdecode/sysdecode_fcntl_arg.33
-rw-r--r--lib/libthr/pthread.map1
-rw-r--r--lib/libthr/thread/thr_list.c38
-rw-r--r--lib/libthr/thread/thr_private.h2
-rw-r--r--lib/libusb/libusb.343
-rw-r--r--lib/libusb/libusb.h28
-rw-r--r--lib/libusb/libusb10.c187
-rw-r--r--lib/libusb/libusb10.h30
-rw-r--r--lib/libusb/libusb10_desc.c11
-rw-r--r--lib/libusb/libusb10_hotplug.c18
-rw-r--r--lib/libusb/libusb10_io.c42
-rw-r--r--lib/libusb/libusb20_desc.h6
-rw-r--r--lib/ncurses/tinfo/Makefile9
-rw-r--r--libexec/flua/linit_flua.c10
-rw-r--r--libexec/flua/modules/lfbsd.c177
-rw-r--r--libexec/flua/modules/lposix.c80
-rw-r--r--libexec/flua/modules/lposix.h8
-rw-r--r--libexec/nuageinit/nuage.lua35
-rwxr-xr-xlibexec/nuageinit/nuageinit7
-rw-r--r--libexec/rc/rc4
-rw-r--r--libexec/rc/rc.conf2
-rwxr-xr-xlibexec/rc/rc.d/hostname4
-rwxr-xr-xlibexec/rc/rc.d/pf2
-rwxr-xr-xlibexec/rc/rc.d/routing2
-rwxr-xr-xlibexec/rc/rc.d/zfs8
-rwxr-xr-xlibexec/rc/rc.d/zfsbe2
-rw-r--r--libexec/rc/rc.shutdown4
-rw-r--r--libexec/rc/rc.subr4
-rw-r--r--libexec/rc/tests/rc_subr_test.sh4
-rw-r--r--libexec/rtld-elf/aarch64/reloc.c7
-rw-r--r--libexec/rtld-elf/map_object.c2
-rw-r--r--libexec/rtld-elf/riscv/reloc.c7
-rw-r--r--libexec/rtld-elf/rtld.c157
-rw-r--r--release/Makefile9
-rwxr-xr-xrelease/amd64/make-memstick.sh7
-rw-r--r--release/amd64/mkisoimages.sh13
-rwxr-xr-xrelease/arm64/make-memstick.sh5
-rw-r--r--release/arm64/mkisoimages.sh13
-rwxr-xr-xrelease/i386/make-memstick.sh9
-rw-r--r--release/i386/mkisoimages.sh5
-rw-r--r--release/packages/Makefile.package193
-rw-r--r--release/packages/certctl.ucl9
-rw-r--r--release/packages/clang-all.ucl1
-rwxr-xr-xrelease/packages/generate-ucl.lua155
-rwxr-xr-xrelease/packages/generate-ucl.sh102
-rw-r--r--release/packages/lld-all.ucl1
-rw-r--r--release/packages/lldb-all.ucl1
-rw-r--r--release/packages/ssh-all.ucl1
-rw-r--r--release/packages/template.ucl6
-rw-r--r--release/packages/ucl/acct-all.ucl4
-rw-r--r--release/packages/ucl/acpi-all.ucl4
-rw-r--r--release/packages/ucl/amd-all.ucl4
-rw-r--r--release/packages/ucl/apm-all.ucl4
-rw-r--r--release/packages/ucl/at-all.ucl4
-rw-r--r--release/packages/ucl/audit-all.ucl4
-rw-r--r--release/packages/ucl/autofs-all.ucl4
-rw-r--r--release/packages/ucl/bhyve-all.ucl4
-rw-r--r--release/packages/ucl/blocklist-all.ucl4
-rw-r--r--release/packages/ucl/bluetooth-all.ucl4
-rw-r--r--release/packages/ucl/bootloader-all.ucl4
-rw-r--r--release/packages/ucl/bsdinstall-all.ucl4
-rw-r--r--release/packages/ucl/bsnmp-all.ucl4
-rw-r--r--release/packages/ucl/caroot-all.ucl4
-rw-r--r--release/packages/ucl/caroot.ucl10
-rw-r--r--release/packages/ucl/ccdconfig-all.ucl5
-rw-r--r--release/packages/ucl/certctl-all.ucl4
-rw-r--r--release/packages/ucl/certctl.ucl6
-rw-r--r--release/packages/ucl/clang-all.ucl5
-rw-r--r--release/packages/ucl/clang.ucl11
-rw-r--r--release/packages/ucl/clibs-all.ucl4
-rw-r--r--release/packages/ucl/clibs.ucl (renamed from release/packages/clibs.ucl)0
-rw-r--r--release/packages/ucl/console-tools-all.ucl4
-rw-r--r--release/packages/ucl/cron-all.ucl4
-rw-r--r--release/packages/ucl/csh-all.ucl4
-rw-r--r--release/packages/ucl/ctf-tools-all.ucl4
-rw-r--r--release/packages/ucl/ctl-all.ucl4
-rw-r--r--release/packages/ucl/cxgbe-tools-all.ucl4
-rw-r--r--release/packages/ucl/devd-all.ucl4
-rw-r--r--release/packages/ucl/devmatch-all.ucl4
-rw-r--r--release/packages/ucl/dhclient-all.ucl4
-rw-r--r--release/packages/ucl/dma-all.ucl4
-rw-r--r--release/packages/ucl/docs-all.ucl4
-rw-r--r--release/packages/ucl/dtb-all.ucl4
-rw-r--r--release/packages/ucl/dtrace-all.ucl4
-rw-r--r--release/packages/ucl/dwatch-all.ucl4
-rw-r--r--release/packages/ucl/ee-all.ucl4
-rw-r--r--release/packages/ucl/efi-tools-all.ucl4
-rw-r--r--release/packages/ucl/examples-all.ucl4
-rw-r--r--release/packages/ucl/fd-all.ucl4
-rw-r--r--release/packages/ucl/fetch-all.ucl4
-rw-r--r--release/packages/ucl/firmware-iwm-all.ucl4
-rw-r--r--release/packages/ucl/ftp-all.ucl4
-rw-r--r--release/packages/ucl/ftpd-all.ucl4
-rw-r--r--release/packages/ucl/fwget-all.ucl4
-rw-r--r--release/packages/ucl/games-all.ucl4
-rw-r--r--release/packages/ucl/geom-all.ucl4
-rw-r--r--release/packages/ucl/ggate-all.ucl4
-rw-r--r--release/packages/ucl/hast-all.ucl4
-rw-r--r--release/packages/ucl/hostapd-all.ucl4
-rw-r--r--release/packages/ucl/hyperv-tools-all.ucl4
-rw-r--r--release/packages/ucl/inetd-all.ucl4
-rw-r--r--release/packages/ucl/ipf-all.ucl4
-rw-r--r--release/packages/ucl/ipfw-all.ucl4
-rw-r--r--release/packages/ucl/iscsi-all.ucl6
-rw-r--r--release/packages/ucl/jail-all.ucl4
-rw-r--r--release/packages/ucl/kerberos-all.ucl4
-rw-r--r--release/packages/ucl/kerberos-lib-all.ucl4
-rw-r--r--release/packages/ucl/kernel-all.ucl4
-rw-r--r--release/packages/ucl/krb5-all.ucl4
-rw-r--r--release/packages/ucl/krb5-lib-all.ucl4
-rw-r--r--release/packages/ucl/lib9p-all.ucl5
-rw-r--r--release/packages/ucl/libarchive-all.ucl4
-rw-r--r--release/packages/ucl/libbegemot-all.ucl5
-rw-r--r--release/packages/ucl/libblocksruntime-all.ucl4
-rw-r--r--release/packages/ucl/libbsdstat-all.ucl5
-rw-r--r--release/packages/ucl/libbsm-all.ucl6
-rw-r--r--release/packages/ucl/libbz2-all.ucl5
-rw-r--r--release/packages/ucl/libcasper-all.ucl5
-rw-r--r--release/packages/ucl/libcompat-all.ucl4
-rw-r--r--release/packages/ucl/libcompiler_rt-all.ucl4
-rw-r--r--release/packages/ucl/libcuse-all.ucl5
-rw-r--r--release/packages/ucl/libdwarf-all.ucl6
-rw-r--r--release/packages/ucl/libevent1-all.ucl4
-rw-r--r--release/packages/ucl/libexecinfo-all.ucl5
-rw-r--r--release/packages/ucl/libipt-all.ucl6
-rw-r--r--release/packages/ucl/libldns-all.ucl6
-rw-r--r--release/packages/ucl/liblzma-all.ucl5
-rw-r--r--release/packages/ucl/libmagic-all.ucl5
-rw-r--r--release/packages/ucl/libopencsd-all.ucl5
-rw-r--r--release/packages/ucl/libpathconv-all.ucl5
-rw-r--r--release/packages/ucl/librpcsec_gss-all.ucl5
-rw-r--r--release/packages/ucl/librss-all.ucl5
-rw-r--r--release/packages/ucl/libsdp-all.ucl5
-rw-r--r--release/packages/ucl/libsqlite3-all.ucl4
-rw-r--r--release/packages/ucl/libstdbuf-all.ucl6
-rw-r--r--release/packages/ucl/libstdthreads-all.ucl4
-rw-r--r--release/packages/ucl/libthread_db-all.ucl5
-rw-r--r--release/packages/ucl/libucl-all.ucl5
-rw-r--r--release/packages/ucl/libufs-all.ucl8
-rw-r--r--release/packages/ucl/libvgl-all.ucl13
-rw-r--r--release/packages/ucl/libvmmapi-all.ucl4
-rw-r--r--release/packages/ucl/liby-all.ucl5
-rw-r--r--release/packages/ucl/libyaml-all.ucl5
-rw-r--r--release/packages/ucl/libzfs-all.ucl5
-rw-r--r--release/packages/ucl/lld-all.ucl6
-rw-r--r--release/packages/ucl/lldb-all.ucl6
-rw-r--r--release/packages/ucl/locales-all.ucl4
-rw-r--r--release/packages/ucl/lp-all.ucl4
-rw-r--r--release/packages/ucl/manuals-all.ucl4
-rw-r--r--release/packages/ucl/mlx-tools-all.ucl4
-rw-r--r--release/packages/ucl/mtree-all.ucl4
-rw-r--r--release/packages/ucl/natd-all.ucl4
-rw-r--r--release/packages/ucl/netmap-all.ucl4
-rw-r--r--release/packages/ucl/newsyslog-all.ucl4
-rw-r--r--release/packages/ucl/nfs-all.ucl4
-rw-r--r--release/packages/ucl/ntp-all.ucl4
-rw-r--r--release/packages/ucl/nuageinit-all.ucl4
-rw-r--r--release/packages/ucl/nvme-tools-all.ucl4
-rw-r--r--release/packages/ucl/openssl-all.ucl4
-rw-r--r--release/packages/ucl/openssl-lib-all.ucl4
-rw-r--r--release/packages/ucl/periodic-all.ucl4
-rw-r--r--release/packages/ucl/periodic.ucl6
-rw-r--r--release/packages/ucl/pf-all.ucl4
-rw-r--r--release/packages/ucl/pkg-bootstrap-all.ucl4
-rw-r--r--release/packages/ucl/ppp-all.ucl5
-rw-r--r--release/packages/ucl/quotacheck-all.ucl8
-rw-r--r--release/packages/ucl/rc-all.ucl4
-rw-r--r--release/packages/ucl/rcmds-all.ucl7
-rw-r--r--release/packages/ucl/rcmds.ucl8
-rw-r--r--release/packages/ucl/rdma-all.ucl1
-rw-r--r--release/packages/ucl/rescue-all.ucl4
-rw-r--r--release/packages/ucl/resolvconf-all.ucl4
-rw-r--r--release/packages/ucl/runtime-all.ucl4
-rw-r--r--release/packages/ucl/runtime.ucl (renamed from release/packages/runtime.ucl)0
-rw-r--r--release/packages/ucl/sendmail-all.ucl4
-rw-r--r--release/packages/ucl/smbutils-all.ucl4
-rw-r--r--release/packages/ucl/src-all.ucl5
-rw-r--r--release/packages/ucl/src-sys-all.ucl5
-rw-r--r--release/packages/ucl/ssh-all.ucl5
-rw-r--r--release/packages/ucl/syscons-data-all.ucl4
-rw-r--r--release/packages/ucl/syslogd-all.ucl4
-rw-r--r--release/packages/ucl/tcpd-all.ucl4
-rw-r--r--release/packages/ucl/telnet-all.ucl4
-rw-r--r--release/packages/ucl/tests-all.ucl4
-rw-r--r--release/packages/ucl/toolchain-all.ucl4
-rw-r--r--release/packages/ucl/ufs-all.ucl4
-rw-r--r--release/packages/ucl/unbound-all.ucl5
-rw-r--r--release/packages/ucl/utilities-all.ucl4
-rw-r--r--release/packages/ucl/utilities.ucl (renamed from release/packages/utilities.ucl)0
-rw-r--r--release/packages/ucl/vi-all.ucl4
-rw-r--r--release/packages/ucl/vt-data-all.ucl4
-rw-r--r--release/packages/ucl/wpa-all.ucl4
-rw-r--r--release/packages/ucl/yp-all.ucl7
-rw-r--r--release/packages/ucl/zfs-all.ucl4
-rw-r--r--release/packages/ucl/zoneinfo-all.ucl5
-rw-r--r--release/packages/unbound-all.ucl1
-rw-r--r--release/powerpc/mkisoimages.sh5
-rwxr-xr-xrelease/riscv/make-memstick.sh5
-rw-r--r--release/riscv/mkisoimages.sh13
-rw-r--r--release/scripts/make-oci-image.sh4
-rw-r--r--release/scripts/tools.subr13
-rw-r--r--release/tools/oci-image-static.conf7
-rw-r--r--release/tools/vmimage.subr7
-rw-r--r--sbin/bectl/bectl.8121
-rw-r--r--sbin/devd/Makefile5
-rw-r--r--sbin/devd/devd.cc11
-rw-r--r--sbin/devd/devd.conf.5122
-rw-r--r--sbin/devd/hyperv.conf1
-rw-r--r--sbin/devd/nvmf.conf7
-rw-r--r--sbin/ifconfig/ifbridge.c184
-rw-r--r--sbin/ifconfig/ifconfig.887
-rw-r--r--sbin/ifconfig/ifgif.c3
-rw-r--r--sbin/ipf/libipf/printhash_live.c3
-rw-r--r--sbin/kldstat/kldstat.c4
-rw-r--r--sbin/mount/mount.86
-rw-r--r--sbin/nvmecontrol/connect.c11
-rw-r--r--sbin/nvmecontrol/nvmecontrol.831
-rw-r--r--sbin/nvmecontrol/reconnect.c17
-rw-r--r--sbin/pfctl/parse.y161
-rw-r--r--sbin/pfctl/pfctl.844
-rw-r--r--sbin/pfctl/pfctl.c578
-rw-r--r--sbin/pfctl/pfctl.h18
-rw-r--r--sbin/pfctl/pfctl_optimize.c36
-rw-r--r--sbin/pfctl/pfctl_osfp.c2
-rw-r--r--sbin/pfctl/pfctl_parser.c24
-rw-r--r--sbin/pfctl/pfctl_parser.h4
-rw-r--r--sbin/pfctl/pfctl_radix.c13
-rw-r--r--sbin/pfctl/pfctl_table.c94
-rw-r--r--sbin/pfctl/tests/files/pf0088.in2
-rw-r--r--sbin/pfctl/tests/files/pf0088.ok2
-rw-r--r--sbin/pfctl/tests/files/pf1072.fail1
-rw-r--r--sbin/pfctl/tests/files/pf1072.in1
-rwxr-xr-xsbin/pfctl/tests/macro.sh1
-rw-r--r--sbin/pfctl/tests/pfctl_test.c25
-rw-r--r--sbin/pfctl/tests/pfctl_test_list.inc1
-rw-r--r--sbin/reboot/reboot.89
-rw-r--r--sbin/reboot/reboot.c7
-rw-r--r--sbin/recoverdisk/recoverdisk.1258
-rw-r--r--sbin/recoverdisk/recoverdisk.c766
-rw-r--r--sbin/route/route_netlink.c1
-rw-r--r--sbin/routed/routed.89
-rw-r--r--sbin/routed/rtquery/rtquery.87
-rw-r--r--sbin/savecore/savecore.86
-rw-r--r--sbin/sysctl/tests/sysctl_test.sh1
-rw-r--r--share/examples/Makefile12
-rw-r--r--share/examples/drivers/README42
-rw-r--r--share/examples/drivers/make_pseudo_driver.sh435
-rw-r--r--share/examples/inotify/Makefile6
-rw-r--r--share/examples/inotify/inotify.c172
-rw-r--r--share/examples/oci/Containerfile.pkg7
-rw-r--r--share/man/man1/Makefile1
-rw-r--r--share/man/man1/builtin.1269
-rw-r--r--share/man/man4/Makefile21
-rw-r--r--share/man/man4/bridge.451
-rw-r--r--share/man/man4/dtrace_dtrace.4191
-rw-r--r--share/man/man4/dtrace_fbt.4332
-rw-r--r--share/man/man4/dtrace_kinst.412
-rw-r--r--share/man/man4/dtrace_profile.4129
-rw-r--r--share/man/man4/gif.4154
-rw-r--r--share/man/man4/hwt.4144
-rw-r--r--share/man/man4/md.44
-rw-r--r--share/man/man4/mtw.478
-rw-r--r--share/man/man4/pf.46
-rw-r--r--share/man/man4/rights.410
-rw-r--r--share/man/man4/sa.43
-rw-r--r--share/man/man4/snd_uaudio.436
-rw-r--r--share/man/man4/ufshci.4181
-rw-r--r--share/man/man5/pf.conf.537
-rw-r--r--share/man/man5/rc.conf.56
-rw-r--r--share/man/man5/src.conf.538
-rw-r--r--share/man/man5/style.Makefile.58
-rw-r--r--share/man/man7/Makefile2
-rw-r--r--share/man/man7/arch.711
-rw-r--r--share/man/man7/d.7287
-rw-r--r--share/man/man7/intro.75
-rw-r--r--share/man/man7/named_attribute.7275
-rw-r--r--share/man/man7/tracing.715
-rw-r--r--share/man/man8/nanobsd.88
-rw-r--r--share/man/man9/Makefile2
-rw-r--r--share/man/man9/VOP_INOTIFY.960
-rw-r--r--share/man/man9/vnode.94
-rw-r--r--share/misc/committers-src.dot5
-rw-r--r--share/mk/bsd.subdir.mk9
-rw-r--r--share/mk/local.sys.machine.mk4
-rw-r--r--share/mk/src.opts.mk2
-rw-r--r--share/termcap/termcap23
-rw-r--r--stand/common/bootstrap.h2
-rw-r--r--stand/common/console.c23
-rw-r--r--stand/common/dev_net.c57
-rw-r--r--stand/common/install.c4
-rw-r--r--stand/defaults/loader.conf2
-rw-r--r--stand/defaults/loader.conf.56
-rw-r--r--stand/efi/libefi/efinet.c2
-rw-r--r--stand/efi/loader/arch/amd64/elf64_freebsd.c8
-rw-r--r--stand/efi/loader/arch/arm/exec.c11
-rw-r--r--stand/efi/loader/arch/arm64/exec.c8
-rw-r--r--stand/efi/loader/arch/i386/elf64_freebsd.c9
-rw-r--r--stand/efi/loader/arch/riscv/exec.c12
-rw-r--r--stand/efi/loader/main.c3
-rw-r--r--stand/libsa/bootp.c78
-rw-r--r--stand/libsa/pkgfs.c33
-rw-r--r--stand/libsa/stand.h13
-rw-r--r--stand/libsa/zfs/zfsimpl.c70
-rw-r--r--sys/amd64/acpica/acpi_wakeup.c18
-rw-r--r--sys/amd64/amd64/apic_vector.S9
-rw-r--r--sys/amd64/amd64/cpu_switch.S4
-rw-r--r--sys/amd64/amd64/efirt_machdep.c33
-rw-r--r--sys/amd64/amd64/exec_machdep.c2
-rw-r--r--sys/amd64/amd64/machdep.c34
-rw-r--r--sys/amd64/amd64/mem.c4
-rw-r--r--sys/amd64/amd64/minidump_machdep.c10
-rw-r--r--sys/amd64/amd64/pmap.c773
-rw-r--r--sys/amd64/amd64/support.S20
-rw-r--r--sys/amd64/amd64/trap.c21
-rw-r--r--sys/amd64/conf/MINIMALUP4
-rw-r--r--sys/amd64/include/efi.h4
-rw-r--r--sys/amd64/include/param.h7
-rw-r--r--sys/amd64/include/pmap.h34
-rw-r--r--sys/amd64/include/smp.h3
-rw-r--r--sys/amd64/include/vmparam.h55
-rw-r--r--sys/amd64/linux/linux_proto.h7
-rw-r--r--sys/amd64/linux/linux_sysent.c4
-rw-r--r--sys/amd64/linux/linux_systrace_args.c40
-rw-r--r--sys/amd64/linux/syscalls.master11
-rw-r--r--sys/amd64/linux32/linux32_proto.h9
-rw-r--r--sys/amd64/linux32/linux32_sysent.c6
-rw-r--r--sys/amd64/linux32/linux32_systrace_args.c54
-rw-r--r--sys/amd64/linux32/syscalls.master15
-rw-r--r--sys/amd64/pt/pt.c978
-rw-r--r--sys/amd64/pt/pt.h49
-rw-r--r--sys/amd64/vmm/intel/vmx_support.S6
-rw-r--r--sys/arm/allwinner/aw_gpio.c8
-rw-r--r--sys/arm/allwinner/aw_mmc.c33
-rw-r--r--sys/arm/allwinner/aw_rtc.c29
-rw-r--r--sys/arm/arm/pmap-v6.c32
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_gpio.c6
-rw-r--r--sys/arm/mv/mvebu_gpio.c1
-rw-r--r--sys/arm/nvidia/as3722_gpio.c2
-rw-r--r--sys/arm/nvidia/tegra_gpio.c1
-rw-r--r--sys/arm64/apple/apple_pinctrl.c20
-rw-r--r--sys/arm64/arm64/pmap.c98
-rw-r--r--sys/arm64/broadcom/genet/if_genet.c4
-rw-r--r--sys/arm64/linux/linux_proto.h7
-rw-r--r--sys/arm64/linux/linux_sysent.c4
-rw-r--r--sys/arm64/linux/linux_systrace_args.c40
-rw-r--r--sys/arm64/linux/syscalls.master11
-rw-r--r--sys/arm64/nvidia/tegra210/max77620_gpio.c2
-rw-r--r--sys/arm64/rockchip/rk_gpio.c12
-rw-r--r--sys/bsm/audit_kevents.h1
-rw-r--r--sys/cam/ata/ata_da.c5
-rw-r--r--sys/cam/cam_periph.c42
-rw-r--r--sys/cam/cam_xpt.c14
-rw-r--r--sys/cam/cam_xpt.h20
-rw-r--r--sys/cam/mmc/mmc_da.c57
-rw-r--r--sys/cam/mmc/mmc_xpt.c1
-rw-r--r--sys/cam/scsi/scsi_all.c12
-rw-r--r--sys/cam/scsi/scsi_cd.c8
-rw-r--r--sys/cam/scsi/scsi_ch.c6
-rw-r--r--sys/cam/scsi/scsi_da.c19
-rw-r--r--sys/cam/scsi/scsi_enc_ses.c5
-rw-r--r--sys/cam/scsi/scsi_sa.c7
-rw-r--r--sys/cam/scsi/scsi_xpt.c56
-rw-r--r--sys/cddl/boot/zfs/zfsimpl.h2
-rw-r--r--sys/compat/freebsd32/freebsd32_syscall.h4
-rw-r--r--sys/compat/freebsd32/freebsd32_syscalls.c2
-rw-r--r--sys/compat/freebsd32/freebsd32_sysent.c4
-rw-r--r--sys/compat/freebsd32/freebsd32_systrace_args.c60
-rw-r--r--sys/compat/linux/linux_dummy.c4
-rw-r--r--sys/compat/linux/linux_file.c121
-rw-r--r--sys/compat/linux/linux_file.h32
-rw-r--r--sys/compat/linuxkpi/common/include/linux/slab.h2
-rw-r--r--sys/compat/linuxkpi/common/src/linux_page.c5
-rw-r--r--sys/conf/files70
-rw-r--r--sys/conf/files.amd648
-rw-r--r--sys/conf/kern.pre.mk4
-rw-r--r--sys/dev/drm2/drm_fb_helper.c2
-rw-r--r--sys/dev/efidev/efirt.c42
-rw-r--r--sys/dev/gpio/acpi_gpiobus.c3
-rw-r--r--sys/dev/gpio/gpiobus.c103
-rw-r--r--sys/dev/gpio/gpiobus_internal.h (renamed from sys/dev/sound/midi/sequencer.h)74
-rw-r--r--sys/dev/gpio/gpiobusvar.h17
-rw-r--r--sys/dev/gpio/gpiopps.c2
-rw-r--r--sys/dev/gpio/ofw_gpiobus.c1
-rw-r--r--sys/dev/gpio/pl061.c12
-rw-r--r--sys/dev/gpio/pl061.h1
-rw-r--r--sys/dev/gpio/pl061_acpi.c15
-rw-r--r--sys/dev/gpio/pl061_fdt.c15
-rw-r--r--sys/dev/gpio/qoriq_gpio.c11
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_chan.c6
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_reg.h10
-rw-r--r--sys/dev/ice/ice_features.h2
-rw-r--r--sys/dev/ice/ice_iflib.h16
-rw-r--r--sys/dev/ice/ice_iov.c1856
-rw-r--r--sys/dev/ice/ice_iov.h125
-rw-r--r--sys/dev/ice/ice_lib.c28
-rw-r--r--sys/dev/ice/ice_lib.h4
-rw-r--r--sys/dev/ice/ice_vf_mbx.c471
-rw-r--r--sys/dev/ice/ice_vf_mbx.h67
-rw-r--r--sys/dev/ice/if_ice_iflib.c132
-rw-r--r--sys/dev/ichiic/ig4_pci.c12
-rw-r--r--sys/dev/iicbus/gpio/tca64xx.c3
-rw-r--r--sys/dev/md/md.c6
-rw-r--r--sys/dev/mem/memutil.c19
-rw-r--r--sys/dev/mgb/if_mgb.c2
-rw-r--r--sys/dev/mlx5/mlx5_accel/ipsec.h8
-rw-r--r--sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c16
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c100
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_rx.c2
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c295
-rw-r--r--sys/dev/nvme/nvme_private.h4
-rw-r--r--sys/dev/nvmf/host/nvmf.c119
-rw-r--r--sys/dev/nvmf/host/nvmf_var.h6
-rw-r--r--sys/dev/nvmf/nvmf.h11
-rw-r--r--sys/dev/ofw/ofw_bus_subr.c101
-rw-r--r--sys/dev/qlnx/qlnxe/qlnx_os.c11
-rw-r--r--sys/dev/random/fortuna.c7
-rw-r--r--sys/dev/random/random_harvestq.c335
-rw-r--r--sys/dev/random/random_harvestq.h2
-rw-r--r--sys/dev/random/randomdev.c2
-rw-r--r--sys/dev/regulator/regulator_fixed.c8
-rw-r--r--sys/dev/sound/midi/midi.c670
-rw-r--r--sys/dev/sound/midi/midi.h7
-rw-r--r--sys/dev/sound/midi/mpu401.c44
-rw-r--r--sys/dev/sound/midi/mpu_if.m11
-rw-r--r--sys/dev/sound/midi/sequencer.c2107
-rw-r--r--sys/dev/sound/midi/synth_if.m312
-rw-r--r--sys/dev/sound/pcm/mixer.c4
-rw-r--r--sys/dev/sound/pcm/sndstat.c7
-rw-r--r--sys/dev/sound/pcm/sound.h8
-rw-r--r--sys/dev/ufshci/ufshci_private.h4
-rw-r--r--sys/dev/ufshci/ufshci_req_sdb.c45
-rw-r--r--sys/dev/usb/controller/xhci_pci.c7
-rw-r--r--sys/dev/vt/hw/vga/vt_vga.c2
-rw-r--r--sys/dev/vt/vt_core.c4
-rw-r--r--sys/fs/fdescfs/fdesc_vnops.c9
-rw-r--r--sys/fs/fuse/fuse_vnops.c197
-rw-r--r--sys/fs/msdosfs/msdosfs_conv.c11
-rw-r--r--sys/fs/msdosfs/msdosfs_lookup.c1
-rw-r--r--sys/fs/msdosfs/msdosfs_vfsops.c3
-rw-r--r--sys/fs/msdosfs/msdosfs_vnops.c35
-rw-r--r--sys/fs/msdosfs/msdosfsmount.h1
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c99
-rw-r--r--sys/fs/nfs/nfs_var.h8
-rw-r--r--sys/fs/nfs/nfsproto.h8
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c10
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c2
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c23
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c93
-rw-r--r--sys/fs/nfsserver/nfs_nfsdserv.c67
-rw-r--r--sys/fs/nullfs/null_subr.c4
-rw-r--r--sys/fs/nullfs/null_vnops.c29
-rw-r--r--sys/fs/p9fs/p9fs_vnops.c8
-rw-r--r--sys/fs/smbfs/smbfs_vnops.c3
-rw-r--r--sys/fs/tmpfs/tmpfs_vnops.c4
-rw-r--r--sys/fs/udf/ecma167-udf.h4
-rw-r--r--sys/fs/udf/udf_vfsops.c7
-rw-r--r--sys/fs/udf/udf_vnops.c48
-rw-r--r--sys/i386/conf/GENERIC2
-rw-r--r--sys/i386/conf/GENERIC-NODEBUG2
-rw-r--r--sys/i386/conf/LINT1
-rw-r--r--sys/i386/conf/MINIMAL2
-rw-r--r--sys/i386/conf/PAE2
-rw-r--r--sys/i386/i386/pmap.c12
-rw-r--r--sys/i386/linux/linux_proto.h9
-rw-r--r--sys/i386/linux/linux_sysent.c6
-rw-r--r--sys/i386/linux/linux_systrace_args.c54
-rw-r--r--sys/i386/linux/syscalls.master15
-rw-r--r--sys/kern/init_sysent.c4
-rw-r--r--sys/kern/kern_descrip.c151
-rw-r--r--sys/kern/kern_resource.c21
-rw-r--r--sys/kern/kern_sendfile.c4
-rw-r--r--sys/kern/kern_sig.c18
-rw-r--r--sys/kern/kern_syscalls.c5
-rw-r--r--sys/kern/subr_asan.c3
-rw-r--r--sys/kern/subr_capability.c4
-rw-r--r--sys/kern/subr_pctrie.c36
-rw-r--r--sys/kern/subr_trap.c5
-rw-r--r--sys/kern/sys_generic.c104
-rw-r--r--sys/kern/sys_pipe.c2
-rw-r--r--sys/kern/syscalls.c2
-rw-r--r--sys/kern/syscalls.master17
-rw-r--r--sys/kern/systrace_args.c60
-rw-r--r--sys/kern/sysv_msg.c2
-rw-r--r--sys/kern/sysv_sem.c2
-rw-r--r--sys/kern/sysv_shm.c2
-rw-r--r--sys/kern/uipc_syscalls.c13
-rw-r--r--sys/kern/uipc_usrreq.c3
-rw-r--r--sys/kern/vfs_aio.c46
-rw-r--r--sys/kern/vfs_cache.c72
-rw-r--r--sys/kern/vfs_default.c18
-rw-r--r--sys/kern/vfs_inotify.c1011
-rw-r--r--sys/kern/vfs_lookup.c177
-rw-r--r--sys/kern/vfs_mount.c2
-rw-r--r--sys/kern/vfs_subr.c100
-rw-r--r--sys/kern/vfs_syscalls.c37
-rw-r--r--sys/kern/vfs_vnops.c7
-rw-r--r--sys/kern/vnode_if.src24
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/efirt/Makefile2
-rw-r--r--sys/modules/ice/Makefile1
-rw-r--r--sys/modules/pt/Makefile8
-rw-r--r--sys/modules/qlnx/qlnxe/Makefile1
-rw-r--r--sys/modules/sound/sound/Makefile6
-rw-r--r--sys/net/ethernet.h23
-rw-r--r--sys/net/if_bridge.c305
-rw-r--r--sys/net/if_bridgevar.h29
-rw-r--r--sys/net/if_ethersubr.c5
-rw-r--r--sys/net/if_gif.h3
-rw-r--r--sys/net/if_lagg.c1
-rw-r--r--sys/net/if_vlan.c1
-rw-r--r--sys/net/if_vlan_var.h7
-rw-r--r--sys/net/pfvar.h67
-rw-r--r--sys/net80211/ieee80211_hostap.c7
-rw-r--r--sys/net80211/ieee80211_ht.c13
-rw-r--r--sys/net80211/ieee80211_node.c30
-rw-r--r--sys/net80211/ieee80211_node.h6
-rw-r--r--sys/net80211/ieee80211_output.c44
-rw-r--r--sys/net80211/ieee80211_vht.c4
-rw-r--r--sys/net80211/ieee80211_vht.h3
-rw-r--r--sys/netinet/icmp_var.h9
-rw-r--r--sys/netinet/in_pcb.c17
-rw-r--r--sys/netinet/in_pcb.h1
-rw-r--r--sys/netinet/ip_icmp.c3
-rw-r--r--sys/netinet/tcp_hpts.c73
-rw-r--r--sys/netinet/tcp_hpts.h17
-rw-r--r--sys/netinet/tcp_input.c48
-rw-r--r--sys/netinet/tcp_log_buf.c2
-rw-r--r--sys/netinet/tcp_log_buf.h8
-rw-r--r--sys/netinet/tcp_stacks/bbr.c22
-rw-r--r--sys/netinet/tcp_stacks/rack.c63
-rw-r--r--sys/netinet/tcp_stacks/rack_bbr_common.c2
-rw-r--r--sys/netinet/tcp_subr.c65
-rw-r--r--sys/netinet/tcp_usrreq.c3
-rw-r--r--sys/netinet6/in6_gif.c18
-rw-r--r--sys/netinet6/mld6.c29
-rw-r--r--sys/netinet6/raw_ip6.c3
-rw-r--r--sys/netipsec/ipsec.c6
-rw-r--r--sys/netipsec/ipsec_offload.c25
-rw-r--r--sys/netipsec/ipsec_offload.h16
-rw-r--r--sys/netipsec/key.c2
-rw-r--r--sys/netlink/netlink_message_parser.h3
-rw-r--r--sys/netpfil/ipfilter/netinet/fil.c29
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c5
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_ftp_pxy.c8
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_htable.c6
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c4
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_irc_pxy.c7
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_lookup.c4
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_nat.c43
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_nat6.c52
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_netbios_pxy.c5
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_pptp_pxy.c5
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_proxy.c4
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_raudio_pxy.c8
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_rcmd_pxy.c8
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_rpcb_pxy.c8
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_state.c22
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c4
-rw-r--r--sys/netpfil/ipfilter/netinet/ipf_rb.h2
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c2
-rw-r--r--sys/netpfil/pf/if_pflog.c6
-rw-r--r--sys/netpfil/pf/if_pfsync.c22
-rw-r--r--sys/netpfil/pf/pf.c229
-rw-r--r--sys/netpfil/pf/pf.h3
-rw-r--r--sys/netpfil/pf/pf_if.c4
-rw-r--r--sys/netpfil/pf/pf_ioctl.c457
-rw-r--r--sys/netpfil/pf/pf_lb.c235
-rw-r--r--sys/netpfil/pf/pf_nl.c68
-rw-r--r--sys/netpfil/pf/pf_ruleset.c31
-rw-r--r--sys/netpfil/pf/pf_table.c92
-rw-r--r--sys/powerpc/aim/mmu_oea.c3
-rw-r--r--sys/powerpc/aim/mmu_oea64.c3
-rw-r--r--sys/powerpc/aim/mmu_radix.c4
-rw-r--r--sys/powerpc/include/pcb.h10
-rw-r--r--sys/powerpc/include/ucontext.h2
-rw-r--r--sys/powerpc/mpc85xx/mpc85xx_gpio.c4
-rw-r--r--sys/powerpc/powerpc/exec_machdep.c39
-rw-r--r--sys/powerpc/powerpc/fpu.c30
-rw-r--r--sys/riscv/allwinner/files.allwinner2
-rw-r--r--sys/riscv/conf/std.allwinner2
-rw-r--r--sys/riscv/riscv/pmap.c2
-rw-r--r--sys/rpc/clnt_rc.c7
-rw-r--r--sys/rpc/rpcsec_gss/rpcsec_gss.c14
-rw-r--r--sys/rpc/rpcsec_tls/rpctls_impl.c8
-rw-r--r--sys/sys/caprights.h2
-rw-r--r--sys/sys/capsicum.h8
-rw-r--r--sys/sys/efi.h18
-rw-r--r--sys/sys/elf_common.h280
-rw-r--r--sys/sys/exterr_cat.h2
-rw-r--r--sys/sys/exterrvar.h1
-rw-r--r--sys/sys/fcntl.h17
-rw-r--r--sys/sys/file.h1
-rw-r--r--sys/sys/filedesc.h2
-rw-r--r--sys/sys/inotify.h158
-rw-r--r--sys/sys/mount.h1
-rw-r--r--sys/sys/namei.h12
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/random.h3
-rw-r--r--sys/sys/resourcevar.h4
-rw-r--r--sys/sys/socket.h6
-rw-r--r--sys/sys/specialfd.h5
-rw-r--r--sys/sys/syscall.h4
-rw-r--r--sys/sys/syscall.mk4
-rw-r--r--sys/sys/syscallsubr.h1
-rw-r--r--sys/sys/sysent.h9
-rw-r--r--sys/sys/sysproto.h14
-rw-r--r--sys/sys/unistd.h2
-rw-r--r--sys/sys/user.h5
-rw-r--r--sys/sys/vnode.h24
-rw-r--r--sys/tools/vnode_if.awk1
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c3
-rw-r--r--sys/ufs/ufs/ufs_lookup.c1
-rw-r--r--sys/ufs/ufs/ufs_vnops.c21
-rw-r--r--sys/ufs/ufs/ufsmount.h2
-rw-r--r--sys/vm/swap_pager.c23
-rw-r--r--sys/vm/vm_domainset.c16
-rw-r--r--sys/vm/vm_fault.c3
-rw-r--r--sys/vm/vm_kern.c9
-rw-r--r--sys/vm/vm_pagequeue.h6
-rw-r--r--sys/x86/linux/linux_dummy_x86.c2
-rw-r--r--tests/Makefile5
-rw-r--r--tests/atf_python/sys/net/vnet.py8
-rw-r--r--tests/ci/Makefile40
-rwxr-xr-xtests/ci/tools/freebsdci12
-rw-r--r--tests/oclo/Makefile11
-rw-r--r--tests/sys/file/closefrom_test.c35
-rw-r--r--tests/sys/file/dup_test.c98
-rw-r--r--tests/sys/kern/Makefile4
-rw-r--r--tests/sys/kern/exterr_test.c108
-rw-r--r--tests/sys/kern/getdirentries_test.c172
-rw-r--r--tests/sys/kern/inotify_test.c864
-rw-r--r--tests/sys/kern/unix_passfd_test.c25
-rwxr-xr-xtests/sys/net/if_bridge_test.sh400
-rwxr-xr-xtests/sys/netinet6/addr6.sh25
-rw-r--r--tests/sys/netpfil/pf/anchor.sh61
-rw-r--r--tests/sys/netpfil/pf/debug.sh50
-rw-r--r--tests/sys/netpfil/pf/header.py23
-rw-r--r--tests/sys/netpfil/pf/icmp.py10
-rw-r--r--tests/sys/netpfil/pf/ioctl/validation.c35
-rw-r--r--tests/sys/netpfil/pf/mbuf.sh6
-rw-r--r--tests/sys/netpfil/pf/nat.sh33
-rw-r--r--tests/sys/netpfil/pf/nat64.py15
-rw-r--r--tests/sys/netpfil/pf/pfsync.sh85
-rw-r--r--tests/sys/netpfil/pf/rdr.sh2
-rw-r--r--tests/sys/netpfil/pf/route_to.sh117
-rw-r--r--tests/sys/netpfil/pf/utils.subr101
-rw-r--r--tools/build/cross-build/include/common/exterr.h14
-rw-r--r--tools/build/cross-build/include/common/sys/exterrvar.h6
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc9
-rw-r--r--tools/build/options/WITH_RUN_TESTS1
-rw-r--r--tools/test/stress2/misc/all.exclude8
-rwxr-xr-xtools/test/stress2/misc/fullpath2.sh2
-rwxr-xr-xtools/test/stress2/misc/syzkaller80.sh320
-rwxr-xr-xtools/test/stress2/misc/syzkaller81.sh72
-rw-r--r--tools/tools/git/git-arc.sh2
-rw-r--r--usr.bin/Makefile1
-rw-r--r--usr.bin/bmake/Makefile.config2
-rw-r--r--usr.bin/bmake/unit-tests/Makefile7
-rw-r--r--usr.bin/calendar/calendars/calendar.freebsd1
-rw-r--r--usr.bin/clang/Makefile4
-rw-r--r--usr.bin/clang/clang-scan-deps/Makefile26
-rw-r--r--usr.bin/clang/clang-scan-deps/clang-scan-deps-driver.cpp18
-rw-r--r--usr.bin/du/du.16
-rw-r--r--usr.bin/find/find.12
-rw-r--r--usr.bin/fortune/datfiles/freebsd-tips2
-rw-r--r--usr.bin/iscsictl/iscsictl.86
-rw-r--r--usr.bin/kdump/kdump.c21
-rw-r--r--usr.bin/kyua/Makefile2
-rw-r--r--usr.bin/last/last.16
-rw-r--r--usr.bin/lockf/lockf.130
-rw-r--r--usr.bin/lockf/lockf.c123
-rw-r--r--usr.bin/lockf/tests/lockf_test.sh103
-rwxr-xr-xusr.bin/man/man.sh13
-rw-r--r--usr.bin/mkimg/mkimg.18
-rw-r--r--usr.bin/mkimg/mkimg.c24
-rw-r--r--usr.bin/mkimg/mkimg.h4
-rw-r--r--usr.bin/mkimg/uuid.c7
-rw-r--r--usr.bin/mkimg/vhd.c2
-rw-r--r--usr.bin/netstat/netstat.136
-rw-r--r--usr.bin/nfsstat/nfsstat.14
-rw-r--r--usr.bin/procstat/procstat.19
-rw-r--r--usr.bin/procstat/procstat_files.c9
-rw-r--r--usr.bin/sed/sed.111
-rw-r--r--usr.bin/shar/Makefile4
-rw-r--r--usr.bin/shar/Makefile.depend10
-rw-r--r--usr.bin/shar/shar.1121
-rw-r--r--usr.bin/shar/shar.sh78
-rw-r--r--usr.bin/sockstat/sockstat.16
-rw-r--r--usr.bin/sockstat/sockstat.c76
-rw-r--r--usr.bin/top/top.13
-rw-r--r--usr.bin/truncate/truncate.130
-rw-r--r--usr.bin/truss/syscall.h1
-rw-r--r--usr.bin/truss/syscalls.c7
-rw-r--r--usr.bin/vmstat/vmstat.86
-rw-r--r--usr.bin/w/w.16
-rw-r--r--usr.bin/wc/wc.16
-rw-r--r--usr.sbin/arp/arp.86
-rwxr-xr-xusr.sbin/bluetooth/bluetooth-config/bluetooth-config.sh8
-rwxr-xr-xusr.sbin/bsdinstall/scripts/pkgbase.in13
-rwxr-xr-xusr.sbin/bsdinstall/scripts/wlanconfig8
-rw-r--r--usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c6
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c9
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h1
-rw-r--r--usr.sbin/certctl/certctl.810
-rwxr-xr-xusr.sbin/certctl/certctl.sh22
-rw-r--r--usr.sbin/crunch/examples/really-big.conf2
-rw-r--r--usr.sbin/efitable/efitable.817
-rw-r--r--usr.sbin/efitable/efitable.c50
-rw-r--r--usr.sbin/fwget/Makefile2
-rw-r--r--usr.sbin/fwget/fwget.814
-rwxr-xr-xusr.sbin/fwget/fwget.sh6
-rw-r--r--usr.sbin/fwget/usb/Makefile10
-rwxr-xr-xusr.sbin/fwget/usb/usb43
-rwxr-xr-xusr.sbin/fwget/usb/usb_ralink12
-rw-r--r--usr.sbin/gstat/gstat.83
-rw-r--r--usr.sbin/inetd/inetd.conf4
-rw-r--r--usr.sbin/lastlogin/lastlogin.84
-rw-r--r--usr.sbin/makefs/ffs.c2
-rw-r--r--usr.sbin/makefs/makefs.816
-rw-r--r--usr.sbin/makefs/tests/Makefile4
-rw-r--r--usr.sbin/makefs/tests/makefs_msdos_tests.sh2
-rw-r--r--usr.sbin/makefs/tests/makefs_zfs_tests.sh92
-rw-r--r--usr.sbin/makefs/zfs.c6
-rw-r--r--usr.sbin/makefs/zfs/dsl.c44
-rw-r--r--usr.sbin/mfiutil/Makefile2
-rw-r--r--usr.sbin/mfiutil/mfi_bbu.c44
-rw-r--r--usr.sbin/mfiutil/mfi_drive.c34
-rw-r--r--usr.sbin/mfiutil/mfi_show.c10
-rw-r--r--usr.sbin/mfiutil/mfiutil.h4
-rw-r--r--usr.sbin/rip6query/rip6query.88
-rw-r--r--usr.sbin/route6d/route6d.87
-rw-r--r--usr.sbin/sesutil/sesutil.86
-rw-r--r--usr.sbin/trim/trim.818
-rw-r--r--usr.sbin/trim/trim.c11
1101 files changed, 83136 insertions, 78646 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index d6c4df7a9776..b03fac2b26b5 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -194,11 +194,13 @@ precommit_task:
matrix:
- name: amd64 smoke test using internal ci systems
only_if: $CIRRUS_REPO_FULL_NAME != 'freebsd/freebsd-src' || $CIRRUS_BRANCH =~ 'pull/.*'
+ trigger_type: manual
env:
TARGET: amd64
TARGET_ARCH: amd64
- name: aarch64 smoke test using internal ci systems
only_if: $CIRRUS_REPO_FULL_NAME != 'freebsd/freebsd-src' || $CIRRUS_BRANCH =~ 'pull/.*'
+ trigger_type: manual
env:
TARGET: arm64
TARGET_ARCH: aarch64
diff --git a/.github/workflows/checklist.yml b/.github/workflows/checklist.yml
index f5c3ea599abf..7f7b0d51f46e 100644
--- a/.github/workflows/checklist.yml
+++ b/.github/workflows/checklist.yml
@@ -89,6 +89,7 @@ jobs:
/* Loop for each key in "checklist". */
for (const c in checklist)
msg += "- " + c + "<sup>" + checklist[c].join(", ") + "</sup>\n";
+ msg += "\nPlease review CONTRIBUTING.md, then update and push your branch again.\n"
comment_func({
owner: context.repo.owner,
diff --git a/Makefile b/Makefile
index 4afec2a80c60..383430307495 100644
--- a/Makefile
+++ b/Makefile
@@ -103,7 +103,7 @@
#
# See src/UPDATING `COMMON ITEMS' for more complete information.
#
-# If TARGET=machine (e.g. powerpc, arm64, ...) is specified you can
+# If TARGET=machine (e.g. powerpc64, arm64, ...) is specified you can
# cross build world for other machine types using the buildworld target,
# and once the world is built you can cross build a kernel using the
# buildkernel target.
@@ -530,8 +530,7 @@ worlds: .PHONY
# Don't build rarely used, semi-supported architectures unless requested.
#
.if defined(EXTRA_TARGETS)
-# powerpcspe excluded from main list until clang fixed
-EXTRA_ARCHES_powerpc= powerpcspe
+EXTRA_ARCHES_powerpc= powerpc powerpcspe
.endif
TARGETS?= ${TARGET_MACHINE_LIST}
_UNIVERSE_TARGETS= ${TARGETS}
@@ -546,8 +545,7 @@ TOOLCHAINS_amd64= amd64-${_GCC_VERSION}
TOOLCHAINS_arm= armv7-${_GCC_VERSION}
TOOLCHAINS_arm64= aarch64-${_GCC_VERSION}
TOOLCHAINS_i386= i386-${_GCC_VERSION}
-TOOLCHAINS_powerpc= powerpc-${_GCC_VERSION} powerpc64-${_GCC_VERSION}
-TOOLCHAIN_powerpc64= powerpc64-${_GCC_VERSION}
+TOOLCHAINS_powerpc= powerpc64-${_GCC_VERSION}
TOOLCHAINS_riscv= riscv64-${_GCC_VERSION}
.endif
diff --git a/Makefile.inc1 b/Makefile.inc1
index d366be09f497..010f5ac2bb55 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -2130,11 +2130,10 @@ create-source-src-package: _pkgbootstrap .PHONY
PKGNAME "src" \
PKGGENNAME "src" \
VERSION "${PKG_VERSION}" \
- DESC "FreeBSD Kernel Sources" \
- COMMENT "FreeBSD Userland Sources" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${SSTAGEDIR}/src.ucl
${PKG_CMD} -o ABI=${PKG_ABI} \
@@ -2155,13 +2154,12 @@ create-source-src-sys-package: _pkgbootstrap .PHONY
> ${SSTAGEDIR}/src-sys.plist
${SRCDIR}/release/packages/generate-ucl.lua \
PKGNAME "src-sys" \
- PKGGENNAME "src" \
+ PKGGENNAME "src-sys" \
VERSION "${PKG_VERSION}" \
- DESC "FreeBSD Kernel Sources" \
- COMMENT "FreeBSD Kernel Sources" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${SSTAGEDIR}/src-sys.ucl
${PKG_CMD} -o ABI=${PKG_ABI} \
@@ -2226,12 +2224,12 @@ create-dtb-package:
@if [ -f ${KSTAGEDIR}/${DISTDIR}/dtb.plist ]; then \
${SRCDIR}/release/packages/generate-ucl.lua \
PKGNAME "dtb" \
+ PKGGENNAME "dtb" \
VERSION "${PKG_VERSION}" \
- COMMENT "FreeBSD Devicetree Blobs" \
- DESC "FreeBSD Devicetree Blobs" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${KSTAGEDIR}/${DISTDIR}/dtb.ucl ; \
awk -F\" ' \
@@ -2257,13 +2255,15 @@ create-kernel-packages-flavor${flavor:C,^""$,${_default_flavor},}: _pkgbootstrap
-v kernel=yes -v _kernconf=${INSTALLKERNEL} ; \
${SRCDIR}/release/packages/generate-ucl.lua \
PKGNAME "kernel-${INSTALLKERNEL:tl}${flavor}" \
+ PKGGENNAME "kernel" \
VERSION "${PKG_VERSION}" \
KERNELDIR "kernel" \
- COMMENT "FreeBSD ${INSTALLKERNEL} kernel ${flavor}" \
- DESC "FreeBSD ${INSTALLKERNEL} kernel ${flavor}" \
+ KERNEL_NAME "${INSTALLKERNEL}" \
+ KERNEL_FLAVOR "${flavor}" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${KSTAGEDIR}/${DISTDIR}/kernel.${INSTALLKERNEL}${flavor}.ucl ; \
awk -F\" ' \
@@ -2296,14 +2296,14 @@ create-kernel-packages-extra-flavor${flavor:C,^""$,${_default_flavor},}-${_kerne
PKGNAME "kernel-${_kernel:tl}${flavor}" \
PKGGENNAME "kernel" \
FORCEINCLUDE "kernel${flavor}" \
- UCLFILES "${SRCDIR}/release/packages/" \
VERSION "${PKG_VERSION}" \
+ KERNEL_NAME "${_kernel:tl}" \
+ KERNEL_FLAVOR "${flavor}" \
KERNELDIR "kernel.${_kernel}" \
- DESC "FreeBSD ${_kernel} kernel ${flavor}" \
- COMMENT "FreeBSD ${_kernel} kernel ${flavor}" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${KSTAGEDIR}/kernel.${_kernel}/kernel.${_kernel}${flavor}.ucl ; \
awk -F\" ' \
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index dcda9a035b44..e5a3da94e127 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -51,16 +51,27 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20250716: Remove an old manual page, vn(4) was removed in FreeBSD 5.0
+OLD_FILES+=usr/share/man/man4/vn.4.gz
+
+# 20250710: share: Delete bitrotted make_*_driver.sh scripts
+OLD_FILES+=usr/share/examples/drivers/README
+OLD_FILES+=usr/share/examples/drivers/make_device_driver.sh
+OLD_FILES+=usr/share/examples/drivers/make_pseudo_driver.sh
+OLD_DIRS+=usr/share/examples/drivers
+
+# 20250710: shar(1) removed
+OLD_FILES+=usr/bin/shar
+
+# 20250708: For 34 days 15.0-CURRENT installed libkadm5clnt symlink without .so
+OLD_FILES+=usr/lib/libkadm5clnt
+
# 20250626: For 11 days 15.0-CURRENT installed libtpool to the wrong location
MOVED_LIBS+=usr/lib/libtpool.so.2
# 20250626: replace yaml.lua with lyaml
OLD_FILES+=usr/share/flua/yaml.lua
-# 20250623: fscandir() renamed to fdscandir()
-OLD_FILES+=usr/share/man/man3/fscandir.3.gz
-OLD_FILES+=usr/share/man/man3/fscandir_b.3.gz
-
# 20250615: don't install man page for absent function
OLD_FILES+=usr/share/man/man9/vm_map_simplify_entry.9.gz
@@ -2481,7 +2492,7 @@ OLD_FILES+=usr/share/man/man4/ng_uni.4.gz
OLD_FILES+=usr/share/man/man4/ngatmbase.4.gz
# 20230308: machine-id merged into hostid_save
-OLD_FILES+=etc/rc.d/machine-id
+OLD_FILES+=etc/rc.d/machine_id
# 20230306: remove tzsetwall(3)
OLD_FILES+=usr/share/man/man3/tzsetwall.3.gz
diff --git a/RELNOTES b/RELNOTES
index 4933c8392552..bd275e809777 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -10,6 +10,14 @@ newline. Entries should be separated by a newline.
Changes to this file should not be MFCed.
+1349a733cf28:
+ Add a driver supporting a new storage controller interface,
+ Universal Flash Storage Host Controller Interface, supporting
+ version 4.1 and earlier, via ufshci(4).
+
+f1f230439fa4:
+ FreeBSD now implements the inotify(2) family of system calls.
+
50e733f19b37, 171f66b0c2ca:
These commits helped improve utilization of NFSv4.1/4.2
delegations. The changes are only used when the NFSv4
diff --git a/UPDATING b/UPDATING
index 8205086dbab5..3fd8a0fd0c0b 100644
--- a/UPDATING
+++ b/UPDATING
@@ -27,6 +27,22 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 15.x IS SLOW:
world, or to merely disable the most expensive debugging functionality
at runtime, run "ln -s 'abort:false,junk:false' /etc/malloc.conf".)
+20250721:
+ WITH_MITKRB5 is now enabled by default. MIT KRB5 has replaced
+ Heimdal in base. Ports that use USES=gssapi must be rebuilt.
+ A clean buildworld is required.
+
+20250719:
+ Commits 392a82b225 and c00baac0ab both changed the
+ internal API between the NFS modules. As such, all
+ these modules need to be rebuilt from sources.
+ __FreeBSD_version was bumped to 1500053 for this.
+
+20250710:
+ The shar(1) utility has been removed from base. The
+ sysutils/freebsd-shar port was created to maintain this version of
+ shar(1) past its removal from base.
+
20250704:
LinuxKPI device.h and acpi changes effecting drivers and drm-kmod.
Bump __FreeBSD_version 1500050 to be able to detect these changes.
diff --git a/bin/cp/cp.1 b/bin/cp/cp.1
index 2856391a029e..5231fa72621c 100644
--- a/bin/cp/cp.1
+++ b/bin/cp/cp.1
@@ -29,7 +29,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 28, 2024
+.Dd July 9, 2025
.Dt CP 1
.Os
.Sh NAME
@@ -84,16 +84,16 @@ If the
.Fl R
option is specified, symbolic links on the command line are followed.
(Symbolic links encountered in the tree traversal are not followed.)
-.It Fl L
+.It Fl L , Fl -dereference
If the
.Fl R
option is specified, all symbolic links are followed.
-.It Fl P
+.It Fl P , Fl -no-dereference
No symbolic links are followed.
This is the default if the
.Fl R
option is specified.
-.It Fl R
+.It Fl R , Fl -recursive
If
.Ar source_file
designates a directory,
@@ -121,11 +121,11 @@ If you need to preserve hard links, consider using
or
.Xr pax 1
instead.
-.It Fl a
+.It Fl a , Fl -archive
Archive mode.
Same as
.Fl RpP .
-.It Fl f
+.It Fl f , Fl -force
For each existing destination pathname, remove it and
create a new file, without prompting for confirmation
regardless of its permissions.
@@ -136,10 +136,8 @@ option overrides any previous
or
.Fl n
options.)
-.It Fl i
-Cause
-.Nm
-to write a prompt to the standard error output before copying a file
+.It Fl i , Fl -interactive
+Write a prompt to the standard error output before copying a file
that would overwrite an existing file.
If the response from the standard input begins with the character
.Sq Li y
@@ -153,13 +151,13 @@ option overrides any previous
or
.Fl n
options.)
-.It Fl l
+.It Fl l , Fl -link
Create hard links to regular files in a hierarchy instead of copying.
.It Fl N
When used with
.Fl p ,
suppress copying file flags.
-.It Fl n
+.It Fl n , Fl -no-clobber
Do not overwrite an existing file.
(The
.Fl n
@@ -169,9 +167,7 @@ or
.Fl i
options.)
.It Fl p
-Cause
-.Nm
-to preserve the following attributes of each source
+Preserve the following attributes of each source
file in the copy: modification time, access time,
file flags, file mode, ACL, user ID, and group ID, as allowed by permissions.
.Pp
@@ -188,14 +184,25 @@ If the source file has both its set-user-ID and set-group-ID bits on,
and either the user ID or group ID cannot be preserved, neither
the set-user-ID nor set-group-ID bits are preserved in the copy's
permissions.
-.It Fl s
-Create symbolic links to regular files in a hierarchy instead of copying.
-.It Fl v
-Cause
+.It Fl -sort
+Visit and traverse sources in (non-localized) lexicographical order.
+Normally,
.Nm
-to be verbose, showing files as they are copied.
-.It Fl x
-File system mount points are not traversed.
+visits the sources in the order they were listed on the command line,
+and if recursing, traverses their contents in whichever order they
+were returned in by the kernel, which may be the order in which they
+were created, lexicographical order, or something else entirely.
+With
+.Fl -sort ,
+the sources are both visited and traversed in lexicographical order.
+This is mostly useful for testing.
+.It Fl s , Fl -symbolic-link
+Create symbolic links to regular files in a hierarchy instead of copying.
+.It Fl v , Fl -verbose
+Be verbose, showing both the source and destination path of each file
+as is copied.
+.It Fl x , Fl -one-file-system
+Do not traverse file system mount points.
.El
.Pp
For each destination file that already exists, its contents are
diff --git a/bin/cp/cp.c b/bin/cp/cp.c
index 7e97715c3ef4..38fe65399d06 100644
--- a/bin/cp/cp.c
+++ b/bin/cp/cp.c
@@ -55,6 +55,7 @@
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
+#include <getopt.h>
#include <limits.h>
#include <signal.h>
#include <stdbool.h>
@@ -69,8 +70,8 @@ static char dot[] = ".";
#define END(buf) (buf + sizeof(buf))
PATH_T to = { .dir = -1, .end = to.path };
-int Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
-static int Hflag, Lflag, Pflag, Rflag, rflag;
+bool Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
+static bool Hflag, Lflag, Pflag, Rflag, rflag, Sflag;
volatile sig_atomic_t info;
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
@@ -78,6 +79,27 @@ enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
static int copy(char *[], enum op, int, struct stat *);
static void siginfo(int __unused);
+enum {
+ SORT_OPT = CHAR_MAX,
+};
+
+static const struct option long_opts[] =
+{
+ { "archive", no_argument, NULL, 'a' },
+ { "force", no_argument, NULL, 'f' },
+ { "interactive", no_argument, NULL, 'i' },
+ { "dereference", no_argument, NULL, 'L' },
+ { "link", no_argument, NULL, 'l' },
+ { "no-clobber", no_argument, NULL, 'n' },
+ { "no-dereference", no_argument, NULL, 'P' },
+ { "recursive", no_argument, NULL, 'R' },
+ { "symbolic-link", no_argument, NULL, 's' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "one-file-system", no_argument, NULL, 'x' },
+ { "sort", no_argument, NULL, SORT_OPT },
+ { 0 }
+};
+
int
main(int argc, char *argv[])
{
@@ -88,63 +110,67 @@ main(int argc, char *argv[])
bool have_trailing_slash = false;
fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
- while ((ch = getopt(argc, argv, "HLPRafilNnprsvx")) != -1)
+ while ((ch = getopt_long(argc, argv, "+HLPRafilNnprsvx", long_opts,
+ NULL)) != -1)
switch (ch) {
case 'H':
- Hflag = 1;
- Lflag = Pflag = 0;
+ Hflag = true;
+ Lflag = Pflag = false;
break;
case 'L':
- Lflag = 1;
- Hflag = Pflag = 0;
+ Lflag = true;
+ Hflag = Pflag = false;
break;
case 'P':
- Pflag = 1;
- Hflag = Lflag = 0;
+ Pflag = true;
+ Hflag = Lflag = false;
break;
case 'R':
- Rflag = 1;
+ Rflag = true;
break;
case 'a':
- pflag = 1;
- Rflag = 1;
- Pflag = 1;
- Hflag = Lflag = 0;
+ pflag = true;
+ Rflag = true;
+ Pflag = true;
+ Hflag = Lflag = false;
break;
case 'f':
- fflag = 1;
- iflag = nflag = 0;
+ fflag = true;
+ iflag = nflag = false;
break;
case 'i':
- iflag = 1;
- fflag = nflag = 0;
+ iflag = true;
+ fflag = nflag = false;
break;
case 'l':
- lflag = 1;
+ lflag = true;
break;
case 'N':
- Nflag = 1;
+ Nflag = true;
break;
case 'n':
- nflag = 1;
- fflag = iflag = 0;
+ nflag = true;
+ fflag = iflag = false;
break;
case 'p':
- pflag = 1;
+ pflag = true;
break;
case 'r':
- rflag = Lflag = 1;
- Hflag = Pflag = 0;
+ rflag = Lflag = true;
+ Hflag = Pflag = false;
break;
case 's':
- sflag = 1;
+ sflag = true;
break;
case 'v':
- vflag = 1;
+ vflag = true;
break;
case 'x':
fts_options |= FTS_XDEV;
break;
+ case SORT_OPT:
+ Sflag = true;
+ break;
default:
usage();
}
@@ -159,7 +185,7 @@ main(int argc, char *argv[])
if (lflag && sflag)
errx(1, "the -l and -s options may not be specified together");
if (rflag)
- Rflag = 1;
+ Rflag = true;
if (Rflag) {
if (Hflag)
fts_options |= FTS_COMFOLLOW;
@@ -263,6 +289,12 @@ main(int argc, char *argv[])
}
static int
+ftscmp(const FTSENT * const *a, const FTSENT * const *b)
+{
+ return (strcmp((*a)->fts_name, (*b)->fts_name));
+}
+
+static int
copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
{
char rootname[NAME_MAX];
@@ -305,7 +337,7 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
}
level = FTS_ROOTLEVEL;
- if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
+ if ((ftsp = fts_open(argv, fts_options, Sflag ? ftscmp : NULL)) == NULL)
err(1, "fts_open");
for (badcp = rval = 0;
(curr = fts_read(ftsp)) != NULL;
diff --git a/bin/cp/extern.h b/bin/cp/extern.h
index c0c524756980..683e6e5f289f 100644
--- a/bin/cp/extern.h
+++ b/bin/cp/extern.h
@@ -37,7 +37,7 @@ typedef struct {
} PATH_T;
extern PATH_T to;
-extern int Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
+extern bool Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
extern volatile sig_atomic_t info;
__BEGIN_DECLS
diff --git a/bin/cp/tests/cp_test.sh b/bin/cp/tests/cp_test.sh
index 1d2cd4292459..999993bfad67 100755
--- a/bin/cp/tests/cp_test.sh
+++ b/bin/cp/tests/cp_test.sh
@@ -34,6 +34,10 @@ check_size()
}
atf_test_case basic
+basic_head()
+{
+ atf_set "descr" "Copy a file"
+}
basic_body()
{
echo "foo" > bar
@@ -43,18 +47,26 @@ basic_body()
}
atf_test_case basic_symlink
+basic_symlink_head()
+{
+ atf_set "descr" "Copy a symlink to a file"
+}
basic_symlink_body()
{
echo "foo" > bar
ln -s bar baz
atf_check cp baz foo
- atf_check test '!' -L foo
+ atf_check test ! -L foo
atf_check cmp foo bar
}
atf_test_case chrdev
+chrdev_head()
+{
+ atf_set "descr" "Copy a character device"
+}
chrdev_body()
{
echo "foo" > bar
@@ -69,6 +81,10 @@ chrdev_body()
}
atf_test_case hardlink
+hardlink_head()
+{
+ atf_set "descr" "Create a hard link to a file"
+}
hardlink_body()
{
echo "foo" >foo
@@ -78,6 +94,11 @@ hardlink_body()
}
atf_test_case hardlink_exists
+hardlink_exists_head()
+{
+ atf_set "descr" "Attempt to create a hard link to a file, " \
+ "but the destination already exists"
+}
hardlink_exists_body()
{
echo "foo" >foo
@@ -88,6 +109,11 @@ hardlink_exists_body()
}
atf_test_case hardlink_exists_force
+hardlink_exists_force_head()
+{
+ atf_set "descr" "Force creation of a hard link to a file " \
+ "when the destination already exists"
+}
hardlink_exists_force_body()
{
echo "foo" >foo
@@ -98,9 +124,12 @@ hardlink_exists_force_body()
}
atf_test_case matching_srctgt
+matching_srctgt_head()
+{
+ atf_set "descr" "Avoid infinite loop when copying a directory to itself"
+}
matching_srctgt_body()
{
-
# PR235438: `cp -R foo foo` would previously infinitely recurse and
# eventually error out.
mkdir foo
@@ -110,13 +139,17 @@ matching_srctgt_body()
atf_check cp -R foo foo
atf_check -o inline:"qux\n" cat foo/foo/bar
atf_check -o inline:"qux\n" cat foo/foo/zoo
- atf_check -e not-empty -s not-exit:0 stat foo/foo/foo
+ atf_check test ! -e foo/foo/foo
}
atf_test_case matching_srctgt_contained
+matching_srctgt_contained_head()
+{
+ atf_set "descr" "Avoid infinite loop when copying a directory " \
+ "into an existing subdirectory of itself"
+}
matching_srctgt_contained_body()
{
-
# Let's do the same thing, except we'll try to recursively copy foo into
# one of its subdirectories.
mkdir foo
@@ -142,9 +175,13 @@ matching_srctgt_contained_body()
}
atf_test_case matching_srctgt_link
+matching_srctgt_link_head()
+{
+ atf_set "descr" "Avoid infinite loop when recursively copying a " \
+ "symlink to a directory into the directory it links to"
+}
matching_srctgt_link_body()
{
-
mkdir foo
echo "qux" > foo/bar
cp foo/bar foo/zoo
@@ -156,9 +193,13 @@ matching_srctgt_link_body()
}
atf_test_case matching_srctgt_nonexistent
+matching_srctgt_nonexistent_head()
+{
+ atf_set "descr" "Avoid infinite loop when recursively copying a " \
+ "directory into a new subdirectory of itself"
+}
matching_srctgt_nonexistent_body()
{
-
# We'll copy foo to a nonexistent subdirectory; ideally, we would
# skip just the directory and end up with a layout like;
#
@@ -180,6 +221,10 @@ matching_srctgt_nonexistent_body()
}
atf_test_case pflag_acls
+pflag_acls_head()
+{
+ atf_set "descr" "Verify that -p preserves access control lists"
+}
pflag_acls_body()
{
mkdir dir
@@ -216,6 +261,10 @@ pflag_acls_body()
}
atf_test_case pflag_flags
+pflag_flags_head()
+{
+ atf_set "descr" "Verify that -p preserves file flags"
+}
pflag_flags_body()
{
mkdir dir
@@ -263,6 +312,11 @@ recursive_link_setup()
}
atf_test_case recursive_link_dflt
+recursive_link_dflt_head()
+{
+ atf_set "descr" "Copy a directory containing a subdirectory and a " \
+ "symlink to that subdirectory"
+}
recursive_link_dflt_body()
{
recursive_link_setup
@@ -270,9 +324,15 @@ recursive_link_dflt_body()
# -P is the default, so this should work and preserve the link.
atf_check cp -R foo foo-mirror
atf_check test -L foo-mirror/foo/baz
+ atf_check test -d foo-mirror/foo/baz
}
atf_test_case recursive_link_Hflag
+recursive_link_Hflag_head()
+{
+ atf_set "descr" "Copy a directory containing a subdirectory and a " \
+ "symlink to that subdirectory"
+}
recursive_link_Hflag_body()
{
recursive_link_setup
@@ -281,22 +341,32 @@ recursive_link_Hflag_body()
# link.
atf_check cp -RH foo foo-mirror
atf_check test -L foo-mirror/foo/baz
+ atf_check test -d foo-mirror/foo/baz
}
atf_test_case recursive_link_Lflag
+recursive_link_Lflag_head()
+{
+ atf_set "descr" "Copy a directory containing a subdirectory and a " \
+ "symlink to that subdirectory"
+}
recursive_link_Lflag_body()
{
recursive_link_setup -L
# -L will work, but foo/baz ends up expanded to a directory.
- atf_check test -d foo-mirror/foo/baz -a \
- '(' ! -L foo-mirror/foo/baz ')'
+ atf_check test ! -L foo-mirror/foo/baz
+ atf_check test -d foo-mirror/foo/baz
atf_check cp -RL foo foo-mirror
- atf_check test -d foo-mirror/foo/baz -a \
- '(' ! -L foo-mirror/foo/baz ')'
+ atf_check test ! -L foo-mirror/foo/baz
+ atf_check test -d foo-mirror/foo/baz
}
atf_test_case samefile
+samefile_head()
+{
+ atf_set "descr" "Copy a file to itself"
+}
samefile_body()
{
echo "foo" >foo
@@ -324,6 +394,10 @@ files_are_equal()
}
atf_test_case sparse_leading_hole
+sparse_leading_hole_head()
+{
+ atf_set "descr" "Copy a sparse file stat starts with a hole"
+}
sparse_leading_hole_body()
{
# A 16-megabyte hole followed by one megabyte of data
@@ -337,6 +411,10 @@ sparse_leading_hole_body()
}
atf_test_case sparse_multiple_holes
+sparse_multiple_hole_head()
+{
+ atf_set "descr" "Copy a sparse file with multiple holes"
+}
sparse_multiple_holes_body()
{
# Three one-megabyte blocks of data preceded, separated, and
@@ -356,6 +434,10 @@ sparse_multiple_holes_body()
}
atf_test_case sparse_only_hole
+sparse_only_hole_head()
+{
+ atf_set "descr" "Copy a sparse file consisting entirely of a hole"
+}
sparse_only_hole_body()
{
# A 16-megabyte hole
@@ -368,6 +450,10 @@ sparse_only_hole_body()
}
atf_test_case sparse_to_dev
+sparse_to_dev_head()
+{
+ atf_set "descr" "Copy a sparse file to a device"
+}
sparse_to_dev_body()
{
# Three one-megabyte blocks of data preceded, separated, and
@@ -385,6 +471,10 @@ sparse_to_dev_body()
}
atf_test_case sparse_trailing_hole
+sparse_trailing_hole_head()
+{
+ atf_set "descr" "Copy a sparse file that ends with a hole"
+}
sparse_trailing_hole_body()
{
# One megabyte of data followed by a 16-megabyte hole
@@ -398,16 +488,24 @@ sparse_trailing_hole_body()
}
atf_test_case standalone_Pflag
+standalone_Pflag_head()
+{
+ atf_set "descr" "Test -P without -R"
+}
standalone_Pflag_body()
{
echo "foo" > bar
ln -s bar foo
atf_check cp -P foo baz
- atf_check -o inline:'Symbolic Link\n' stat -f %SHT baz
+ atf_check test -L baz
}
atf_test_case symlink
+symlink_head()
+{
+ atf_set "descr" "Create a symbolic link to a file"
+}
symlink_body()
{
echo "foo" >foo
@@ -417,6 +515,11 @@ symlink_body()
}
atf_test_case symlink_exists
+symlink_exists_head()
+{
+ atf_set "descr" "Attempt to create a symbolic link to a file, " \
+ "but the destination already exists"
+}
symlink_exists_body()
{
echo "foo" >foo
@@ -426,6 +529,11 @@ symlink_exists_body()
}
atf_test_case symlink_exists_force
+symlink_exists_force_head()
+{
+ atf_set "descr" "Force creation of a symbolic link to a file " \
+ "when the destination already exists"
+}
symlink_exists_force_body()
{
echo "foo" >foo
@@ -436,6 +544,10 @@ symlink_exists_force_body()
}
atf_test_case directory_to_symlink
+directory_to_symlink_head()
+{
+ atf_set "descr" "Attempt to copy a directory to a symlink"
+}
directory_to_symlink_body()
{
mkdir -p foo
@@ -449,6 +561,10 @@ directory_to_symlink_body()
}
atf_test_case overwrite_directory
+overwrite_directory_head()
+{
+ atf_set "descr" "Attempt to overwrite a directory with a file"
+}
overwrite_directory_body()
{
mkdir -p foo/bar/baz
@@ -465,6 +581,10 @@ overwrite_directory_body()
}
atf_test_case to_dir_dne
+to_dir_dne_head()
+{
+ atf_set "descr" "Copy a directory to a nonexistent directory"
+}
to_dir_dne_body()
{
mkdir dir
@@ -476,6 +596,10 @@ to_dir_dne_body()
}
atf_test_case to_nondir
+to_dir_dne_head()
+{
+ atf_set "descr" "Copy one or more files to a non-directory"
+}
to_nondir_body()
{
echo "foo" >foo
@@ -490,6 +614,10 @@ to_nondir_body()
}
atf_test_case to_deadlink
+to_deadlink_head()
+{
+ atf_set "descr" "Copy a file to a dead symbolic link"
+}
to_deadlink_body()
{
echo "foo" >foo
@@ -499,6 +627,10 @@ to_deadlink_body()
}
atf_test_case to_deadlink_append
+to_deadlink_append_head()
+{
+ atf_set "descr" "Copy multiple files to a dead symbolic link"
+}
to_deadlink_append_body()
{
echo "foo" >foo
@@ -517,6 +649,10 @@ to_deadlink_append_body()
}
atf_test_case to_dirlink
+to_dirlink_head()
+{
+ atf_set "descr" "Copy things to a symbolic link to a directory"
+}
to_dirlink_body()
{
mkdir src dir
@@ -542,6 +678,11 @@ to_dirlink_body()
}
atf_test_case to_deaddirlink
+to_deaddirlink_head()
+{
+ atf_set "descr" "Copy things to a symbolic link to a nonexistent " \
+ "directory"
+}
to_deaddirlink_body()
{
mkdir src
@@ -572,6 +713,11 @@ to_deaddirlink_body()
}
atf_test_case to_link_outside
+to_link_outside_head()
+{
+ atf_set "descr" "Recursively copy a directory containing a symbolic " \
+ "link that points to somewhere outside the source directory"
+}
to_link_outside_body()
{
mkdir dir dst dst/dir
@@ -584,6 +730,11 @@ to_link_outside_body()
}
atf_test_case dstmode
+dstmode_head()
+{
+ atf_set "descr" "Verify that directories are created with the " \
+ "correct permissions"
+}
dstmode_body()
{
mkdir -m 0755 dir
@@ -646,6 +797,7 @@ atf_test_case unrdir
unrdir_head()
{
atf_set "descr" "Test handling of unreadable directories"
+ atf_set "require.user" "unprivileged"
}
unrdir_body()
{
@@ -657,7 +809,7 @@ unrdir_body()
atf_check \
-s exit:1 \
-e match:"^cp: src/b: Permission denied" \
- cp -R src dst
+ cp -R --sort src dst
atf_check test -d dst/a
atf_check cmp src/a/f dst/a/f
atf_check test -d dst/b
@@ -670,6 +822,7 @@ atf_test_case unrfile
unrfile_head()
{
atf_set "descr" "Test handling of unreadable files"
+ atf_set "require.user" "unprivileged"
}
unrfile_body()
{
@@ -681,13 +834,28 @@ unrfile_body()
atf_check \
-s exit:1 \
-e match:"^cp: src/b: Permission denied" \
- cp -R src dst
+ cp -R --sort src dst
atf_check test -d dst
atf_check cmp src/a dst/a
atf_check test ! -e dst/b
atf_check cmp src/c dst/c
}
+atf_test_case nopermute
+nopermute_head()
+{
+ atf_set descr "Check that getopt_long does not permute options"
+}
+nopermute_body()
+{
+ mkdir src dst
+ atf_check \
+ -s exit:1 \
+ -e match:'cp: -p: No such file' \
+ cp -R src -p dst
+ atf_check test -d dst/src
+}
+
atf_init_test_cases()
{
atf_add_test_case basic
@@ -729,4 +897,5 @@ atf_init_test_cases()
atf_add_test_case dirloop
atf_add_test_case unrdir
atf_add_test_case unrfile
+ atf_add_test_case nopermute
}
diff --git a/bin/cp/utils.c b/bin/cp/utils.c
index cfc0f0f12603..2036056ada68 100644
--- a/bin/cp/utils.c
+++ b/bin/cp/utils.c
@@ -105,7 +105,7 @@ copy_file(const FTSENT *entp, bool dne, bool beneath)
ssize_t wcount;
off_t wtotal;
int ch, checkch, from_fd, rval, to_fd;
- int use_copy_file_range = 1;
+ bool use_copy_file_range = true;
fs = entp->fts_statp;
from_fd = to_fd = -1;
@@ -210,7 +210,7 @@ copy_file(const FTSENT *entp, bool dne, bool beneath)
to_fd, NULL, SSIZE_MAX, 0);
if (wcount < 0 && errno == EINVAL) {
/* probably a non-seekable descriptor */
- use_copy_file_range = 0;
+ use_copy_file_range = false;
}
}
if (!use_copy_file_range) {
diff --git a/bin/df/df.1 b/bin/df/df.1
index ceb1bb45babf..2de72e4e3bb2 100644
--- a/bin/df/df.1
+++ b/bin/df/df.1
@@ -26,7 +26,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 29, 2023
+.Dd July 16, 2025
.Dt DF 1
.Os
.Sh NAME
@@ -65,7 +65,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl a
Show all mount points, including those that were mounted with the
@@ -264,7 +264,7 @@ each file or directory name or disk label
.Xr getmntinfo 3 ,
.Xr libxo 3 ,
.Xr localeconv 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr fstab 5 ,
.Xr mount 8 ,
.Xr pstat 8 ,
diff --git a/bin/ps/ps.1 b/bin/ps/ps.1
index 1c964157f53f..542004453658 100644
--- a/bin/ps/ps.1
+++ b/bin/ps/ps.1
@@ -33,7 +33,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 06, 2025
+.Dd July 16, 2025
.Dt PS 1
.Os
.Sh NAME
@@ -194,7 +194,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
The default is the traditional text style output.
.It Fl A
@@ -925,7 +925,7 @@ Display information on all system processes:
.Xr kvm 3 ,
.Xr libxo 3 ,
.Xr strftime 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr mac 4 ,
.Xr procfs 4 ,
.Xr pstat 8 ,
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
index 1836707d72df..da8cbd9ffe50 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
+++ b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
@@ -20,7 +20,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 14, 2025
+.Dd July 16, 2025
.Dt DTRACE 1
.Os
.Sh NAME
@@ -617,6 +617,52 @@ Same as the
flag.
.It Sy dynvarsize Ns = Ns Ar size
Size of the dynamic variable space.
+.Sm off
+.It Sy evaltime = Cm exec | preinit | postinit | main
+.Sm on
+Process create mode.
+When using
+.Fl c Ar cmd
+to start a command,
+.Nm
+will first stop the newly started
+.Ar cmd ,
+evaluate the
+.Xr d 7
+program,
+and then resume the
+.Ar cmd .
+The
+.Cm evaltime
+option controls the exact moment when this happens.
+.Pp
+The following table describes supported modes.
+.Bl -column -offset indent "postinit" "D Program Evaluation Time"
+.It Sy Mode Ta Sy D Program Evaluation Time
+.It Cm exec Ta
+Right at the first instruction of the command
+.Ar cmd
+execution.
+.It Cm preinit Ta
+Before
+.Xr elf 5 Ap s
+.Dq .init
+sections.
+.It Cm postinit Ta
+After
+.Xr elf 5 Ap s
+.Dq .init
+sections.
+Default on
+.Fx .
+.It Cm main Ta
+Before the first instruction of the
+.Fn main
+function.
+.El
+.Pp
+Usually, there is no reason to change the default mode,
+but it might be handy in situations such as shared library tracing.
.It Sy flowindent
Turn on flow indentation.
Same as the
@@ -1221,18 +1267,24 @@ Invalid command line options or arguments were specified.
.El
.Sh SEE ALSO
.Xr cpp 1 ,
+.Xr dwatch 1 ,
.Xr dtrace_audit 4 ,
+.Xr dtrace_dtrace 4 ,
+.Xr dtrace_fbt 4 ,
.Xr dtrace_io 4 ,
.Xr dtrace_ip 4 ,
.Xr dtrace_kinst 4 ,
.Xr dtrace_lockstat 4 ,
.Xr dtrace_proc 4 ,
+.Xr dtrace_profile 4 ,
.Xr dtrace_sched 4 ,
.Xr dtrace_sctp 4 ,
.Xr dtrace_tcp 4 ,
.Xr dtrace_udp 4 ,
.Xr dtrace_udplite 4 ,
.Xr elf 5 ,
+.Xr d 7 ,
+.Xr tracing 7 ,
.Xr SDT 9
.Rs
.%T Solaris Dynamic Tracing Guide
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ticks.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ticks.d
new file mode 100644
index 000000000000..4061db9858c1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ticks.d
@@ -0,0 +1,54 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2025 Mark Johnston <markj@FreeBSD.org>
+ */
+
+/*
+ * For 10s, verify that the value of `ticks goes up by `hz each second.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-1s
+{
+ if (i == 0) {
+ t = *(int *)&`ticks;
+ i++;
+ } else {
+ u = *(int *)&`ticks;
+ if (u - t != `hz) {
+ printf("ticks: %d, expected %d\n", u - t, `hz);
+ exit(1);
+ }
+ t = u;
+ i++;
+ if (i == 10) {
+ exit(0);
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
index 2a0386c33124..f6a328bb9b39 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
@@ -109,8 +109,7 @@ dt_module_syminit32(dt_module_t *dmp)
if (sym->st_name == 0 || sym->st_name >= ss_size)
continue; /* skip null or invalid names */
- if (sym->st_value != 0 &&
- (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
+ if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size) {
asrsv++; /* reserve space in the address map */
#if defined(__FreeBSD__)
@@ -159,8 +158,7 @@ dt_module_syminit64(dt_module_t *dmp)
if (sym->st_name == 0 || sym->st_name >= ss_size)
continue; /* skip null or invalid names */
- if (sym->st_value != 0 &&
- (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
+ if (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size) {
asrsv++; /* reserve space in the address map */
#if defined(__FreeBSD__)
sym->st_value += (Elf_Addr) dmp->dm_reloc_offset;
@@ -245,8 +243,7 @@ dt_module_symsort32(dt_module_t *dmp)
for (i = 1; i < n; i++, dsp++) {
Elf32_Sym *sym = symtab + dsp->ds_symid;
- if (sym->st_value != 0 &&
- (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
+ if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)
*sympp++ = sym;
}
@@ -269,8 +266,7 @@ dt_module_symsort64(dt_module_t *dmp)
for (i = 1; i < n; i++, dsp++) {
Elf64_Sym *sym = symtab + dsp->ds_symid;
- if (sym->st_value != 0 &&
- (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
+ if (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)
*sympp++ = sym;
}
@@ -1218,7 +1214,7 @@ dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat)
continue; /* skip any malformed sections */
if (sh.sh_size == 0)
continue;
- if (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) {
+ if (sh.sh_flags & SHF_ALLOC) {
alignmask = sh.sh_addralign - 1;
mapbase += alignmask;
mapbase &= ~alignmask;
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
index d1ebaa8791da..8cc504856567 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
@@ -1918,6 +1918,14 @@ dt_node_op1(int op, dt_node_t *cp)
return (cp);
}
+ /*
+ * When applying the addressof operator to an identifier, it's okay if
+ * we can't find type information for the identifier, so flag the node
+ * to ensure that we don't raise an error.
+ */
+ if (op == DT_TOK_ADDROF && cp->dn_kind == DT_NODE_IDENT)
+ cp->dn_flags |= DT_NF_IDENTADDR;
+
dnp = dt_node_alloc(DT_NODE_OP1);
assert(op <= USHRT_MAX);
dnp->dn_op = (ushort_t)op;
@@ -2786,10 +2794,21 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
dt_module_modelname(dtp->dt_ddefs));
}
- xyerror(D_SYM_NOTYPES,
+ /*
+ * If we're taking the address of an identifier that
+ * doesn't have type info, try to make it a void *.
+ * This lets us use identifiers that are defined in
+ * assembly and don't have type information.
+ */
+ if ((dnp->dn_flags & DT_NF_IDENTADDR) == 0 ||
+ dtrace_lookup_by_type(dtp, DTRACE_OBJ_CDEFS,
+ "void", &dtt) != 0) {
+ xyerror(D_SYM_NOTYPES,
"no symbolic type information is available for "
- "%s%s%s: %s\n", dts.dts_object, mark, dts.dts_name,
- dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ "%s%s%s: %s\n", dts.dts_object, mark,
+ dts.dts_name,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
}
idp = dt_ident_create(name, DT_IDENT_SYMBOL, 0, 0,
@@ -4506,30 +4525,30 @@ dt_cook_none(dt_node_t *dnp, uint_t idflags)
return (dnp);
}
-static dt_node_t *(*dt_cook_funcs[])(dt_node_t *, uint_t) = {
- dt_cook_none, /* DT_NODE_FREE */
- dt_cook_none, /* DT_NODE_INT */
- dt_cook_none, /* DT_NODE_STRING */
- dt_cook_ident, /* DT_NODE_IDENT */
- dt_cook_var, /* DT_NODE_VAR */
- dt_cook_none, /* DT_NODE_SYM */
- dt_cook_none, /* DT_NODE_TYPE */
- dt_cook_func, /* DT_NODE_FUNC */
- dt_cook_op1, /* DT_NODE_OP1 */
- dt_cook_op2, /* DT_NODE_OP2 */
- dt_cook_op3, /* DT_NODE_OP3 */
- dt_cook_statement, /* DT_NODE_DEXPR */
- dt_cook_statement, /* DT_NODE_DFUNC */
- dt_cook_aggregation, /* DT_NODE_AGG */
- dt_cook_none, /* DT_NODE_PDESC */
- dt_cook_clause, /* DT_NODE_CLAUSE */
- dt_cook_inline, /* DT_NODE_INLINE */
- dt_cook_member, /* DT_NODE_MEMBER */
- dt_cook_xlator, /* DT_NODE_XLATOR */
- dt_cook_none, /* DT_NODE_PROBE */
- dt_cook_provider, /* DT_NODE_PROVIDER */
- dt_cook_none, /* DT_NODE_PROG */
- dt_cook_none, /* DT_NODE_IF */
+static dt_node_t *(* const dt_cook_funcs[])(dt_node_t *, uint_t) = {
+ [DT_NODE_FREE] = dt_cook_none,
+ [DT_NODE_INT] = dt_cook_none,
+ [DT_NODE_STRING] = dt_cook_none,
+ [DT_NODE_IDENT] = dt_cook_ident,
+ [DT_NODE_VAR] = dt_cook_var,
+ [DT_NODE_SYM] = dt_cook_none,
+ [DT_NODE_TYPE] = dt_cook_none,
+ [DT_NODE_FUNC] = dt_cook_func,
+ [DT_NODE_OP1] = dt_cook_op1,
+ [DT_NODE_OP2] = dt_cook_op2,
+ [DT_NODE_OP3] = dt_cook_op3,
+ [DT_NODE_DEXPR] = dt_cook_statement,
+ [DT_NODE_DFUNC] = dt_cook_statement,
+ [DT_NODE_AGG] = dt_cook_aggregation,
+ [DT_NODE_PDESC] = dt_cook_none,
+ [DT_NODE_CLAUSE] = dt_cook_clause,
+ [DT_NODE_INLINE] = dt_cook_inline,
+ [DT_NODE_MEMBER] = dt_cook_member,
+ [DT_NODE_XLATOR] = dt_cook_xlator,
+ [DT_NODE_PROBE] = dt_cook_none,
+ [DT_NODE_PROVIDER] = dt_cook_provider,
+ [DT_NODE_PROG] = dt_cook_none,
+ [DT_NODE_IF] = dt_cook_none,
};
/*
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
index 3a146c5d2592..1d2f33beee0f 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
@@ -182,6 +182,7 @@ typedef struct dt_node {
#define DT_NF_WRITABLE 0x10 /* node is writable (can be modified) */
#define DT_NF_BITFIELD 0x20 /* node is an integer bitfield */
#define DT_NF_USERLAND 0x40 /* data is a userland address */
+#define DT_NF_IDENTADDR 0x80 /* node is an identifier address */
#define DT_TYPE_NAMELEN 128 /* reasonable size for ctf_type_name() */
diff --git a/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo.c b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo.c
new file mode 100644
index 000000000000..8e6f7c726f24
--- /dev/null
+++ b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo.c
@@ -0,0 +1,1341 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2025 Oxide Computer Company
+ */
+
+/*
+ * Verify the behavior of the various O_CLOFORK and O_CLOEXEC variants. In
+ * particular getting this via:
+ *
+ * - open(2): O_CLOFORK/O_CLOEXEC
+ * - fcntl(2): F_SETFD FD_CLOFORK/FD_CLOEXEC
+ * - fcntl(2): F_DUPFD_CLOFORK/F_DUPFD_CLOEXEC
+ * - fcntl(2): F_DUP2FD_CLOFORK/F_DUP2FD_CLOEXEC
+ * - dup2(3C)
+ * - dup3(3C): argument translation
+ * - pipe2(2)
+ * - socket(2): SOCK_CLOEXEC/SOCK_CLOFORK
+ * - accept(2): flags on the listen socket aren't inherited on accept
+ * - socketpair(3SOCKET)
+ * - accept4(2): SOCK_CLOEXEC/SOCK_CLOFORK
+ * - recvmsg(2): SCM_RIGHTS MSG_CMSG_CLOFORK/MSG_CMSG_CLOEXEC
+ *
+ * The test is designed such that we have an array of functions that are used to
+ * create file descriptors with different rules. This is found in the
+ * oclo_create array. Each file descriptor that is created is then registered
+ * with information about what is expected about it. A given creation function
+ * can create more than one file descriptor; however, our expectation is that
+ * every file descriptor is accounted for (ignoring stdin, stdout, and stderr).
+ *
+ * We pass a record of each file descriptor that was recorded to a verification
+ * program that will verify everything is correctly honored after an exec. Note
+ * that O_CLOFORK is cleared after exec. The original specification in POSIX has
+ * it being retained; however, this issue was raised after the spec was
+ * published as folks went to implement it and we have ended up following along
+ * with the divergence of other implementations.
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void *recallocarray(void *, size_t, size_t, size_t);
+
+#define strerrorname_np(e) (sys_errlist[e])
+
+/*
+ * Get pathname to avoid reading /proc/curproc/exe
+ *
+ * Taken from procstat_getpathname_sysctl()
+ */
+static int
+getpathname(pid_t pid, char *pathname, size_t maxlen)
+{
+ int error, name[4];
+ size_t len;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_PATHNAME;
+ name[3] = pid;
+ len = maxlen;
+ error = sysctl(name, nitems(name), pathname, &len, NULL, 0);
+ if (error != 0 && errno != ESRCH)
+ warn("sysctl: kern.proc.pathname: %d", pid);
+ if (len == 0)
+ pathname[0] = '\0';
+ return (error);
+}
+
+/*
+ * Verification program name.
+ */
+#define OCLO_VERIFY "ocloexec_verify"
+
+/*
+ * This structure represents a table of ways we expect to create file
+ * descriptors that should have the resulting flags set when done. The table is
+ * ordered and subsequent iterations are allowed to assume that the ones that
+ * have gone ahead of them have run and are therefore allowed to access them.
+ * The create function is expected to return the created fd.
+ */
+typedef struct clo_create clo_create_t;
+struct clo_create {
+ const char *clo_desc;
+ int clo_flags;
+ void (*clo_func)(const clo_create_t *);
+};
+
+/*
+ * This is our run-time data. We expect all file descriptors to be registered by
+ * our calling functions through oclo_record().
+ */
+typedef struct clo_rtdata {
+ const clo_create_t *crt_data;
+ size_t crt_idx;
+ int crt_fd;
+ int crt_flags;
+ const char *crt_desc;
+} clo_rtdata_t;
+
+static clo_rtdata_t *oclo_rtdata;
+static size_t oclo_rtdata_nents = 0;
+static size_t oclo_rtdata_next = 0;
+static int oclo_nextfd = STDERR_FILENO + 1;
+
+static bool
+oclo_flags_match(const clo_rtdata_t *rt, bool child)
+{
+ const char *pass = child ? "post-fork" : "pre-fork";
+ bool fail = child && (rt->crt_flags & FD_CLOFORK) != 0;
+ int flags = fcntl(rt->crt_fd, F_GETFD, NULL);
+
+ if (flags < 0) {
+ int e = errno;
+
+ if (fail) {
+ if (e == EBADF) {
+ (void) printf("TEST PASSED: %s (%s): fd %d: "
+ "correctly closed\n",
+ rt->crt_data->clo_desc, pass, rt->crt_fd);
+ return (true);
+ }
+
+ warn("TEST FAILED: %s (%s): fd %d: expected fcntl to "
+ "fail with EBADF, but found %s",
+ rt->crt_data->clo_desc, pass, rt->crt_fd,
+ strerrorname_np(e));
+ return (false);
+ }
+
+ warnx("TEST FAILED: %s (%s): fd %d: fcntl(F_GETFD) "
+ "unexpectedly failed", rt->crt_data->clo_desc, pass,
+ rt->crt_fd);
+ return (false);
+ }
+
+ if (fail) {
+ warnx("TEST FAILED: %s (%s): fd %d: received flags %d, but "
+ "expected to fail based on flags %d",
+ rt->crt_data->clo_desc, pass, rt->crt_fd, flags,
+ rt->crt_fd);
+ return (false);
+ }
+
+ if (flags != rt->crt_flags) {
+ warnx("TEST FAILED: %s (%s): fd %d: discovered flags 0x%x do "
+ "not match expected flags 0x%x", rt->crt_data->clo_desc,
+ pass, rt->crt_fd, flags, rt->crt_fd);
+ return (false);
+ }
+
+ (void) printf("TEST PASSED: %s (%s): fd %d discovered flags match "
+ "(0x%x)\n", rt->crt_data->clo_desc, pass, rt->crt_fd, flags);
+ return (true);
+}
+
+
+static void
+oclo_record(const clo_create_t *c, int fd, int exp_flags, const char *desc)
+{
+ if (oclo_rtdata_next == oclo_rtdata_nents) {
+ size_t newrt = oclo_rtdata_nents + 8;
+ clo_rtdata_t *rt;
+ rt = recallocarray(oclo_rtdata, oclo_rtdata_nents, newrt,
+ sizeof (clo_rtdata_t));
+ if (rt == NULL) {
+ err(EXIT_FAILURE, "TEST_FAILED: internal error "
+ "expanding fd records to %zu entries", newrt);
+ }
+
+ oclo_rtdata_nents = newrt;
+ oclo_rtdata = rt;
+ }
+
+ if (fd != oclo_nextfd) {
+ errx(EXIT_FAILURE, "TEST FAILED: internal test error: expected "
+ "to record next fd %d, given %d", oclo_nextfd, fd);
+ }
+
+ oclo_rtdata[oclo_rtdata_next].crt_data = c;
+ oclo_rtdata[oclo_rtdata_next].crt_fd = fd;
+ oclo_rtdata[oclo_rtdata_next].crt_flags = exp_flags;
+ oclo_rtdata[oclo_rtdata_next].crt_desc = desc;
+
+ /*
+ * Matching errors at this phase are fatal as it means we screwed up the
+ * program pretty badly.
+ */
+ if (!oclo_flags_match(&oclo_rtdata[oclo_rtdata_next], false)) {
+ exit(EXIT_FAILURE);
+ }
+
+ oclo_rtdata_next++;
+ oclo_nextfd++;
+}
+
+static int
+oclo_file(const clo_create_t *c)
+{
+ int flags = O_RDWR, fd;
+
+ if ((c->clo_flags & FD_CLOEXEC) != 0)
+ flags |= O_CLOEXEC;
+ if ((c->clo_flags & FD_CLOFORK) != 0)
+ flags |= O_CLOFORK;
+ fd = open("/dev/null", flags);
+ if (fd < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to open /dev/null",
+ c->clo_desc);
+ }
+
+ return (fd);
+}
+
+static void
+oclo_open(const clo_create_t *c)
+{
+ oclo_record(c, oclo_file(c), c->clo_flags, NULL);
+}
+
+static void
+oclo_setfd_common(const clo_create_t *c, int targ_flags)
+{
+ int fd = oclo_file(c);
+ if (fcntl(fd, F_SETFD, targ_flags) < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: F_SETFD failed to set "
+ "flags to %d", c->clo_desc, targ_flags);
+ }
+
+ oclo_record(c, fd, targ_flags, NULL);
+}
+
+static void
+oclo_setfd_none(const clo_create_t *c)
+{
+ oclo_setfd_common(c, 0);
+}
+
+static void
+oclo_setfd_exec(const clo_create_t *c)
+{
+ oclo_setfd_common(c, FD_CLOEXEC);
+}
+
+static void
+oclo_setfd_fork(const clo_create_t *c)
+{
+ oclo_setfd_common(c, FD_CLOFORK);
+}
+
+static void
+oclo_setfd_both(const clo_create_t *c)
+{
+ oclo_setfd_common(c, FD_CLOFORK | FD_CLOEXEC);
+}
+
+/*
+ * Open an fd with flags in a certain form and then use one of the F_DUPFD or
+ * F_DUP2FD variants and ensure that flags are properly propagated as expected.
+ */
+static void
+oclo_fdup_common(const clo_create_t *c, int targ_flags, int cmd)
+{
+ int dup, fd;
+
+ fd = oclo_file(c);
+ oclo_record(c, fd, c->clo_flags, "base");
+ switch (cmd) {
+ case F_DUPFD:
+ case F_DUPFD_CLOEXEC:
+ case F_DUPFD_CLOFORK:
+ dup = fcntl(fd, cmd, fd);
+ break;
+ case F_DUP2FD:
+ case F_DUP2FD_CLOEXEC:
+#ifdef F_DUP2FD_CLOFORK
+ case F_DUP2FD_CLOFORK:
+#endif
+ dup = fcntl(fd, cmd, fd + 1);
+ break;
+ case F_DUP3FD:
+ dup = fcntl(fd, cmd | (targ_flags << F_DUP3FD_SHIFT), fd + 1);
+ break;
+ default:
+ errx(EXIT_FAILURE, "TEST FAILURE: %s: internal error: "
+ "unexpected fcntl cmd: 0x%x", c->clo_desc, cmd);
+ }
+
+ if (dup < 0) {
+ err(EXIT_FAILURE, "TEST FAILURE: %s: failed to dup fd with "
+ "fcntl command 0x%x", c->clo_desc, cmd);
+ }
+
+ oclo_record(c, dup, targ_flags, "dup");
+}
+
+static void
+oclo_fdupfd(const clo_create_t *c)
+{
+ oclo_fdup_common(c, 0, F_DUPFD);
+}
+
+static void
+oclo_fdupfd_fork(const clo_create_t *c)
+{
+ oclo_fdup_common(c, FD_CLOFORK, F_DUPFD_CLOFORK);
+}
+
+static void
+oclo_fdupfd_exec(const clo_create_t *c)
+{
+ oclo_fdup_common(c, FD_CLOEXEC, F_DUPFD_CLOEXEC);
+}
+
+static void
+oclo_fdup2fd(const clo_create_t *c)
+{
+ oclo_fdup_common(c, 0, F_DUP2FD);
+}
+
+#ifdef F_DUP2FD_CLOFORK
+static void
+oclo_fdup2fd_fork(const clo_create_t *c)
+{
+ oclo_fdup_common(c, FD_CLOFORK, F_DUP2FD_CLOFORK);
+}
+#endif
+
+static void
+oclo_fdup2fd_exec(const clo_create_t *c)
+{
+ oclo_fdup_common(c, FD_CLOEXEC, F_DUP2FD_CLOEXEC);
+}
+
+static void
+oclo_fdup3fd_none(const clo_create_t *c)
+{
+ oclo_fdup_common(c, 0, F_DUP3FD);
+}
+
+static void
+oclo_fdup3fd_exec(const clo_create_t *c)
+{
+ oclo_fdup_common(c, FD_CLOEXEC, F_DUP3FD);
+}
+
+static void
+oclo_fdup3fd_fork(const clo_create_t *c)
+{
+ oclo_fdup_common(c, FD_CLOFORK, F_DUP3FD);
+}
+
+static void
+oclo_fdup3fd_both(const clo_create_t *c)
+{
+ oclo_fdup_common(c, FD_CLOEXEC | FD_CLOFORK, F_DUP3FD);
+}
+
+static void
+oclo_dup_common(const clo_create_t *c, int targ_flags, bool v3)
+{
+ int dup, fd;
+ fd = oclo_file(c);
+ oclo_record(c, fd, c->clo_flags, "base");
+ if (v3) {
+ int dflags = 0;
+ if ((targ_flags & FD_CLOEXEC) != 0)
+ dflags |= O_CLOEXEC;
+ if ((targ_flags & FD_CLOFORK) != 0)
+ dflags |= O_CLOFORK;
+ dup = dup3(fd, fd + 1, dflags);
+ } else {
+ dup = dup2(fd, fd + 1);
+ }
+
+ oclo_record(c, dup, targ_flags, "dup");
+}
+
+static void
+oclo_dup2(const clo_create_t *c)
+{
+ oclo_dup_common(c, 0, false);
+}
+
+static void
+oclo_dup3_none(const clo_create_t *c)
+{
+ oclo_dup_common(c, 0, true);
+}
+
+static void
+oclo_dup3_exec(const clo_create_t *c)
+{
+ oclo_dup_common(c, FD_CLOEXEC, true);
+}
+
+static void
+oclo_dup3_fork(const clo_create_t *c)
+{
+ oclo_dup_common(c, FD_CLOFORK, true);
+}
+
+static void
+oclo_dup3_both(const clo_create_t *c)
+{
+ oclo_dup_common(c, FD_CLOEXEC | FD_CLOFORK, true);
+}
+
+static void
+oclo_pipe(const clo_create_t *c)
+{
+ int flags = 0, fds[2];
+
+ if ((c->clo_flags & FD_CLOEXEC) != 0)
+ flags |= O_CLOEXEC;
+ if ((c->clo_flags & FD_CLOFORK) != 0)
+ flags |= O_CLOFORK;
+
+ if (pipe2(fds, flags) < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: pipe2() with flags %d "
+ "failed", c->clo_desc, flags);
+ }
+
+ oclo_record(c, fds[0], c->clo_flags, "pipe[0]");
+ oclo_record(c, fds[1], c->clo_flags, "pipe[1]");
+}
+
+static void
+oclo_socket(const clo_create_t *c)
+{
+ int type = SOCK_DGRAM, fd;
+
+ if ((c->clo_flags & FD_CLOEXEC) != 0)
+ type |= SOCK_CLOEXEC;
+ if ((c->clo_flags & FD_CLOFORK) != 0)
+ type |= SOCK_CLOFORK;
+ fd = socket(PF_INET, type, 0);
+ if (fd < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to create socket "
+ "with flags: 0x%x\n", c->clo_desc, c->clo_flags);
+ }
+
+ oclo_record(c, fd, c->clo_flags, NULL);
+}
+
+static void
+oclo_accept_common(const clo_create_t *c, int targ_flags, bool a4)
+{
+ int lsock, csock, asock;
+ int ltype = SOCK_STREAM, atype = 0;
+ struct sockaddr_in in;
+ socklen_t slen;
+
+ if ((c->clo_flags & FD_CLOEXEC) != 0)
+ ltype |= SOCK_CLOEXEC;
+ if ((c->clo_flags & FD_CLOFORK) != 0)
+ ltype |= SOCK_CLOFORK;
+
+ if ((targ_flags & FD_CLOEXEC) != 0)
+ atype |= SOCK_CLOEXEC;
+ if ((targ_flags & FD_CLOFORK) != 0)
+ atype |= SOCK_CLOFORK;
+
+ lsock = socket(PF_INET, ltype, 0);
+ if (lsock < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to create listen "
+ "socket with flags: 0x%x\n", c->clo_desc, c->clo_flags);
+ }
+
+ oclo_record(c, lsock, c->clo_flags, "listen");
+ (void) memset(&in, 0, sizeof (in));
+ in.sin_family = AF_INET;
+ in.sin_port = 0;
+ in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (bind(lsock, (struct sockaddr *)&in, sizeof (in)) != 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to bind socket",
+ c->clo_desc);
+ }
+
+ slen = sizeof (struct sockaddr_in);
+ if (getsockname(lsock, (struct sockaddr *)&in, &slen) != 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to discover bound "
+ "socket address", c->clo_desc);
+ }
+
+ if (listen(lsock, 5) < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to listen on socket",
+ c->clo_desc);
+ }
+
+ csock = socket(PF_INET, SOCK_STREAM, 0);
+ if (csock < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to create client "
+ "socket", c->clo_desc);
+ }
+ oclo_record(c, csock, 0, "connect");
+
+ if (connect(csock, (struct sockaddr *)&in, sizeof (in)) != 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to connect to "
+ "server socket", c->clo_desc);
+ }
+
+ if (a4) {
+ asock = accept4(lsock, NULL, NULL, atype);
+ } else {
+ asock = accept(lsock, NULL, NULL);
+ }
+ if (asock < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to accept client "
+ "connection", c->clo_desc);
+ }
+ oclo_record(c, asock, targ_flags, "accept");
+}
+
+static void
+oclo_accept(const clo_create_t *c)
+{
+ oclo_accept_common(c, 0, false);
+}
+
+static void
+oclo_accept4_none(const clo_create_t *c)
+{
+ oclo_accept_common(c, 0, true);
+}
+
+static void
+oclo_accept4_fork(const clo_create_t *c)
+{
+ oclo_accept_common(c, FD_CLOFORK, true);
+}
+
+static void
+oclo_accept4_exec(const clo_create_t *c)
+{
+ oclo_accept_common(c, FD_CLOEXEC, true);
+}
+
+static void
+oclo_accept4_both(const clo_create_t *c)
+{
+ oclo_accept_common(c, FD_CLOEXEC | FD_CLOFORK, true);
+}
+
+/*
+ * Go through the process of sending ourselves a file descriptor.
+ */
+static void
+oclo_rights_common(const clo_create_t *c, int targ_flags)
+{
+ int pair[2], type = SOCK_DGRAM, sflags = 0;
+ int tosend = oclo_file(c), recvfd;
+ uint32_t data = 0x7777;
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *cm;
+
+ if ((c->clo_flags & FD_CLOEXEC) != 0)
+ type |= SOCK_CLOEXEC;
+ if ((c->clo_flags & FD_CLOFORK) != 0)
+ type |= SOCK_CLOFORK;
+
+ if (socketpair(PF_UNIX, type, 0, pair) < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to create socket "
+ "pair", c->clo_desc);
+ }
+
+ oclo_record(c, tosend, c->clo_flags, "send fd");
+ oclo_record(c, pair[0], c->clo_flags, "pair[0]");
+ oclo_record(c, pair[1], c->clo_flags, "pair[1]");
+
+ iov.iov_base = (void *)&data;
+ iov.iov_len = sizeof (data);
+
+ (void) memset(&msg, 0, sizeof (msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_controllen = CMSG_SPACE(sizeof (int));
+
+ msg.msg_control = calloc(1, msg.msg_controllen);
+ if (msg.msg_control == NULL) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to allocate %u "
+ "bytes for SCM_RIGHTS control message", c->clo_desc,
+ msg.msg_controllen);
+ }
+
+ cm = CMSG_FIRSTHDR(&msg);
+ cm->cmsg_len = CMSG_LEN(sizeof (int));
+ cm->cmsg_level = SOL_SOCKET;
+ cm->cmsg_type = SCM_RIGHTS;
+ (void) memcpy(CMSG_DATA(cm), &tosend, sizeof (tosend));
+
+ if ((targ_flags & FD_CLOEXEC) != 0)
+ sflags |= MSG_CMSG_CLOEXEC;
+ if ((targ_flags & FD_CLOFORK) != 0)
+ sflags |= MSG_CMSG_CLOFORK;
+
+ if (sendmsg(pair[0], &msg, 0) < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to send fd",
+ c->clo_desc);
+ }
+
+ data = 0;
+ if (recvmsg(pair[1], &msg, sflags) < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: %s: failed to get fd",
+ c->clo_desc);
+ }
+
+ if (data != 0x7777) {
+ errx(EXIT_FAILURE, "TEST FAILED: %s: did not receive correct "
+ "data: expected 0x7777, found 0x%x", c->clo_desc, data);
+ }
+
+ if (msg.msg_controllen < CMSG_SPACE(sizeof (int))) {
+ errx(EXIT_FAILURE, "TEST FAILED: %s: found insufficient "
+ "message control length: expected at least 0x%zx, found "
+ "0x%x", c->clo_desc, CMSG_SPACE(sizeof (int)),
+ msg.msg_controllen);
+ }
+
+ cm = CMSG_FIRSTHDR(&msg);
+ if (cm->cmsg_level != SOL_SOCKET || cm->cmsg_type != SCM_RIGHTS) {
+ errx(EXIT_FAILURE, "TEST FAILED: %s: found surprising cmsg "
+ "0x%x/0x%x, expected 0x%x/0x%x", c->clo_desc,
+ cm->cmsg_level, cm->cmsg_type, SOL_SOCKET, SCM_RIGHTS);
+ }
+
+ if (cm->cmsg_len != CMSG_LEN(sizeof (int))) {
+ errx(EXIT_FAILURE, "TEST FAILED: %s: found unexpected "
+ "SCM_RIGHTS length 0x%x: expected 0x%zx", c->clo_desc,
+ cm->cmsg_len, CMSG_LEN(sizeof (int)));
+ }
+
+ (void) memcpy(&recvfd, CMSG_DATA(cm), sizeof (recvfd));
+ oclo_record(c, recvfd, targ_flags, "SCM_RIGHTS");
+}
+
+static void
+oclo_rights_none(const clo_create_t *c)
+{
+ oclo_rights_common(c, 0);
+}
+
+static void
+oclo_rights_exec(const clo_create_t *c)
+{
+ oclo_rights_common(c, FD_CLOEXEC);
+}
+
+static void
+oclo_rights_fork(const clo_create_t *c)
+{
+ oclo_rights_common(c, FD_CLOFORK);
+}
+
+static void
+oclo_rights_both(const clo_create_t *c)
+{
+ oclo_rights_common(c, FD_CLOEXEC | FD_CLOFORK);
+}
+
+static const clo_create_t oclo_create[] = { {
+ .clo_desc = "open(2), no flags",
+ .clo_flags = 0,
+ .clo_func = oclo_open
+}, {
+ .clo_desc = "open(2), O_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_open
+}, {
+ .clo_desc = "open(2), O_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_open
+}, {
+ .clo_desc = "open(2), O_CLOEXEC|O_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_open
+}, {
+ .clo_desc = "fcntl(F_SETFD) no flags->no flags",
+ .clo_flags = 0,
+ .clo_func = oclo_setfd_none
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOFORK|O_CLOEXEC->no flags",
+ .clo_flags = O_CLOFORK | O_CLOEXEC,
+ .clo_func = oclo_setfd_none
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOEXEC->no flags",
+ .clo_flags = O_CLOEXEC,
+ .clo_func = oclo_setfd_none
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOFORK->no flags",
+ .clo_flags = O_CLOFORK,
+ .clo_func = oclo_setfd_none
+}, {
+ .clo_desc = "fcntl(F_SETFD) no flags->O_CLOEXEC",
+ .clo_flags = 0,
+ .clo_func = oclo_setfd_exec
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOFORK|O_CLOEXEC->O_CLOEXEC",
+ .clo_flags = O_CLOFORK | O_CLOEXEC,
+ .clo_func = oclo_setfd_exec
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOEXEC->O_CLOEXEC",
+ .clo_flags = O_CLOEXEC,
+ .clo_func = oclo_setfd_exec
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOFORK->O_CLOEXEC",
+ .clo_flags = O_CLOFORK,
+ .clo_func = oclo_setfd_exec
+}, {
+ .clo_desc = "fcntl(F_SETFD) no flags->O_CLOFORK",
+ .clo_flags = 0,
+ .clo_func = oclo_setfd_fork
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOFORK|O_CLOEXEC->O_CLOFORK",
+ .clo_flags = O_CLOFORK | O_CLOEXEC,
+ .clo_func = oclo_setfd_fork
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOEXEC->O_CLOFORK",
+ .clo_flags = O_CLOEXEC,
+ .clo_func = oclo_setfd_fork
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOFORK->O_CLOFORK",
+ .clo_flags = O_CLOFORK,
+ .clo_func = oclo_setfd_fork
+}, {
+ .clo_desc = "fcntl(F_SETFD) no flags->O_CLOFORK|O_CLOEXEC",
+ .clo_flags = 0,
+ .clo_func = oclo_setfd_both
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOFORK|O_CLOEXEC->O_CLOFORK|O_CLOEXEC",
+ .clo_flags = O_CLOFORK | O_CLOEXEC,
+ .clo_func = oclo_setfd_both
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOEXEC->O_CLOFORK|O_CLOEXEC",
+ .clo_flags = O_CLOEXEC,
+ .clo_func = oclo_setfd_both
+}, {
+ .clo_desc = "fcntl(F_SETFD) O_CLOFORK->O_CLOFORK|O_CLOEXEC",
+ .clo_flags = O_CLOFORK,
+ .clo_func = oclo_setfd_both
+}, {
+ .clo_desc = "fcntl(F_DUPFD) none->none",
+ .clo_flags = 0,
+ .clo_func = oclo_fdupfd
+}, {
+ .clo_desc = "fcntl(F_DUPFD) FD_CLOEXEC->none",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdupfd
+}, {
+ .clo_desc = "fcntl(F_DUPFD) FD_CLOFORK->none",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdupfd
+}, {
+ .clo_desc = "fcntl(F_DUPFD) FD_CLOEXEC|FD_CLOFORK->none",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdupfd
+}, {
+ .clo_desc = "fcntl(F_DUPFD_CLOFORK) none",
+ .clo_flags = 0,
+ .clo_func = oclo_fdupfd_fork
+}, {
+ .clo_desc = "fcntl(F_DUPFD_CLOFORK) FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdupfd_fork
+}, {
+ .clo_desc = "fcntl(F_DUPFD_CLOFORK) FD_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdupfd_fork
+}, {
+ .clo_desc = "fcntl(F_DUPFD_CLOFORK) FD_CLOEXEC|FD_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdupfd_fork
+}, {
+ .clo_desc = "fcntl(F_DUPFD_CLOEXEC) none",
+ .clo_flags = 0,
+ .clo_func = oclo_fdupfd_exec
+}, {
+ .clo_desc = "fcntl(F_DUPFD_CLOEXEC) FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdupfd_exec
+}, {
+ .clo_desc = "fcntl(F_DUPFD_CLOEXEC) FD_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdupfd_exec
+}, {
+ .clo_desc = "fcntl(F_DUPFD_CLOEXEC) FD_CLOEXEC|FD_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdupfd_exec
+}, {
+ .clo_desc = "fcntl(F_DUP2FD) none->none",
+ .clo_flags = 0,
+ .clo_func = oclo_fdup2fd
+}, {
+ .clo_desc = "fcntl(F_DUP2FD) FD_CLOEXEC->none",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdup2fd
+}, {
+ .clo_desc = "fcntl(F_DUP2FD) FD_CLOFORK->none",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdup2fd
+}, {
+ .clo_desc = "fcntl(F_DUP2FD) FD_CLOEXEC|FD_CLOFORK->none",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdup2fd
+}, {
+#ifdef F_DUP2FD_CLOFORK
+ .clo_desc = "fcntl(F_DUP2FD_CLOFORK) none",
+ .clo_flags = 0,
+ .clo_func = oclo_fdup2fd_fork
+}, {
+ .clo_desc = "fcntl(F_DUP2FD_CLOFORK) FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdup2fd_fork
+}, {
+ .clo_desc = "fcntl(F_DUP2FD_CLOFORK) FD_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdup2fd_fork
+}, {
+ .clo_desc = "fcntl(F_DUP2FD_CLOFORK) FD_CLOEXEC|FD_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdup2fd_fork
+}, {
+#endif
+ .clo_desc = "fcntl(F_DUP2FD_CLOEXEC) none",
+ .clo_flags = 0,
+ .clo_func = oclo_fdup2fd_exec
+}, {
+ .clo_desc = "fcntl(F_DUP2FD_CLOEXEC) FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdup2fd_exec
+}, {
+ .clo_desc = "fcntl(F_DUP2FD_CLOEXEC) FD_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdup2fd_exec
+}, {
+ .clo_desc = "fcntl(F_DUP2FD_CLOEXEC) FD_CLOEXEC|FD_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdup2fd_exec
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) none->none",
+ .clo_flags = 0,
+ .clo_func = oclo_fdup3fd_none
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOEXEC->none",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdup3fd_none
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOFORK->none",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdup3fd_none
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOEXEC|FD_CLOFORK->none",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdup3fd_none
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) none->FD_CLOEXEC",
+ .clo_flags = 0,
+ .clo_func = oclo_fdup3fd_exec
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOEXEC->FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdup3fd_exec
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOFORK->FD_CLOEXEC",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdup3fd_exec
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOEXEC|FD_CLOFORK->FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdup3fd_exec
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) none->FD_CLOFORK|FD_CLOEXEC",
+ .clo_flags = 0,
+ .clo_func = oclo_fdup3fd_both
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOEXEC->FD_CLOFORK|FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdup3fd_both
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOFORK->FD_CLOFORK|FD_CLOEXEC",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdup3fd_both
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOEXEC|FD_CLOFORK->"
+ "FD_CLOFORK|FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdup3fd_both
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) none->FD_CLOFORK",
+ .clo_flags = 0,
+ .clo_func = oclo_fdup3fd_fork
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOEXEC->FD_CLOFORK",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_fdup3fd_fork
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOFORK->FD_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_fdup3fd_fork
+}, {
+ .clo_desc = "fcntl(F_DUP3FD) FD_CLOEXEC|FD_CLOFORK->FD_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_fdup3fd_fork
+}, {
+ .clo_desc = "dup2() none->none",
+ .clo_flags = 0,
+ .clo_func = oclo_dup2
+}, {
+ .clo_desc = "dup2() FD_CLOEXEC->none",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_dup2
+}, {
+ .clo_desc = "dup2() FD_CLOFORK->none",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_dup2
+}, {
+ .clo_desc = "dup2() FD_CLOEXEC|FD_CLOFORK->none",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_dup2
+}, {
+ .clo_desc = "dup3() none->none",
+ .clo_flags = 0,
+ .clo_func = oclo_dup3_none
+}, {
+ .clo_desc = "dup3() FD_CLOEXEC->none",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_dup3_none
+}, {
+ .clo_desc = "dup3() FD_CLOFORK->none",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_dup3_none
+}, {
+ .clo_desc = "dup3() FD_CLOEXEC|FD_CLOFORK->none",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_dup3_none
+}, {
+ .clo_desc = "dup3() none->FD_CLOEXEC",
+ .clo_flags = 0,
+ .clo_func = oclo_dup3_exec
+}, {
+ .clo_desc = "dup3() FD_CLOEXEC->FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_dup3_exec
+}, {
+ .clo_desc = "dup3() FD_CLOFORK->FD_CLOEXEC",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_dup3_exec
+}, {
+ .clo_desc = "dup3() FD_CLOEXEC|FD_CLOFORK->FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_dup3_exec
+}, {
+ .clo_desc = "dup3() none->FD_CLOFORK|FD_CLOEXEC",
+ .clo_flags = 0,
+ .clo_func = oclo_dup3_both
+}, {
+ .clo_desc = "dup3() FD_CLOEXEC->FD_CLOFORK|FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_dup3_both
+}, {
+ .clo_desc = "dup3() FD_CLOFORK->FD_CLOFORK|FD_CLOEXEC",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_dup3_both
+}, {
+ .clo_desc = "dup3() FD_CLOEXEC|FD_CLOFORK->FD_CLOFORK|FD_CLOEXEC",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_dup3_both
+}, {
+ .clo_desc = "dup3() none->FD_CLOFORK",
+ .clo_flags = 0,
+ .clo_func = oclo_dup3_fork
+}, {
+ .clo_desc = "dup3() FD_CLOEXEC->FD_CLOFORK",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_dup3_fork
+}, {
+ .clo_desc = "dup3() FD_CLOFORK->FD_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_dup3_fork
+}, {
+ .clo_desc = "dup3() FD_CLOEXEC|FD_CLOFORK->FD_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_dup3_fork
+}, {
+ .clo_desc = "pipe(2), no flags",
+ .clo_flags = 0,
+ .clo_func = oclo_pipe
+}, {
+ .clo_desc = "pipe(2), O_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_pipe
+}, {
+ .clo_desc = "pipe(2), O_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_pipe
+}, {
+ .clo_desc = "pipe(2), O_CLOEXEC|O_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_pipe
+}, {
+ .clo_desc = "socket(2), no flags",
+ .clo_flags = 0,
+ .clo_func = oclo_socket
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_socket
+}, {
+ .clo_desc = "socket(2), O_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_socket
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC|O_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_socket
+}, {
+ .clo_desc = "socket(2), no flags->accept() none",
+ .clo_flags = 0,
+ .clo_func = oclo_accept
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC->accept() none",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_accept
+}, {
+ .clo_desc = "socket(2), O_CLOFORK->accept() none",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_accept
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC|O_CLOFORK->accept() none",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_accept
+}, {
+ .clo_desc = "socket(2), no flags->accept4() none",
+ .clo_flags = 0,
+ .clo_func = oclo_accept4_none
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC->accept4() none",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_accept4_none
+}, {
+ .clo_desc = "socket(2), O_CLOFORK->accept4() none",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_accept4_none
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC|O_CLOFORK->accept4() none",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_accept4_none
+}, {
+ .clo_desc = "socket(2), no flags->accept4() SOCK_CLOFORK|SOCK_CLOEXEC",
+ .clo_flags = 0,
+ .clo_func = oclo_accept4_both
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC->accept4() SOCK_CLOFORK|SOCK_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_accept4_both
+}, {
+ .clo_desc = "socket(2), O_CLOFORK->accept4() SOCK_CLOFORK|SOCK_CLOEXEC",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_accept4_both
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC|O_CLOFORK->accept4() "
+ "SOCK_CLOFORK|SOCK_CLOEXEC",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_accept4_both
+}, {
+ .clo_desc = "socket(2), no flags->accept4() SOCK_CLOFORK",
+ .clo_flags = 0,
+ .clo_func = oclo_accept4_fork
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC->accept4() SOCK_CLOFORK",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_accept4_fork
+}, {
+ .clo_desc = "socket(2), O_CLOFORK->accept4() SOCK_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_accept4_fork
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC|O_CLOFORK->accept4() SOCK_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_accept4_fork
+}, {
+ .clo_desc = "socket(2), no flags->accept4() SOCK_CLOEXEC",
+ .clo_flags = 0,
+ .clo_func = oclo_accept4_exec
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC->accept4() SOCK_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_accept4_exec
+}, {
+ .clo_desc = "socket(2), O_CLOFORK->accept4() SOCK_CLOEXEC",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_accept4_exec
+}, {
+ .clo_desc = "socket(2), O_CLOEXEC|O_CLOFORK->accept4() SOCK_CLOEXEC",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_accept4_exec
+}, {
+ .clo_desc = "SCM_RIGHTS none->none",
+ .clo_flags = 0,
+ .clo_func = oclo_rights_none
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOFORK->none",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_rights_none
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOEXEC->none",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_rights_none
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOEXEC|FD_CLOFORK->none",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_rights_none
+}, {
+ .clo_desc = "SCM_RIGHTS none->MSG_CMSG_CLOEXEC",
+ .clo_flags = 0,
+ .clo_func = oclo_rights_exec
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOFORK->MSG_CMSG_CLOEXEC",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_rights_exec
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOEXEC->MSG_CMSG_CLOEXEC",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_rights_exec
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOEXEC|FD_CLOFORK->MSG_CMSG_CLOEXEC",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_rights_exec
+}, {
+ .clo_desc = "SCM_RIGHTS MSG_CMSG_CLOFORK->nMSG_CMSG_CLOFORK",
+ .clo_flags = 0,
+ .clo_func = oclo_rights_fork
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOFORK->MSG_CMSG_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_rights_fork
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOEXEC->MSG_CMSG_CLOFORK",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_rights_fork
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOEXEC|FD_CLOFORK->MSG_CMSG_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_rights_fork
+}, {
+ .clo_desc = "SCM_RIGHTS none->MSG_CMSG_CLOEXEC|MSG_CMSG_CLOFORK",
+ .clo_flags = 0,
+ .clo_func = oclo_rights_both
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOFORK->MSG_CMSG_CLOEXEC|MSG_CMSG_CLOFORK",
+ .clo_flags = FD_CLOFORK,
+ .clo_func = oclo_rights_both
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOEXEC->MSG_CMSG_CLOEXEC|MSG_CMSG_CLOFORK",
+ .clo_flags = FD_CLOEXEC,
+ .clo_func = oclo_rights_both
+}, {
+ .clo_desc = "SCM_RIGHTS FD_CLOEXEC|FD_CLOFORK->"
+ "MSG_CMSG_CLOEXEC|MSG_CMSG_CLOFORK",
+ .clo_flags = FD_CLOEXEC | FD_CLOFORK,
+ .clo_func = oclo_rights_both
+} };
+
+static bool
+oclo_verify_fork(void)
+{
+ bool ret = true;
+
+ for (size_t i = 0; i < oclo_rtdata_next; i++) {
+ if (!oclo_flags_match(&oclo_rtdata[i], true)) {
+ ret = false;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * Here we proceed to re-open any fd that was closed due to O_CLOFORK again to
+ * make sure that the file descriptor makes it to our child verifier.
+ * Importantly, with the changes that cause O_CLOFORK to be cleared on exec, we
+ * should not see any file descriptors with the flag in the child. This allows
+ * us to confirm that this is what we expect.
+ *
+ * In addition, this serves as a test to make sure that our opening of the
+ * lowest fd is correct. While this doesn't actually use the same method as was
+ * done previously, this should get us most of the way there.
+ */
+static void
+oclo_child_reopen(void)
+{
+ for (size_t i = 0; i < oclo_rtdata_next; i++) {
+ int fd;
+ int flags = O_RDWR | O_CLOFORK;
+
+ if ((oclo_rtdata[i].crt_flags & FD_CLOFORK) == 0)
+ continue;
+
+ if ((oclo_rtdata[i].crt_flags & FD_CLOEXEC) != 0)
+ flags |= O_CLOEXEC;
+
+ fd = open("/dev/zero", flags);
+ if (fd < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: failed to re-open fd "
+ "%d with flags %d", oclo_rtdata[i].crt_fd, flags);
+ }
+
+ if (fd != oclo_rtdata[i].crt_fd) {
+ errx(EXIT_FAILURE, "TEST FAILED: re-opening fd %d "
+ "returned fd %d: test design issue or lowest fd "
+ "algorithm is broken", oclo_rtdata[i].crt_fd, fd);
+ }
+ }
+
+ (void) printf("TEST PASSED: successfully reopened fds post-fork");
+}
+
+/*
+ * Look for the verification program in the same directory that this program is
+ * found in. Note, that isn't the same thing as the current working directory.
+ */
+static void
+oclo_exec(void)
+{
+ ssize_t ret;
+ char dir[PATH_MAX], file[PATH_MAX];
+ char **argv;
+
+ ret = getpathname(getpid(), dir, sizeof(dir));
+ if (ret < 0)
+ err(EXIT_FAILURE, "TEST FAILED: failed to read executable path");
+
+ if (snprintf(file, sizeof (file), "%s/%s", dirname(dir), OCLO_VERIFY) >=
+ (int)sizeof (file)) {
+ errx(EXIT_FAILURE, "TEST FAILED: cannot assemble exec path "
+ "name: internal buffer overflow");
+ }
+
+ /* We need an extra for both the NULL terminator and the program name */
+ argv = calloc(oclo_rtdata_next + 2, sizeof (char *));
+ if (argv == NULL) {
+ err(EXIT_FAILURE, "TEST FAILED: failed to allocate exec "
+ "argument array");
+ }
+
+ argv[0] = file;
+ for (size_t i = 0; i < oclo_rtdata_next; i++) {
+ if (asprintf(&argv[i + 1], "0x%x", oclo_rtdata[i].crt_flags) ==
+ -1) {
+ err(EXIT_FAILURE, "TEST FAILED: failed to assemble "
+ "exec argument %zu", i + 1);
+ }
+ }
+
+ (void) execv(file, argv);
+ warn("TEST FAILED: failed to exec verifier %s", file);
+}
+
+int
+main(void)
+{
+ int ret = EXIT_SUCCESS;
+ siginfo_t cret;
+
+ /*
+ * Before we do anything else close all FDs that aren't standard. We
+ * don't want anything the test suite environment may have left behind.
+ */
+ (void) closefrom(STDERR_FILENO + 1);
+
+ /*
+ * Treat failure during this set up phase as a hard failure. There's no
+ * reason to continue if we can't successfully create the FDs we expect.
+ */
+ for (size_t i = 0; i < nitems(oclo_create); i++) {
+ oclo_create[i].clo_func(&oclo_create[i]);
+ }
+
+ pid_t child = fork();
+ if (child == 0) {
+ if (!oclo_verify_fork()) {
+ ret = EXIT_FAILURE;
+ }
+
+ oclo_child_reopen();
+
+ oclo_exec();
+ ret = EXIT_FAILURE;
+ _exit(ret);
+ }
+
+ if (waitid(P_PID, child, &cret, WEXITED) < 0) {
+ err(EXIT_FAILURE, "TEST FAILED: internal test failure waiting "
+ "for forked child to report");
+ }
+
+ if (cret.si_code != CLD_EXITED) {
+ warnx("TEST FAILED: child process did not successfully exit: "
+ "found si_code: %d", cret.si_code);
+ ret = EXIT_FAILURE;
+ } else if (cret.si_status != 0) {
+ warnx("TEST FAILED: child process did not exit with code 0: "
+ "found %d", cret.si_status);
+ ret = EXIT_FAILURE;
+ }
+
+ if (ret == EXIT_SUCCESS) {
+ (void) printf("All tests passed successfully\n");
+ }
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo_errors.c b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo_errors.c
new file mode 100644
index 000000000000..05b0c1a0839b
--- /dev/null
+++ b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo_errors.c
@@ -0,0 +1,202 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2024 Oxide Computer Company
+ */
+
+/*
+ * Verify that unsupported flags will properly generate errors across the
+ * functions that we know perform strict error checking. This includes:
+ *
+ * o fcntl(..., F_DUP3FD, ...)
+ * o dup3()
+ * o pipe2()
+ * o socket()
+ * o accept4()
+ */
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define strerrorname_np(e) (sys_errlist[e])
+
+static bool
+oclo_check(const char *desc, const char *act, int ret, int e)
+{
+ if (ret >= 0) {
+ warnx("TEST FAILED: %s: fd was %s!", desc, act);
+ return (false);
+ } else if (errno != EINVAL) {
+ e = errno;
+ warnx("TEST FAILED: %s: failed with %s, expected "
+ "EINVAL", desc, strerrorname_np(e));
+ return (false);
+ }
+
+ (void) printf("TEST PASSED: %s: correctly failed with EINVAL\n",
+ desc);
+ return (true);
+}
+
+static bool
+oclo_dup3(const char *desc, int flags)
+{
+ int fd = dup3(STDERR_FILENO, 23, flags);
+ return (oclo_check(desc, "duplicated", fd, errno));
+}
+
+static bool
+oclo_dup3fd(const char *desc, int flags)
+{
+ int fd = fcntl(STDERR_FILENO, F_DUP3FD | (flags << F_DUP3FD_SHIFT), 23);
+ return (oclo_check(desc, "duplicated", fd, errno));
+}
+
+
+static bool
+oclo_pipe2(const char *desc, int flags)
+{
+ int fds[2], ret;
+
+ ret = pipe2(fds, flags);
+ return (oclo_check(desc, "piped", ret, errno));
+}
+
+#if 0
+static bool
+oclo_socket(const char *desc, int type)
+{
+ int fd = socket(PF_UNIX, SOCK_STREAM | type, 0);
+ return (oclo_check(desc, "created", fd, errno));
+}
+#endif
+
+static bool
+oclo_accept(const char *desc, int flags)
+{
+ int sock, fd, e;
+ struct sockaddr_in in;
+
+ sock = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+ if (sock < 0) {
+ warn("TEST FAILED: %s: failed to create listen socket", desc);
+ return (false);
+ }
+
+ (void) memset(&in, 0, sizeof (in));
+ in.sin_family = AF_INET;
+ in.sin_port = 0;
+ in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (bind(sock, (struct sockaddr *)&in, sizeof (in)) != 0) {
+ warn("TEST FAILED: %s: failed to bind socket", desc);
+ (void) close(sock);
+ return (false);
+ }
+
+ if (listen(sock, 5) < 0) {
+ warn("TEST FAILED: %s: failed to listen on socket", desc);
+ (void) close(sock);
+ return (false);
+ }
+
+
+ fd = accept4(sock, NULL, NULL, flags);
+ e = errno;
+ (void) close(sock);
+ return (oclo_check(desc, "accepted", fd, e));
+}
+
+int
+main(void)
+{
+ int ret = EXIT_SUCCESS;
+
+ closefrom(STDERR_FILENO + 1);
+
+ if (!oclo_dup3("dup3(): O_RDWR", O_RDWR)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_dup3("dup3(): O_NONBLOCK|O_CLOXEC", O_NONBLOCK | O_CLOEXEC)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_dup3("dup3(): O_CLOFORK|O_WRONLY", O_CLOFORK | O_WRONLY)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_dup3fd("fcntl(FDUP3FD): 0x7777", 0x7777)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_dup3fd("fcntl(FDUP3FD): FD_CLOEXEC|FD_CLOFORK + 1",
+ (FD_CLOEXEC | FD_CLOFORK) + 1)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_dup3fd("fcntl(FDUP3FD): INT_MAX", INT_MAX)) {
+ ret = EXIT_FAILURE;
+ }
+
+
+ if (!oclo_pipe2("pipe2(): O_RDWR", O_RDWR)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_pipe2("pipe2(): O_SYNC|O_CLOXEC", O_SYNC | O_CLOEXEC)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_pipe2("pipe2(): O_CLOFORK|O_WRONLY", O_CLOFORK | O_WRONLY)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_pipe2("pipe2(): INT32_MAX", INT32_MAX)) {
+ ret = EXIT_FAILURE;
+ }
+
+#if 0 /* These tests are known to fail on FreeBSD */
+ if (!oclo_socket("socket(): INT32_MAX", INT32_MAX)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_socket("socket(): 3 << 25", 3 << 25)) {
+ ret = EXIT_FAILURE;
+ }
+#endif
+
+ if (!oclo_accept("accept4(): INT32_MAX", INT32_MAX)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!oclo_accept("accept4(): 3 << 25", 3 << 25)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (ret == EXIT_SUCCESS) {
+ (void) printf("All tests completed successfully\n");
+ }
+
+ return (ret);
+}
diff --git a/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/ocloexec_verify.c b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/ocloexec_verify.c
new file mode 100644
index 000000000000..e33c61f03d54
--- /dev/null
+++ b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/ocloexec_verify.c
@@ -0,0 +1,154 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2025 Oxide Computer Company
+ */
+
+/*
+ * Verify that our file descriptors starting after stderr are correct based upon
+ * the series of passed in arguments from the 'oclo' program. Arguments are
+ * passed as a string that represents the flags that were originally verified
+ * pre-fork/exec via fcntl(F_GETFD). In addition, anything that was originally
+ * closed because it had FD_CLOFORK set was reopened with the same flags. This
+ * allows us to verify that the combinations worked and that FD_CLOFORK was
+ * properly cleared.
+ */
+
+#include <sys/types.h>
+#include <sys/user.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define strerrorname_np(e) (sys_errlist[e])
+
+static int
+getmaxfd(void)
+{
+ struct kinfo_file *files;
+ int i, cnt, max;
+
+ if ((files = kinfo_getfile(getpid(), &cnt)) == NULL)
+ err(1, "kinfo_getfile");
+
+ max = -1;
+ for (i = 0; i < cnt; i++)
+ if (files[i].kf_fd > max)
+ max = files[i].kf_fd;
+
+ free(files);
+ return (max);
+}
+
+/*
+ * Our flags may have FD_CLOFORK set in them (anything with FD_CLOEXEC Should
+ * not exist by definition). FD_CLOFORK is supposed to be cleared on exec. We
+ * still indicate which file descriptors FD_CLOFORK so we can check where it
+ * wasn't cleared.
+ */
+static bool
+verify_flags(int fd, int exp_flags)
+{
+ bool fail = (exp_flags & FD_CLOEXEC) != 0;
+ int flags = fcntl(fd, F_GETFD, NULL);
+ bool clofork = (exp_flags & FD_CLOFORK) != 0;
+ exp_flags &= ~FD_CLOFORK;
+
+ if (flags < 0) {
+ int e = errno;
+
+ if (fail) {
+ if (e == EBADF) {
+ (void) printf("TEST PASSED: post-exec fd %d: "
+ "flags 0x%x: correctly closed\n", fd,
+ exp_flags);
+ return (true);
+ }
+
+
+ warn("TEST FAILED: post-fork fd %d: expected fcntl to "
+ "fail with EBADF, but found %s", fd,
+ strerrorname_np(e));
+ return (false);
+ }
+
+ warnx("TEST FAILED: post-fork fd %d: fcntl(F_GETFD) "
+ "unexpectedly failed with %s, expected flags %d", fd,
+ strerrorname_np(e), exp_flags);
+ return (false);
+ }
+
+ if (fail) {
+ warnx("TEST FAILED: post-fork fd %d: received flags %d, but "
+ "expected to fail based on flags %d", fd, flags, exp_flags);
+ return (false);
+ }
+
+ if (clofork && (flags & FD_CLOFORK) != 0) {
+ warnx("TEST FAILED: post-fork fd %d (flags %d) retained "
+ "FD_CLOFORK, but it should have been cleared", fd, flags);
+ return (false);
+ }
+
+ if (flags != exp_flags) {
+ warnx("TEST FAILED: post-exec fd %d: discovered flags 0x%x do "
+ "not match expected flags 0x%x", fd, flags, exp_flags);
+ return (false);
+ }
+
+ (void) printf("TEST PASSED: post-exec fd %d: flags 0x%x: successfully "
+ "matched\n", fd, exp_flags);
+ return (true);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int maxfd;
+ int ret = EXIT_SUCCESS;
+
+ /*
+ * We should have one argument for each fd we found, ignoring stdin,
+ * stdout, and stderr. argc will also have an additional entry for our
+ * program name, which we want to skip. Note, the last fd may not exist
+ * because it was marked for close, hence the use of '>' below.
+ */
+ maxfd = getmaxfd();
+ if (maxfd - 3 > argc - 1) {
+ errx(EXIT_FAILURE, "TEST FAILED: found more fds %d than "
+ "arguments %d", maxfd - 3, argc - 1);
+ }
+
+ for (int i = 1; i < argc; i++) {
+ char *endptr;
+ int targ_fd = i + STDERR_FILENO;
+ errno = 0;
+ long long val = strtoll(argv[i], &endptr, 0);
+
+ if (errno != 0 || *endptr != '\0' ||
+ (val < 0 || val > (FD_CLOEXEC | FD_CLOFORK))) {
+ errx(EXIT_FAILURE, "TEST FAILED: failed to parse "
+ "argument %d: %s", i, argv[i]);
+ }
+
+ if (!verify_flags(targ_fd, (int)val))
+ ret = EXIT_FAILURE;
+ }
+
+ return (ret);
+}
diff --git a/cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile b/cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile
index 84f4706b61ee..ceb52fcf5bd0 100644
--- a/cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile
+++ b/cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile
@@ -37,6 +37,7 @@ ${PACKAGE}FILES= \
tst.profileusec.d \
tst.profileusec.d.out \
tst.sym.ksh \
+ tst.ticks.d \
tst.ufunc.ksh \
tst.ufuncsort.ksh \
tst.ufuncsort.ksh.out \
diff --git a/contrib/bmake/ChangeLog b/contrib/bmake/ChangeLog
index 0a5eced2d439..5a1c30a95750 100644
--- a/contrib/bmake/ChangeLog
+++ b/contrib/bmake/ChangeLog
@@ -1,3 +1,30 @@
+2025-07-07 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * VERSION (_MAKE_VERSION): 20250707
+ Merge with NetBSD make, pick up
+ o cond.c: improve debug log message for 'exists' function.
+ complain about unfinished escape sequences or string literals.
+
+2025-07-04 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * VERSION (_MAKE_VERSION): 20250704
+ Merge with NetBSD make, pick up
+ o make.1: add a DIAGNOSTICS section for make to reference.
+ o main.c: simplify the warning for invalid -J by refering to
+ manual page.
+
+2025-06-30 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * VERSION (_MAKE_VERSION): 20250630
+ Merge with NetBSD make, pick up
+ o consistently use double quotes in error messages
+ o cond.c: if a condition is erroneous, skip the whole .if/.endif
+ o make_malloc.c: in cleanup mode, initialize freshly allocated memory
+ o str.c: error out on an ":M" modifier whose pattern ends with
+ backslash
+ o var.c: fix parsing of modifier parts for :gmtime and :localtime
+ add POSIX $^ support
+
2025-06-18 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20250618
diff --git a/contrib/bmake/FILES b/contrib/bmake/FILES
index 8bed07d546a3..1cec16b73ef4 100644
--- a/contrib/bmake/FILES
+++ b/contrib/bmake/FILES
@@ -76,6 +76,8 @@ unit-tests/archive-suffix.exp
unit-tests/archive-suffix.mk
unit-tests/archive.exp
unit-tests/archive.mk
+unit-tests/char-005c-reverse-solidus.exp
+unit-tests/char-005c-reverse-solidus.mk
unit-tests/check-expect.lua
unit-tests/cmd-errors-jobs.exp
unit-tests/cmd-errors-jobs.mk
@@ -602,8 +604,6 @@ unit-tests/shell-ksh.exp
unit-tests/shell-ksh.mk
unit-tests/shell-sh.exp
unit-tests/shell-sh.mk
-unit-tests/suff.exp
-unit-tests/suff.mk
unit-tests/suff-add-later.exp
unit-tests/suff-add-later.mk
unit-tests/suff-clear-regular.exp
@@ -634,6 +634,8 @@ unit-tests/suff-transform-select.exp
unit-tests/suff-transform-select.mk
unit-tests/suff-use.exp
unit-tests/suff-use.mk
+unit-tests/suff.exp
+unit-tests/suff.mk
unit-tests/sunshcmd.exp
unit-tests/sunshcmd.mk
unit-tests/ternary.exp
@@ -780,6 +782,8 @@ unit-tests/varmod-unique.exp
unit-tests/varmod-unique.mk
unit-tests/varmod.exp
unit-tests/varmod.mk
+unit-tests/varname-circumflex.exp
+unit-tests/varname-circumflex.mk
unit-tests/varname-dollar.exp
unit-tests/varname-dollar.mk
unit-tests/varname-dot-alltargets.exp
diff --git a/contrib/bmake/VERSION b/contrib/bmake/VERSION
index 1467403891f1..eef1ef4b8ba9 100644
--- a/contrib/bmake/VERSION
+++ b/contrib/bmake/VERSION
@@ -1,2 +1,2 @@
# keep this compatible with sh and make
-_MAKE_VERSION=20250618
+_MAKE_VERSION=20250707
diff --git a/contrib/bmake/arch.c b/contrib/bmake/arch.c
index 77ac7f3c5707..87e2b128ae00 100644
--- a/contrib/bmake/arch.c
+++ b/contrib/bmake/arch.c
@@ -1,4 +1,4 @@
-/* $NetBSD: arch.c,v 1.222 2024/08/06 17:46:01 rillig Exp $ */
+/* $NetBSD: arch.c,v 1.223 2025/06/28 22:39:27 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -147,7 +147,7 @@ struct ar_hdr {
#include "dir.h"
/* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */
-MAKE_RCSID("$NetBSD: arch.c,v 1.222 2024/08/06 17:46:01 rillig Exp $");
+MAKE_RCSID("$NetBSD: arch.c,v 1.223 2025/06/28 22:39:27 rillig Exp $");
typedef struct List ArchList;
typedef struct ListNode ArchListNode;
@@ -314,7 +314,7 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
if (*cp == '\0') {
Parse_Error(PARSE_FATAL,
- "Missing ')' in archive specification");
+ "Missing \")\" in archive specification");
return false;
}
diff --git a/contrib/bmake/bmake.1 b/contrib/bmake/bmake.1
index 92ed9e201ea5..01f173bc1a69 100644
--- a/contrib/bmake/bmake.1
+++ b/contrib/bmake/bmake.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: make.1,v 1.385 2025/06/13 03:51:18 rillig Exp $
+.\" $NetBSD: make.1,v 1.387 2025/07/02 17:11:56 rillig Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
-.Dd June 12, 2025
+.Dd July 2, 2025
.Dt BMAKE 1
.Os
.Sh NAME
@@ -785,11 +785,13 @@ Is redundant with respect to global variables,
which have already been expanded.
.El
.Pp
-The seven built-in local variables are:
+The built-in local variables are:
.Bl -tag -width ".Va .ARCHIVE" -offset indent
.It Va .ALLSRC
The list of all sources for this target; also known as
-.Sq Va \&> .
+.Sq Va \&>
+or
+.Sq Va \&^ .
.It Va .ARCHIVE
The name of the archive file; also known as
.Sq Va \&! .
@@ -823,6 +825,7 @@ in archive member rules.
The shorter forms
.Po
.Sq Va \&> ,
+.Sq Va \&^ ,
.Sq Va \&! ,
.Sq Va \&< ,
.Sq Va \&% ,
@@ -2714,6 +2717,8 @@ If the
environment variable is set to
.Dq yes ,
any stack traces include the call chain of the parent processes.
+.\" .Sh EXIT STATUS
+.\" .Sh ENVIRONMENT
.Sh FILES
.Bl -tag -width /usr/share/mk -compact
.It .depend
@@ -2727,6 +2732,68 @@ system makefile
.It /usr/share/mk
system makefile directory
.El
+.\" .Sh EXAMPLES
+.Sh DIAGNOSTICS
+.Bl -tag
+.It Dv Invalid internal option \(dq-J\(dq in \(dq Ns Ar directory Ns Dv \(dq
+The internal
+.Fl J
+option coordinates the main
+.Nm
+process with the sub-make processes to limit
+the number of jobs that run in parallel.
+The option is passed to all child processes via the
+.Ev MAKEFLAGS
+environment variable.
+To become valid,
+this option requires that the target running the sub-make is marked with the
+.Dv .MAKE
+special source,
+or that one of the target's commands directly contains the word
+.Dq make
+or one of the expressions
+.Dq ${MAKE} ,
+.Dq ${.MAKE} ,
+.Dq $(MAKE) ,
+.Dq $(.MAKE) .
+If that's not the case,
+make issues the above warning and falls back to compat mode.
+.Pp
+To see the chain of sub-makes that leads to the invalid option, set the
+.Ev MAKE_STACK_TRACE
+environment variable to
+.Dq yes .
+.Pp
+To run the sub-make in parallel mode, even in dry-run mode (see the
+.Fl n
+option), add the
+.Dv .MAKE
+pseudo source to the target.
+This is appropriate when the sub-make runs the same target in a subdirectory.
+.Pp
+To run the sub-make in parallel mode but not in dry-mode,
+add a
+.Dq ${:D make}
+marker to one of the target's commands.
+This marker expands to an empty string
+and thus does not affect the executed commands.
+.\" The marker can even be added before any of the "@+-" modifiers,
+.\" so no need to mention this explicitly.
+.Pp
+To run the sub-make in compat mode, add the
+.Fl B
+option to its invocation.
+This is appropriate when the sub-make is only used to print a variable's
+value using the
+.Fl v
+or
+.Fl V
+options.
+.Pp
+To make the sub-make independent from the parent make, unset the
+.Ev MAKEFLAGS
+environment variable in the target's commands.
+.El
.Sh COMPATIBILITY
The basic make syntax is compatible between different make variants;
however the special variables, variable modifiers and conditionals are not.
@@ -2813,6 +2880,7 @@ not trying to chain transformations together, etc.) is also reasonably
portable.
.Sh SEE ALSO
.Xr mkdep 1
+.\" .Sh STANDARDS
.Sh HISTORY
.Nm
is derived from NetBSD
@@ -2837,6 +2905,8 @@ has been used to FoRCe rebuilding (since the target/dependency
does not exist ... unless someone creates an
.Pa FRC
file).
+.\" .Sh AUTHORS
+.\" .Sh CAVEATS
.Sh BUGS
The
.Nm
@@ -2858,3 +2928,4 @@ using that token pool to abort the build and exit with error code 6.
Sometimes the attempt to suppress a cascade of unnecessary errors,
can result in a seemingly unexplained
.Ql *** Error code 6
+.\" .Sh SECURITY CONSIDERATIONS
diff --git a/contrib/bmake/bmake.cat1 b/contrib/bmake/bmake.cat1
index 667c80898def..950437a8db9c 100644
--- a/contrib/bmake/bmake.cat1
+++ b/contrib/bmake/bmake.cat1
@@ -507,10 +507,10 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
::== Is redundant with respect to global variables, which have
already been expanded.
- The seven built-in local variables are:
+ The built-in local variables are:
_._A_L_L_S_R_C The list of all sources for this target; also known as
- `_>'.
+ `_>' or `_^'.
_._A_R_C_H_I_V_E The name of the archive file; also known as `_!'.
@@ -531,9 +531,9 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
compatibility with other makes this is an alias for
_._A_R_C_H_I_V_E in archive member rules.
- The shorter forms (`_>', `_!', `_<', `_%', `_?', `_*', and `_@') are permitted
- for backward compatibility with historical makefiles and legacy POSIX
- make and are not recommended.
+ The shorter forms (`_>', `_^', `_!', `_<', `_%', `_?', `_*', and `_@') are
+ permitted for backward compatibility with historical makefiles and legacy
+ POSIX make and are not recommended.
Variants of these variables with the punctuation followed immediately by
`D' or `F', e.g. `$(@D)', are legacy forms equivalent to using the `:H'
@@ -1748,6 +1748,39 @@ FFIILLEESS
sys.mk system makefile
/usr/share/mk system makefile directory
+DDIIAAGGNNOOSSTTIICCSS
+ Invalid internal option "-J" in "_d_i_r_e_c_t_o_r_y"
+ The internal --JJ option coordinates the main bbmmaakkee process with
+ the sub-make processes to limit the number of jobs that run in
+ parallel. The option is passed to all child processes via the
+ MAKEFLAGS environment variable. To become valid, this option
+ requires that the target running the sub-make is marked with the
+ .MAKE special source, or that one of the target's commands
+ directly contains the word "make" or one of the expressions
+ "${MAKE}", "${.MAKE}", "$(MAKE)", "$(.MAKE)". If that's not the
+ case, make issues the above warning and falls back to compat
+ mode.
+
+ To see the chain of sub-makes that leads to the invalid option,
+ set the MAKE_STACK_TRACE environment variable to "yes".
+
+ To run the sub-make in parallel mode, even in dry-run mode (see
+ the --nn option), add the .MAKE pseudo source to the target. This
+ is appropriate when the sub-make runs the same target in a
+ subdirectory.
+
+ To run the sub-make in parallel mode but not in dry-mode, add a
+ "${:D make}" marker to one of the target's commands. This marker
+ expands to an empty string and thus does not affect the executed
+ commands.
+
+ To run the sub-make in compat mode, add the --BB option to its
+ invocation. This is appropriate when the sub-make is only used
+ to print a variable's value using the --vv or --VV options.
+
+ To make the sub-make independent from the parent make, unset the
+ MAKEFLAGS environment variable in the target's commands.
+
CCOOMMPPAATTIIBBIILLIITTYY
The basic make syntax is compatible between different make variants;
however the special variables, variable modifiers and conditionals are
@@ -1831,4 +1864,4 @@ BBUUGGSS
attempt to suppress a cascade of unnecessary errors, can result in a
seemingly unexplained `*** Error code 6'
-FreeBSD 14.2-RELEASE-p1 June 12, 2025 FreeBSD 14.2-RELEASE-p1
+FreeBSD 14.2-RELEASE-p1 July 2, 2025 FreeBSD 14.2-RELEASE-p1
diff --git a/contrib/bmake/compat.c b/contrib/bmake/compat.c
index 7a51a99be4ba..f32213bf67e5 100644
--- a/contrib/bmake/compat.c
+++ b/contrib/bmake/compat.c
@@ -1,4 +1,4 @@
-/* $NetBSD: compat.c,v 1.267 2025/06/13 03:51:18 rillig Exp $ */
+/* $NetBSD: compat.c,v 1.268 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -97,7 +97,7 @@
#include "pathnames.h"
/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: compat.c,v 1.267 2025/06/13 03:51:18 rillig Exp $");
+MAKE_RCSID("$NetBSD: compat.c,v 1.268 2025/07/06 07:11:31 rillig Exp $");
static GNode *curTarg;
static pid_t compatChild;
@@ -334,11 +334,8 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
if (useShell) {
static const char *shargv[5];
- if (Cmd_Argv(cmd, cmd_len, shargv, 5,
- cmd_file, sizeof(cmd_file),
- errCheck && shellErrFlag != NULL,
- DEBUG(SHELL)) < 0)
- Fatal("cannot run \"%s\"", cmd);
+ Cmd_Argv(cmd, cmd_len, shargv, cmd_file, sizeof(cmd_file),
+ errCheck && shellErrFlag != NULL, DEBUG(SHELL));
av = shargv;
bp = NULL;
mav = NULL;
diff --git a/contrib/bmake/cond.c b/contrib/bmake/cond.c
index f83163cbb50e..b3613bbadf5d 100644
--- a/contrib/bmake/cond.c
+++ b/contrib/bmake/cond.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cond.c,v 1.373 2025/04/22 19:28:50 rillig Exp $ */
+/* $NetBSD: cond.c,v 1.378 2025/07/06 07:56:16 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -77,9 +77,8 @@
* '.if <cond>', '.elifnmake <cond>', '.else', '.endif'.
*
* Cond_EvalCondition
- * Evaluate the conditional, which is either the argument
- * of one of the .if directives or the condition in a
- * ':?then:else' variable modifier.
+ * Evaluate a condition, either from one of the .if
+ * directives, or from a ':?then:else' modifier.
*
* Cond_EndFile At the end of reading a makefile, ensure that the
* conditional directives are well-balanced.
@@ -91,14 +90,14 @@
#include "dir.h"
/* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */
-MAKE_RCSID("$NetBSD: cond.c,v 1.373 2025/04/22 19:28:50 rillig Exp $");
+MAKE_RCSID("$NetBSD: cond.c,v 1.378 2025/07/06 07:56:16 rillig Exp $");
/*
* Conditional expressions conform to this grammar:
* Or -> And ('||' And)*
* And -> Term ('&&' Term)*
* Term -> Function '(' Argument ')'
- * Term -> Leaf Operator Leaf
+ * Term -> Leaf ComparisonOp Leaf
* Term -> Leaf
* Term -> '(' Or ')'
* Term -> '!' Term
@@ -106,7 +105,7 @@ MAKE_RCSID("$NetBSD: cond.c,v 1.373 2025/04/22 19:28:50 rillig Exp $");
* Leaf -> Number
* Leaf -> VariableExpression
* Leaf -> BareWord
- * Operator -> '==' | '!=' | '>' | '<' | '>=' | '<='
+ * ComparisonOp -> '==' | '!=' | '>' | '<' | '>=' | '<='
*
* BareWord is an unquoted string literal, its evaluation depends on the kind
* of '.if' directive.
@@ -156,12 +155,12 @@ typedef struct CondParser {
* been an expression or a plain word.
*
* In conditional directives like '.if', the left-hand side must
- * either be an expression, a quoted string or a number.
+ * either be a defined expression, a quoted string or a number.
*/
bool leftUnquotedOK;
const char *p; /* The remaining condition to parse */
- Token curr; /* Single push-back token used in parsing */
+ Token curr; /* The push-back token, or TOK_NONE */
} CondParser;
static CondResult CondParser_Or(CondParser *, bool);
@@ -255,7 +254,7 @@ ParseFuncArg(const char **pp, bool doEval, const char *func)
len++;
Parse_Error(PARSE_FATAL,
- "Missing ')' after argument '%.*s' for '%.*s'",
+ "Missing \")\" after argument \"%.*s\" for \"%.*s\"",
(int)(argEnd - argStart), argStart, len, func);
free(res);
return NULL;
@@ -284,7 +283,8 @@ FuncMake(const char *targetPattern)
if (res.error != NULL && !warned) {
warned = true;
Parse_Error(PARSE_WARNING,
- "%s in pattern argument '%s' to function 'make'",
+ "%s in pattern argument \"%s\" "
+ "to function \"make\"",
res.error, targetPattern);
}
if (res.matched)
@@ -301,14 +301,16 @@ FuncExists(const char *file)
char *path;
path = Dir_FindFile(file, &dirSearchPath);
- DEBUG2(COND, "exists(%s) result is \"%s\"\n",
- file, path != NULL ? path : "");
result = path != NULL;
+ if (result)
+ DEBUG2(COND, "\"%s\" exists in \"%s\"\n", file, path);
+ else
+ DEBUG1(COND, "\"%s\" does not exist\n", file);
free(path);
return result;
}
-/* See if the given node exists and is an actual target. */
+/* See if the given node is an actual target. */
static bool
FuncTarget(const char *node)
{
@@ -316,10 +318,7 @@ FuncTarget(const char *node)
return gn != NULL && GNode_IsTarget(gn);
}
-/*
- * See if the given node exists and is an actual target with commands
- * associated with it.
- */
+/* See if the given node is an actual target with commands. */
static bool
FuncCommands(const char *node)
{
@@ -374,38 +373,37 @@ is_separator(char ch)
*
* Return whether to continue parsing the leaf.
*
- * Example: .if x${CENTER}y == "${PREFIX}${SUFFIX}" || 0x${HEX}
+ * Examples: .if x${CENTER}y == "${PREFIX}${SUFFIX}" || 0x${HEX}
*/
static bool
CondParser_StringExpr(CondParser *par, const char *start,
bool doEval, bool quoted,
- Buffer *buf, FStr *inout_str)
+ Buffer *buf, FStr *out_str)
{
VarEvalMode emode;
const char *p;
- bool atStart; /* true means an expression outside quotes */
+ bool outsideQuotes;
emode = doEval && quoted ? VARE_EVAL
: doEval ? VARE_EVAL_DEFINED_LOUD
: VARE_PARSE;
p = par->p;
- atStart = p == start;
- *inout_str = Var_Parse(&p, SCOPE_CMDLINE, emode);
- /* TODO: handle errors */
- if (inout_str->str == var_Error) {
- FStr_Done(inout_str);
- *inout_str = FStr_InitRefer(NULL);
+ outsideQuotes = p == start;
+ *out_str = Var_Parse(&p, SCOPE_CMDLINE, emode);
+ if (out_str->str == var_Error) {
+ FStr_Done(out_str);
+ *out_str = FStr_InitRefer(NULL);
return false;
}
par->p = p;
- if (atStart && is_separator(par->p[0]))
+ if (outsideQuotes && is_separator(par->p[0]))
return false;
- Buf_AddStr(buf, inout_str->str);
- FStr_Done(inout_str);
- *inout_str = FStr_InitRefer(NULL); /* not finished yet */
+ Buf_AddStr(buf, out_str->str);
+ FStr_Done(out_str);
+ *out_str = FStr_InitRefer(NULL); /* not finished yet */
return true;
}
@@ -414,7 +412,7 @@ CondParser_StringExpr(CondParser *par, const char *start,
* on the left-hand and right-hand sides of comparisons.
*
* Return the string without any enclosing quotes, or NULL on error.
- * Sets out_quoted if the leaf was a quoted string literal.
+ * Set out_quoted if the leaf was a quoted string literal.
*/
static FStr
CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
@@ -439,12 +437,14 @@ CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
if (par->p[0] != '\0') {
Buf_AddByte(&buf, par->p[0]);
par->p++;
- }
+ } else
+ Parse_Error(PARSE_FATAL,
+ "Unfinished backslash escape sequence");
continue;
case '"':
par->p++;
if (quoted)
- goto return_buf; /* skip the closing quote */
+ goto return_buf;
Buf_AddByte(&buf, '"');
continue;
case ')': /* see is_separator */
@@ -475,6 +475,9 @@ CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
continue;
}
}
+ if (quoted)
+ Parse_Error(PARSE_FATAL,
+ "Unfinished string literal \"%s\"", start);
return_buf:
str = FStr_InitOwn(buf.data);
buf.data = NULL;
@@ -528,8 +531,8 @@ EvalCompareStr(const char *lhs, ComparisonOp op, const char *rhs)
{
if (op != EQ && op != NE) {
Parse_Error(PARSE_FATAL,
- "Comparison with '%s' requires both operands "
- "'%s' and '%s' to be numeric",
+ "Comparison with \"%s\" requires both operands "
+ "\"%s\" and \"%s\" to be numeric",
opname[op], lhs, rhs);
return TOK_ERROR;
}
@@ -603,7 +606,7 @@ CondParser_Comparison(CondParser *par, bool doEval)
if (par->p[0] == '\0') {
Parse_Error(PARSE_FATAL,
- "Missing right-hand side of operator '%s'", opname[op]);
+ "Missing right-hand side of operator \"%s\"", opname[op]);
goto done_lhs;
}
@@ -768,7 +771,7 @@ CondParser_Token(CondParser *par, bool doEval)
if (par->p[0] == '|')
par->p++;
else {
- Parse_Error(PARSE_FATAL, "Unknown operator '|'");
+ Parse_Error(PARSE_FATAL, "Unknown operator \"|\"");
return TOK_ERROR;
}
return TOK_OR;
@@ -778,7 +781,7 @@ CondParser_Token(CondParser *par, bool doEval)
if (par->p[0] == '&')
par->p++;
else {
- Parse_Error(PARSE_FATAL, "Unknown operator '&'");
+ Parse_Error(PARSE_FATAL, "Unknown operator \"&\"");
return TOK_ERROR;
}
return TOK_AND;
@@ -825,7 +828,7 @@ CondParser_Skip(CondParser *par, Token t)
/*
* Term -> '(' Or ')'
* Term -> '!' Term
- * Term -> Leaf Operator Leaf
+ * Term -> Leaf ComparisonOp Leaf
* Term -> Leaf
*/
static CondResult
@@ -923,8 +926,10 @@ CondEvalExpression(const char *cond, bool plain,
if (par.curr != TOK_EOF)
rval = CR_ERROR;
- if (rval == CR_ERROR && eprint && parseErrors == parseErrorsBefore)
- Parse_Error(PARSE_FATAL, "Malformed conditional '%s'", cond);
+ if (parseErrors != parseErrorsBefore)
+ rval = CR_ERROR;
+ else if (rval == CR_ERROR && eprint)
+ Parse_Error(PARSE_FATAL, "Malformed conditional \"%s\"", cond);
return rval;
}
diff --git a/contrib/bmake/for.c b/contrib/bmake/for.c
index 438fb4e84de0..904853107db8 100644
--- a/contrib/bmake/for.c
+++ b/contrib/bmake/for.c
@@ -1,4 +1,4 @@
-/* $NetBSD: for.c,v 1.185 2025/04/22 19:28:50 rillig Exp $ */
+/* $NetBSD: for.c,v 1.186 2025/06/28 22:39:27 rillig Exp $ */
/*
* Copyright (c) 1992, The Regents of the University of California.
@@ -58,7 +58,7 @@
#include "make.h"
/* "@(#)for.c 8.1 (Berkeley) 6/6/93" */
-MAKE_RCSID("$NetBSD: for.c,v 1.185 2025/04/22 19:28:50 rillig Exp $");
+MAKE_RCSID("$NetBSD: for.c,v 1.186 2025/06/28 22:39:27 rillig Exp $");
typedef struct ForLoop {
@@ -153,7 +153,8 @@ ForLoop_ParseVarnames(ForLoop *f, const char **pp)
for (;;) {
cpp_skip_whitespace(&p);
if (*p == '\0') {
- Parse_Error(PARSE_FATAL, "missing `in' in for");
+ Parse_Error(PARSE_FATAL,
+ "Missing \"in\" in .for loop");
goto cleanup;
}
@@ -168,7 +169,8 @@ ForLoop_ParseVarnames(ForLoop *f, const char **pp)
}
if (f->vars.len == 0) {
- Parse_Error(PARSE_FATAL, "no iteration variables in for");
+ Parse_Error(PARSE_FATAL,
+ "Missing iteration variables in .for loop");
return;
}
@@ -177,7 +179,7 @@ ForLoop_ParseVarnames(ForLoop *f, const char **pp)
invalid_variable_name:
Parse_Error(PARSE_FATAL,
- "invalid character '%c' in .for loop variable name", *p);
+ "Invalid character \"%c\" in .for loop variable name", *p);
cleanup:
while (f->vars.len > 0)
free(*(char **)Vector_Pop(&f->vars));
diff --git a/contrib/bmake/job.c b/contrib/bmake/job.c
index 582870088f2d..0c54e710afeb 100644
--- a/contrib/bmake/job.c
+++ b/contrib/bmake/job.c
@@ -1,4 +1,4 @@
-/* $NetBSD: job.c,v 1.516 2025/06/13 06:13:19 rillig Exp $ */
+/* $NetBSD: job.c,v 1.517 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -89,7 +89,7 @@
* define the shell that is used for the creation
* commands in jobs mode.
*
- * Job_Finish Make the .END target. Must only be called when the
+ * Job_MakeDotEnd Make the .END target. Must only be called when the
* job table is empty.
*
* Job_AbortAll Kill all currently running jobs, in an emergency.
@@ -137,7 +137,7 @@
#include "trace.h"
/* "@(#)job.c 8.2 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: job.c,v 1.516 2025/06/13 06:13:19 rillig Exp $");
+MAKE_RCSID("$NetBSD: job.c,v 1.517 2025/07/06 07:11:31 rillig Exp $");
#ifdef USE_SELECT
@@ -599,7 +599,7 @@ Job_Pid(Job *job)
}
static void
-DumpJobs(const char *where)
+JobTable_Dump(const char *where)
{
const Job *job;
char flags[4];
@@ -663,6 +663,13 @@ SetNonblocking(int fd)
}
static void
+SetCloseOnExec(int fd)
+{
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ Punt("SetCloseOnExec: %s", strerror(errno));
+}
+
+static void
JobCreatePipe(Job *job, int minfd)
{
int i;
@@ -683,10 +690,8 @@ JobCreatePipe(Job *job, int minfd)
job->inPipe = pipe_fds[0];
job->outPipe = pipe_fds[1];
- if (fcntl(job->inPipe, F_SETFD, FD_CLOEXEC) == -1)
- Punt("SetCloseOnExec: %s", strerror(errno));
- if (fcntl(job->outPipe, F_SETFD, FD_CLOEXEC) == -1)
- Punt("SetCloseOnExec: %s", strerror(errno));
+ SetCloseOnExec(job->inPipe);
+ SetCloseOnExec(job->outPipe);
/*
* We mark the input side of the pipe non-blocking; we poll(2) the
@@ -822,7 +827,7 @@ JobFindPid(int pid, enum JobStatus status, bool isJobs)
return job;
}
if (DEBUG(JOB) && isJobs)
- DumpJobs("no pid");
+ JobTable_Dump("no pid");
return NULL;
}
@@ -1624,7 +1629,7 @@ JobExec(Job *job, char **argv)
debug_printf(
"JobExec: target %s, pid %d added to jobs table\n",
job->node->name, job->pid);
- DumpJobs("job started");
+ JobTable_Dump("job started");
}
JobsTable_Unlock(&mask);
}
@@ -2433,7 +2438,6 @@ static void
JobInterrupt(bool runINTERRUPT, int signo)
{
Job *job;
- GNode *interrupt;
sigset_t mask;
aborting = ABORT_INTERRUPT;
@@ -2460,10 +2464,10 @@ JobInterrupt(bool runINTERRUPT, int signo)
JobsTable_Unlock(&mask);
if (runINTERRUPT && !opts.touch) {
- interrupt = Targ_FindNode(".INTERRUPT");
- if (interrupt != NULL) {
+ GNode *dotInterrupt = Targ_FindNode(".INTERRUPT");
+ if (dotInterrupt != NULL) {
opts.ignoreErrors = false;
- JobRun(interrupt);
+ JobRun(dotInterrupt);
}
}
Trace_Log(MAKEINTR, NULL);
@@ -2472,15 +2476,15 @@ JobInterrupt(bool runINTERRUPT, int signo)
/* Make the .END target, returning the number of job-related errors. */
int
-Job_Finish(void)
+Job_MakeDotEnd(void)
{
- GNode *endNode = Targ_GetEndNode();
- if (!Lst_IsEmpty(&endNode->commands) ||
- !Lst_IsEmpty(&endNode->children)) {
+ GNode *dotEnd = Targ_GetEndNode();
+ if (!Lst_IsEmpty(&dotEnd->commands) ||
+ !Lst_IsEmpty(&dotEnd->children)) {
if (job_errors != 0)
Error("Errors reported so .END ignored");
else
- JobRun(endNode);
+ JobRun(dotEnd);
}
return job_errors;
}
diff --git a/contrib/bmake/job.h b/contrib/bmake/job.h
index 901be0eef1dd..2b4b5e59c37e 100644
--- a/contrib/bmake/job.h
+++ b/contrib/bmake/job.h
@@ -1,4 +1,4 @@
-/* $NetBSD: job.h,v 1.84 2025/04/22 19:28:50 rillig Exp $ */
+/* $NetBSD: job.h,v 1.85 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -101,7 +101,7 @@ void Job_CatchOutput(void);
void Job_Make(GNode *);
void Job_Init(void);
bool Job_ParseShell(char *) MAKE_ATTR_USE;
-int Job_Finish(void);
+int Job_MakeDotEnd(void);
#ifdef CLEANUP
void Job_End(void);
#endif
diff --git a/contrib/bmake/main.c b/contrib/bmake/main.c
index d020ba85f16b..a773b44f42c4 100644
--- a/contrib/bmake/main.c
+++ b/contrib/bmake/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.659 2025/06/13 05:41:36 rillig Exp $ */
+/* $NetBSD: main.c,v 1.661 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -111,7 +111,7 @@
#include "trace.h"
/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: main.c,v 1.659 2025/06/13 05:41:36 rillig Exp $");
+MAKE_RCSID("$NetBSD: main.c,v 1.661 2025/07/06 07:11:31 rillig Exp $");
#if defined(MAKE_NATIVE)
__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
"The Regents of the University of California. "
@@ -1221,23 +1221,8 @@ InitMaxJobs(void)
if (bogusJflag && !opts.compatMake) {
opts.compatMake = true;
Parse_Error(PARSE_WARNING,
- "internal option \"-J\" in \"%s\" "
- "refers to unopened file descriptors; "
- "falling back to compat mode.\n"
- "\t"
- "To run the target even in -n mode, "
- "add the .MAKE pseudo-source to the target.\n"
- "\t"
- "To run the target in default mode only, "
- "add a ${:D make} marker to a target's command. "
- "(This marker expression expands to an empty string.)\n"
- "\t"
- "To make the sub-make run in compat mode, add -B to "
- "its invocation.\n"
- "\t"
- "To make the sub-make independent from the parent make, "
- "unset the MAKEFLAGS environment variable in the "
- "target's commands.",
+ "Invalid internal option \"-J\" in \"%s\"; "
+ "see the manual page",
curdir);
PrintStackTrace(true);
return;
@@ -1734,11 +1719,10 @@ found:
}
/* populate av for Cmd_Exec and Compat_RunCommand */
-int
-Cmd_Argv(const char *cmd, size_t cmd_len, const char **av, size_t avsz,
+void
+Cmd_Argv(const char *cmd, size_t cmd_len, const char *av[5],
char *cmd_file, size_t cmd_filesz, bool eflag, bool xflag)
{
- int ac = 0;
int cmd_fd = -1;
if (shellPath == NULL)
@@ -1764,23 +1748,19 @@ Cmd_Argv(const char *cmd, size_t cmd_len, const char **av, size_t avsz,
cmd_file[0] = '\0';
}
- if (avsz < 4 || (eflag && avsz < 5))
- return -1;
-
/* The following works for any of the builtin shell specs. */
- av[ac++] = shellPath;
+ *av++ = shellPath;
if (eflag)
- av[ac++] = shellErrFlag;
+ *av++ = shellErrFlag;
if (cmd_fd >= 0) {
if (xflag)
- av[ac++] = "-x";
- av[ac++] = cmd_file;
+ *av++ = "-x";
+ *av++ = cmd_file;
} else {
- av[ac++] = xflag ? "-xc" : "-c";
- av[ac++] = cmd;
+ *av++ = xflag ? "-xc" : "-c";
+ *av++ = cmd;
}
- av[ac] = NULL;
- return ac;
+ *av = NULL;
}
/*
@@ -1790,7 +1770,7 @@ Cmd_Argv(const char *cmd, size_t cmd_len, const char **av, size_t avsz,
char *
Cmd_Exec(const char *cmd, char **error)
{
- const char *args[4]; /* Arguments for invoking the shell */
+ const char *args[5]; /* Arguments for invoking the shell */
int pipefds[2];
int cpid; /* Child PID */
int pid; /* PID from wait() */
@@ -1804,8 +1784,8 @@ Cmd_Exec(const char *cmd, char **error)
DEBUG1(VAR, "Capturing the output of command \"%s\"\n", cmd);
- if (Cmd_Argv(cmd, 0, args, 4, cmd_file, sizeof(cmd_file), false, false) < 0
- || pipe(pipefds) == -1) {
+ Cmd_Argv(cmd, 0, args, cmd_file, sizeof(cmd_file), false, false);
+ if (pipe(pipefds) == -1) {
*error = str_concat3(
"Couldn't create pipe for \"", cmd, "\"");
return bmake_strdup("");
@@ -2083,7 +2063,7 @@ shouldDieQuietly(GNode *gn, int bf)
else if (bf >= 0)
quietly = bf;
else
- quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0;
+ quietly = gn != NULL && gn->type & OP_MAKE ? 1 : 0;
}
return quietly != 0;
}
diff --git a/contrib/bmake/make.1 b/contrib/bmake/make.1
index f05653af7e31..de67759290c4 100644
--- a/contrib/bmake/make.1
+++ b/contrib/bmake/make.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: make.1,v 1.385 2025/06/13 03:51:18 rillig Exp $
+.\" $NetBSD: make.1,v 1.387 2025/07/02 17:11:56 rillig Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
-.Dd June 12, 2025
+.Dd July 2, 2025
.Dt MAKE 1
.Os
.Sh NAME
@@ -785,11 +785,13 @@ Is redundant with respect to global variables,
which have already been expanded.
.El
.Pp
-The seven built-in local variables are:
+The built-in local variables are:
.Bl -tag -width ".Va .ARCHIVE" -offset indent
.It Va .ALLSRC
The list of all sources for this target; also known as
-.Sq Va \&> .
+.Sq Va \&>
+or
+.Sq Va \&^ .
.It Va .ARCHIVE
The name of the archive file; also known as
.Sq Va \&! .
@@ -823,6 +825,7 @@ in archive member rules.
The shorter forms
.Po
.Sq Va \&> ,
+.Sq Va \&^ ,
.Sq Va \&! ,
.Sq Va \&< ,
.Sq Va \&% ,
@@ -2725,6 +2728,8 @@ If the
environment variable is set to
.Dq yes ,
any stack traces include the call chain of the parent processes.
+.\" .Sh EXIT STATUS
+.\" .Sh ENVIRONMENT
.Sh FILES
.Bl -tag -width /usr/share/mk -compact
.It .depend
@@ -2738,6 +2743,68 @@ system makefile
.It /usr/share/mk
system makefile directory
.El
+.\" .Sh EXAMPLES
+.Sh DIAGNOSTICS
+.Bl -tag
+.It Dv Invalid internal option \(dq-J\(dq in \(dq Ns Ar directory Ns Dv \(dq
+The internal
+.Fl J
+option coordinates the main
+.Nm
+process with the sub-make processes to limit
+the number of jobs that run in parallel.
+The option is passed to all child processes via the
+.Ev MAKEFLAGS
+environment variable.
+To become valid,
+this option requires that the target running the sub-make is marked with the
+.Dv .MAKE
+special source,
+or that one of the target's commands directly contains the word
+.Dq make
+or one of the expressions
+.Dq ${MAKE} ,
+.Dq ${.MAKE} ,
+.Dq $(MAKE) ,
+.Dq $(.MAKE) .
+If that's not the case,
+make issues the above warning and falls back to compat mode.
+.Pp
+To see the chain of sub-makes that leads to the invalid option, set the
+.Ev MAKE_STACK_TRACE
+environment variable to
+.Dq yes .
+.Pp
+To run the sub-make in parallel mode, even in dry-run mode (see the
+.Fl n
+option), add the
+.Dv .MAKE
+pseudo source to the target.
+This is appropriate when the sub-make runs the same target in a subdirectory.
+.Pp
+To run the sub-make in parallel mode but not in dry-mode,
+add a
+.Dq ${:D make}
+marker to one of the target's commands.
+This marker expands to an empty string
+and thus does not affect the executed commands.
+.\" The marker can even be added before any of the "@+-" modifiers,
+.\" so no need to mention this explicitly.
+.Pp
+To run the sub-make in compat mode, add the
+.Fl B
+option to its invocation.
+This is appropriate when the sub-make is only used to print a variable's
+value using the
+.Fl v
+or
+.Fl V
+options.
+.Pp
+To make the sub-make independent from the parent make, unset the
+.Ev MAKEFLAGS
+environment variable in the target's commands.
+.El
.Sh COMPATIBILITY
The basic make syntax is compatible between different make variants;
however the special variables, variable modifiers and conditionals are not.
@@ -2825,6 +2892,7 @@ portable.
.Sh SEE ALSO
.Xr mkdep 1 ,
.Xr style.Makefile 5
+.\" .Sh STANDARDS
.Sh HISTORY
A
.Nm
@@ -2844,6 +2912,8 @@ has been used to FoRCe rebuilding (since the target/dependency
does not exist ... unless someone creates an
.Pa FRC
file).
+.\" .Sh AUTHORS
+.\" .Sh CAVEATS
.Sh BUGS
The
.Nm
@@ -2865,3 +2935,4 @@ using that token pool to abort the build and exit with error code 6.
Sometimes the attempt to suppress a cascade of unnecessary errors,
can result in a seemingly unexplained
.Ql *** Error code 6
+.\" .Sh SECURITY CONSIDERATIONS
diff --git a/contrib/bmake/make.c b/contrib/bmake/make.c
index 3826c4d4e6a1..811f6e0849c4 100644
--- a/contrib/bmake/make.c
+++ b/contrib/bmake/make.c
@@ -1,4 +1,4 @@
-/* $NetBSD: make.c,v 1.272 2025/05/18 07:02:00 rillig Exp $ */
+/* $NetBSD: make.c,v 1.273 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -107,7 +107,7 @@
#endif
/* "@(#)make.c 8.1 (Berkeley) 6/6/93" */
-MAKE_RCSID("$NetBSD: make.c,v 1.272 2025/05/18 07:02:00 rillig Exp $");
+MAKE_RCSID("$NetBSD: make.c,v 1.273 2025/07/06 07:11:31 rillig Exp $");
/* Sequence # to detect recursion. */
static unsigned checked_seqno = 1;
@@ -1404,7 +1404,7 @@ Make_MakeParallel(GNodeList *targets)
(void)MakeStartJobs();
}
- errors = Job_Finish();
+ errors = Job_MakeDotEnd();
DEBUG1(MAKE, "done: errors %d\n", errors);
if (errors == 0) {
diff --git a/contrib/bmake/make.h b/contrib/bmake/make.h
index 405f03144b69..6b2b215592dd 100644
--- a/contrib/bmake/make.h
+++ b/contrib/bmake/make.h
@@ -1,4 +1,4 @@
-/* $NetBSD: make.h,v 1.360 2025/06/13 18:31:08 rillig Exp $ */
+/* $NetBSD: make.h,v 1.361 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -884,7 +884,8 @@ void JobReapChild(pid_t, int, bool);
#endif
/* main.c */
void Main_ParseArgLine(const char *);
-int Cmd_Argv(const char *, size_t, const char **, size_t, char *, size_t, bool, bool);
+void Cmd_Argv(const char *, size_t, const char *[5], char *, size_t,
+ bool, bool);
char *Cmd_Exec(const char *, char **) MAKE_ATTR_USE;
void Var_ExportStackTrace(const char *, const char *);
void Error(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
diff --git a/contrib/bmake/make_malloc.c b/contrib/bmake/make_malloc.c
index d7a735b8b08e..86e339de5dd2 100644
--- a/contrib/bmake/make_malloc.c
+++ b/contrib/bmake/make_malloc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: make_malloc.c,v 1.27 2025/06/12 18:51:05 rillig Exp $ */
+/* $NetBSD: make_malloc.c,v 1.28 2025/06/29 09:37:58 rillig Exp $ */
/*
* Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
#include "make.h"
-MAKE_RCSID("$NetBSD: make_malloc.c,v 1.27 2025/06/12 18:51:05 rillig Exp $");
+MAKE_RCSID("$NetBSD: make_malloc.c,v 1.28 2025/06/29 09:37:58 rillig Exp $");
#ifndef USE_EMALLOC
@@ -50,6 +50,9 @@ bmake_malloc(size_t len)
if ((p = malloc(len)) == NULL)
enomem();
+#ifdef CLEANUP
+ memset(p, 'Z', len);
+#endif
return p;
}
diff --git a/contrib/bmake/mk/ChangeLog b/contrib/bmake/mk/ChangeLog
index 1822f917a138..db524d2343b6 100644
--- a/contrib/bmake/mk/ChangeLog
+++ b/contrib/bmake/mk/ChangeLog
@@ -1,3 +1,7 @@
+2025-07-04 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * prog.mk: .MADE is a special source not a target!
+
2025-05-28 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20250528
diff --git a/contrib/bmake/mk/prog.mk b/contrib/bmake/mk/prog.mk
index 119645c49859..a7ced7b15d31 100644
--- a/contrib/bmake/mk/prog.mk
+++ b/contrib/bmake/mk/prog.mk
@@ -1,4 +1,4 @@
-# $Id: prog.mk,v 1.45 2024/12/12 19:56:36 sjg Exp $
+# $Id: prog.mk,v 1.46 2025/07/05 16:43:03 sjg Exp $
# should be set properly in sys.mk
_this ?= ${.PARSEFILE:S,bsd.,,}
@@ -27,11 +27,11 @@ CFLAGS+= -mcmodel=medlow
.if ${OBJECT_FMT} == "ELF"
.ifndef LIBCRTBEGIN
LIBCRTBEGIN= ${DESTDIR}/usr/lib/crtbegin.o
-.MADE: ${LIBCRTBEGIN}
+${LIBCRTBEGIN}: .MADE
.endif
.ifndef LIBCRTEND
LIBCRTEND= ${DESTDIR}/usr/lib/crtend.o
-.MADE: ${LIBCRTEND}
+${LIBCRTEND}: .MADE
.endif
_SHLINKER= ${SHLINKDIR}/ld.elf_so
.else
@@ -42,7 +42,7 @@ _SHLINKER= ${SHLINKDIR}/ld.so
.ifndef LIBCRT0
LIBCRT0= ${DESTDIR}/usr/lib/crt0.o
-.MADE: ${LIBCRT0}
+${LIBCRT0}: .MADE
.endif
.endif # NetBSD
diff --git a/contrib/bmake/parse.c b/contrib/bmake/parse.c
index 844d4db207ca..ecc77366d2d7 100644
--- a/contrib/bmake/parse.c
+++ b/contrib/bmake/parse.c
@@ -1,4 +1,4 @@
-/* $NetBSD: parse.c,v 1.752 2025/06/16 18:20:00 rillig Exp $ */
+/* $NetBSD: parse.c,v 1.753 2025/06/28 22:39:27 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -110,7 +110,7 @@
#include "pathnames.h"
/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: parse.c,v 1.752 2025/06/16 18:20:00 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.753 2025/06/28 22:39:27 rillig Exp $");
/* Detects a multiple-inclusion guard in a makefile. */
typedef enum {
@@ -954,10 +954,10 @@ InvalidLineType(const char *line, const char *unexpanded_line)
Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"",
(int)(dirend - dirstart), dirstart);
} else if (strcmp(line, unexpanded_line) == 0)
- Parse_Error(PARSE_FATAL, "Invalid line '%s'", line);
+ Parse_Error(PARSE_FATAL, "Invalid line \"%s\"", line);
else
Parse_Error(PARSE_FATAL,
- "Invalid line '%s', expanded to '%s'",
+ "Invalid line \"%s\", expanded to \"%s\"",
unexpanded_line, line);
}
@@ -1063,7 +1063,7 @@ HandleDependencyTargetPath(const char *suffixName,
path = Suff_GetPath(suffixName);
if (path == NULL) {
Parse_Error(PARSE_FATAL,
- "Suffix '%s' not defined (yet)", suffixName);
+ "Suffix \"%s\" not defined (yet)", suffixName);
return false;
}
@@ -1159,7 +1159,7 @@ SkipExtraTargets(char **pp, const char *lstart)
if (warning) {
const char *start = *pp;
cpp_skip_whitespace(&start);
- Parse_Error(PARSE_WARNING, "Extra target '%.*s' ignored",
+ Parse_Error(PARSE_WARNING, "Extra target \"%.*s\" ignored",
(int)(p - start), start);
}
@@ -1446,7 +1446,8 @@ ApplyDependencyTarget(char *name, char *nameEnd, ParseSpecial *inout_special,
if (*inout_special == SP_NOT && *name != '\0')
HandleDependencyTargetMundane(name);
else if (*inout_special == SP_PATH && *name != '.' && *name != '\0')
- Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", name);
+ Parse_Error(PARSE_WARNING, "Extra target \"%s\" ignored",
+ name);
*nameEnd = savedNameEnd;
return true;
@@ -2066,7 +2067,7 @@ ParseInclude(char *directive)
if (*p != '"' && *p != '<') {
Parse_Error(PARSE_FATAL,
- ".include filename must be delimited by '\"' or '<'");
+ ".include filename must be delimited by \"\" or <>");
return;
}
@@ -2078,7 +2079,7 @@ ParseInclude(char *directive)
if (*p != endc) {
Parse_Error(PARSE_FATAL,
- "Unclosed .include filename. '%c' expected", endc);
+ "Unclosed .include filename, \"%c\" expected", endc);
return;
}
diff --git a/contrib/bmake/str.c b/contrib/bmake/str.c
index f705b0deb874..e66cdbc8682e 100644
--- a/contrib/bmake/str.c
+++ b/contrib/bmake/str.c
@@ -1,4 +1,4 @@
-/* $NetBSD: str.c,v 1.105 2024/07/07 07:50:57 rillig Exp $ */
+/* $NetBSD: str.c,v 1.106 2025/06/28 21:09:43 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -71,7 +71,7 @@
#include "make.h"
/* "@(#)str.c 5.8 (Berkeley) 6/1/90" */
-MAKE_RCSID("$NetBSD: str.c,v 1.105 2024/07/07 07:50:57 rillig Exp $");
+MAKE_RCSID("$NetBSD: str.c,v 1.106 2025/06/28 21:09:43 rillig Exp $");
static HashTable interned_strings;
@@ -363,8 +363,11 @@ match_fixed_length:
continue;
}
- if (*pat == '\\') /* match the next character exactly */
+ if (*pat == '\\') { /* match the next character exactly */
pat++;
+ if (*pat == '\0')
+ res.error = "Unfinished backslash at the end";
+ }
if (*pat != *str) {
if (asterisk && str == fixed_str) {
while (*str != '\0' && *str != *pat)
diff --git a/contrib/bmake/unit-tests/Makefile b/contrib/bmake/unit-tests/Makefile
index 618a5959e304..4e639056815a 100644
--- a/contrib/bmake/unit-tests/Makefile
+++ b/contrib/bmake/unit-tests/Makefile
@@ -1,6 +1,6 @@
-# $Id: Makefile,v 1.239 2025/06/15 21:32:16 sjg Exp $
+# $Id: Makefile,v 1.240 2025/06/30 18:40:54 sjg Exp $
#
-# $NetBSD: Makefile,v 1.367 2025/06/13 20:23:16 rillig Exp $
+# $NetBSD: Makefile,v 1.369 2025/06/29 09:40:13 rillig Exp $
#
# Unit tests for make(1)
#
@@ -58,6 +58,7 @@ rm-tmpdir: .NOMETA
# src/tests/usr.bin/make/t_make.sh as well.
#TESTS+= archive
#TESTS+= archive-suffix
+TESTS+= char-005c-reverse-solidus
TESTS+= cmd-errors
TESTS+= cmd-errors-jobs
TESTS+= cmd-errors-lint
@@ -413,6 +414,7 @@ TESTS+= varmod-to-upper
TESTS+= varmod-undefined
TESTS+= varmod-unique
TESTS+= varname
+TESTS+= varname-circumflex
TESTS+= varname-dollar
TESTS+= varname-dot-alltargets
TESTS+= varname-dot-curdir
@@ -541,7 +543,6 @@ TESTS:= ${TESTS:${BROKEN_TESTS:S,^,N,:ts:}}
# Ideas for more tests:
# char-0020-space.mk
-# char-005C-backslash.mk
# escape-cond-str.mk
# escape-cond-func-arg.mk
# escape-varmod.mk
diff --git a/contrib/bmake/unit-tests/char-005c-reverse-solidus.exp b/contrib/bmake/unit-tests/char-005c-reverse-solidus.exp
new file mode 100644
index 000000000000..351ef95040e5
--- /dev/null
+++ b/contrib/bmake/unit-tests/char-005c-reverse-solidus.exp
@@ -0,0 +1,13 @@
+make: char-005c-reverse-solidus.mk:57: Unclosed expression, expecting "}" for modifier "Mx\}"
+ while evaluating variable "BACKSLASH" with value ""
+make: char-005c-reverse-solidus.mk:64: Unclosed expression, expecting "}" for modifier "Mx\\}"
+ while evaluating variable "BACKSLASH" with value ""
+make: char-005c-reverse-solidus.mk:71: Unclosed expression, expecting "}" for modifier "Mx\\\\\\\\}"
+ while evaluating variable "BACKSLASH" with value ""
+make: char-005c-reverse-solidus.mk:100: Unfinished backslash at the end in pattern "\" of modifier ":M"
+ while evaluating variable "BACKSLASH" with value "\"
+make: char-005c-reverse-solidus.mk:111: Unclosed expression, expecting "}" for modifier "M${:U\\\\}} != "\\""
+ while evaluating variable "BACKSLASH" with value ""
+make: Fatal errors encountered -- cannot continue
+make: stopped in unit-tests
+exit status 1
diff --git a/contrib/bmake/unit-tests/char-005c-reverse-solidus.mk b/contrib/bmake/unit-tests/char-005c-reverse-solidus.mk
new file mode 100644
index 000000000000..7a151ac46322
--- /dev/null
+++ b/contrib/bmake/unit-tests/char-005c-reverse-solidus.mk
@@ -0,0 +1,131 @@
+# $NetBSD: char-005c-reverse-solidus.mk,v 1.2 2025/06/29 11:27:21 rillig Exp $
+#
+# Tests for the character U+005C "REVERSE SOLIDUS".
+#
+# See also:
+# TODO
+# TODO
+# TODO
+
+# TODO: Where is this character used normally?
+# TODO: What are the edge cases?
+
+# TODO: escape '#' in lines
+# TODO: escape '#' in comments
+# TODO: escape ':' in modifiers
+# TODO: escape any character in condition strings
+
+# begin https://gnats.netbsd.org/46139
+
+# Too see the details of parsing, uncomment the following line.
+#.MAKEFLAGS: -dcpv
+
+# This backslash is treated as a line continuation.
+# It does not end up in the variable value.
+LINE_CONTINUATION=foo\
+# This line is still part of the variable assignment
+.if ${LINE_CONTINUATION:C,[^a-z],<>,gW} != "foo"
+. error
+.endif
+
+# The variable value contains two backslashes.
+TWO_BACKSLASHES_AT_EOL=foo\\
+.if ${TWO_BACKSLASHES_AT_EOL:C,[^a-z],<>,gW} != "foo<><>"
+. error
+.endif
+
+TRAILING_WHITESPACE=foo\ # trailing space
+.if ${TRAILING_WHITESPACE:C,[^a-z],<>,gW} != "foo<><>"
+. error
+.endif
+
+# The simplest was to produce a single backslash is the :U modifier.
+BACKSLASH= ${:U\\}
+.if ${BACKSLASH} != "\\"
+. error
+.endif
+BACKSLASH_C= ${:U1:C,.,\\,}
+.if ${BACKSLASH_C} != "\\"
+. error
+.endif
+
+# expect+5: Unclosed expression, expecting "}" for modifier "Mx\}"
+# At the point where the unclosed expression is detected, the ":M" modifier
+# has been applied to the expression. Its pattern is "x}", which doesn't
+# match the single backslash.
+# expect: while evaluating variable "BACKSLASH" with value ""
+.if ${BACKSLASH:Mx\}
+. error
+.else
+. error
+.endif
+
+# expect+1: Unclosed expression, expecting "}" for modifier "Mx\\}"
+.if ${BACKSLASH:Mx\\}
+. error
+.else
+. error
+.endif
+
+# expect+1: Unclosed expression, expecting "}" for modifier "Mx\\\\\\\\}"
+.if ${BACKSLASH:Mx\\\\\\\\}
+. error
+.else
+. error
+.endif
+
+# Adding more text after the backslash adds to the pattern, as the backslash
+# serves to escape the ":" that is otherwise used to separate the modifiers.
+# The result is a single ":M" modifier with the pattern "x:Nzzz".
+.if ${BACKSLASH:Mx\:Nzzz} != ""
+. error
+.endif
+
+# The pattern ends up as "x\:Nzzz". Only the sequence "\:" is unescaped, all
+# others, including "\\", are left as-is.
+.if ${BACKSLASH:Mx\\:Nzzz} != ""
+. error
+.endif
+
+# The pattern for the ":M" modifier ends up as "x\\\\\\\:Nzzz". Only the
+# sequence "\:" is unescaped, all others, including "\\", are left as-is.
+.if ${BACKSLASH:Mx\\\\\\\\:Nzzz} != ""
+. error
+.endif
+
+# The ":M" modifier is parsed differently than the other modifiers. To
+# circumvent the peculiarities of that parser, the pattern can be passed via
+# an expression. There, the usual escaping rules for modifiers apply.
+# expect+1: Unfinished backslash at the end in pattern "\" of modifier ":M"
+.if ${BACKSLASH:M${BACKSLASH}} != "\\"
+. error
+.else
+. error
+.endif
+
+# Trying to bypass the parser by using a direct expression doesn't work, as
+# the parser for the ":M" modifier does not parse the subexpression like in
+# all other places, but instead counts the braces and tries to decode the
+# escaping, which fails in this case.
+# expect+1: Unclosed expression, expecting "}" for modifier "M${:U\\\\}} != "\\""
+.if ${BACKSLASH:M${:U\\\\}} != "\\"
+. error
+.else
+. error
+.endif
+
+# Matching a backslash with the pattern matching characters works.
+.if ${BACKSLASH:M?} != "\\"
+. error
+.endif
+.if ${BACKSLASH:M*} != "\\"
+. error
+.endif
+.if ${BACKSLASH:M[Z-a]} != "\\"
+. error
+.endif
+.if ${BACKSLASH:M[\\]} != "\\"
+. error
+.endif
+
+# end https://gnats.netbsd.org/46139
diff --git a/contrib/bmake/unit-tests/check-expect.lua b/contrib/bmake/unit-tests/check-expect.lua
index 218056fbc021..2f3adf49baa6 100644
--- a/contrib/bmake/unit-tests/check-expect.lua
+++ b/contrib/bmake/unit-tests/check-expect.lua
@@ -1,5 +1,5 @@
#! /usr/bin/lua
--- $NetBSD: check-expect.lua,v 1.13 2025/04/13 09:29:32 rillig Exp $
+-- $NetBSD: check-expect.lua,v 1.17 2025/07/01 05:03:18 rillig Exp $
--[[
@@ -9,29 +9,32 @@ Check that the various 'expect' comments in the .mk files produce the
expected text in the corresponding .exp file.
# expect: <line>
- All of these lines must occur in the .exp file, in the same order as
- in the .mk file.
-
-# expect-reset
- Search the following 'expect:' comments from the top of the .exp
- file again.
+ Each <line> must occur in the .exp file.
+ The order in the .mk file must be the same as in the .exp file.
# expect[+-]offset: <message>
- Each message must occur in the .exp file and refer back to the
+ Each <message> must occur in the .exp file and refer back to the
source line in the .mk file.
+ Each such line in the .exp file must have a corresponding expect line
+ in the .mk file.
+ The order in the .mk file must be the same as in the .exp file.
+
+# expect-reset
+ Search the following "expect:" and "expect[+-]offset:" comments
+ from the top of the .exp file again.
# expect-not: <substring>
- The substring must not occur as part of any line of the .exp file.
+ The <substring> must not occur as part of any line in the .exp file.
# expect-not-matches: <pattern>
- The pattern (see https://lua.org/manual/5.4/manual.html#6.4.1)
- must not occur as part of any line of the .exp file.
+ The <pattern> (see https://lua.org/manual/5.4/manual.html#6.4.1)
+ must not occur as part of any line in the .exp file.
]]
local had_errors = false
---@param fmt string
-function print_error(fmt, ...)
+local function print_error(fmt, ...)
print(fmt:format(...))
had_errors = true
end
@@ -42,7 +45,9 @@ local function load_lines(fname)
local lines = {}
local f = io.open(fname, "r")
- if f == nil then return nil end
+ if f == nil then
+ return nil
+ end
for line in f:lines() do
table.insert(lines, line)
@@ -53,135 +58,129 @@ local function load_lines(fname)
end
----@param exp_lines string[]
-local function collect_lineno_diagnostics(exp_lines)
- ---@type table<string, string[]>
- local by_location = {}
+--- @shape ExpLine
+--- @field filename string | nil
+--- @field lineno number | nil
+--- @field text string
- for _, line in ipairs(exp_lines) do
- ---@type string | nil, string, string
- local l_fname, l_lineno, l_msg =
- line:match('^make: ([^:]+):(%d+): (.*)')
- if l_fname ~= nil then
- local location = ("%s:%d"):format(l_fname, l_lineno)
- if by_location[location] == nil then
- by_location[location] = {}
- end
- table.insert(by_location[location], l_msg)
+
+--- @param lines string[]
+--- @return ExpLine[]
+local function parse_exp(lines)
+ local exp_lines = {}
+ for _, line in ipairs(lines) do
+ local l_filename, l_lineno, l_text =
+ line:match('^make: ([^:]+%.mk):(%d+):%s+(.*)')
+ if not l_filename then
+ l_text = line
end
+ l_text = l_text:gsub("^%s+", ""):gsub("%s+$", "")
+ table.insert(exp_lines, {
+ filename = l_filename,
+ lineno = tonumber(l_lineno),
+ text = l_text,
+ })
end
-
- return by_location
+ return exp_lines
end
-
-local function missing(by_location)
- ---@type {filename: string, lineno: number, location: string, message: string}[]
- local missing_expectations = {}
-
- for location, messages in pairs(by_location) do
- for _, message in ipairs(messages) do
- if message ~= "" and location:find(".mk:") then
- local filename, lineno = location:match("^(%S+):(%d+)$")
- table.insert(missing_expectations, {
- filename = filename,
- lineno = tonumber(lineno),
- location = location,
- message = message
- })
- end
+---@param exp_lines ExpLine[]
+local function detect_missing_expect_lines(exp_fname, exp_lines, s, e)
+ for i = s, e do
+ local exp_line = exp_lines[i]
+ if exp_line.filename then
+ print_error("error: %s:%d requires in %s:%d: # expect+1: %s",
+ exp_fname, i, exp_line.filename, exp_line.lineno, exp_line.text)
end
end
- table.sort(missing_expectations, function(a, b)
- if a.filename ~= b.filename then
- return a.filename < b.filename
- end
- return a.lineno < b.lineno
- end)
- return missing_expectations
end
-
local function check_mk(mk_fname)
local exp_fname = mk_fname:gsub("%.mk$", ".exp")
local mk_lines = load_lines(mk_fname)
- local exp_lines = load_lines(exp_fname)
- if exp_lines == nil then return end
- local by_location = collect_lineno_diagnostics(exp_lines)
- local prev_expect_line = 0
+ local exp_raw_lines = load_lines(exp_fname)
+ if exp_raw_lines == nil then
+ return
+ end
+ local exp_lines = parse_exp(exp_raw_lines)
+
+ local exp_it = 1
for mk_lineno, mk_line in ipairs(mk_lines) do
- for text in mk_line:gmatch("#%s*expect%-not:%s*(.*)") do
- local i = 1
- while i <= #exp_lines and not exp_lines[i]:find(text, 1, true) do
- i = i + 1
- end
- if i <= #exp_lines then
- print_error("error: %s:%d: %s must not contain '%s'",
- mk_fname, mk_lineno, exp_fname, text)
+ local function match(pattern, action)
+ local _, n = mk_line:gsub(pattern, action)
+ if n > 0 then
+ match = function() end
end
end
- for text in mk_line:gmatch("#%s*expect%-not%-matches:%s*(.*)") do
- local i = 1
- while i <= #exp_lines and not exp_lines[i]:find(text) do
- i = i + 1
+ match("^#%s+expect%-not:%s*(.*)", function(text)
+ for exp_lineno, exp_line in ipairs(exp_lines) do
+ if exp_line.text:find(text, 1, true) then
+ print_error("error: %s:%d: %s:%d must not contain '%s'",
+ mk_fname, mk_lineno, exp_fname, exp_lineno, text)
+ end
end
- if i <= #exp_lines then
- print_error("error: %s:%d: %s must not match '%s'",
- mk_fname, mk_lineno, exp_fname, text)
+ end)
+
+ match("^#%s+expect%-not%-matches:%s*(.*)", function(pattern)
+ for exp_lineno, exp_line in ipairs(exp_lines) do
+ if exp_line.text:find(pattern) then
+ print_error("error: %s:%d: %s:%d must not match '%s'",
+ mk_fname, mk_lineno, exp_fname, exp_lineno, pattern)
+ end
end
- end
+ end)
- for text in mk_line:gmatch("#%s*expect:%s*(.*)") do
- local i = prev_expect_line
- -- As of 2022-04-15, some lines in the .exp files contain trailing
- -- whitespace. If possible, this should be avoided by rewriting the
- -- debug logging. When done, the trailing gsub can be removed.
- -- See deptgt-phony.exp lines 14 and 15.
- while i < #exp_lines and text ~= exp_lines[i + 1]:gsub("^%s*", ""):gsub("%s*$", "") do
+ match("^#%s+expect:%s*(.*)", function(text)
+ local i = exp_it
+ while i <= #exp_lines and text ~= exp_lines[i].text do
i = i + 1
end
- if i < #exp_lines then
- prev_expect_line = i + 1
+ if i <= #exp_lines then
+ detect_missing_expect_lines(exp_fname, exp_lines, exp_it, i - 1)
+ exp_lines[i].text = ""
+ exp_it = i + 1
else
print_error("error: %s:%d: '%s:%d+' must contain '%s'",
- mk_fname, mk_lineno, exp_fname, prev_expect_line + 1, text)
+ mk_fname, mk_lineno, exp_fname, exp_it, text)
end
- end
- if mk_line:match("^#%s*expect%-reset$") then
- prev_expect_line = 0
- end
+ end)
- ---@param text string
- for offset, text in mk_line:gmatch("#%s*expect([+%-]%d+):%s*(.*)") do
- local location = ("%s:%d"):format(mk_fname, mk_lineno + tonumber(offset))
-
- local found = false
- if by_location[location] ~= nil then
- for i, message in ipairs(by_location[location]) do
- if message == text then
- by_location[location][i] = ""
- found = true
- break
- elseif message ~= "" then
- print_error("error: %s:%d: out-of-order '%s'",
- mk_fname, mk_lineno, message)
- end
- end
+ match("^#%s+expect%-reset$", function()
+ exp_it = 1
+ end)
+
+ match("^#%s+expect([+%-]%d+):%s*(.*)", function(offset, text)
+ local msg_lineno = mk_lineno + tonumber(offset)
+
+ local i = exp_it
+ while i <= #exp_lines and text ~= exp_lines[i].text do
+ i = i + 1
end
- if not found then
- print_error("error: %s:%d: %s must contain '%s'",
- mk_fname, mk_lineno, exp_fname, text)
+ if i <= #exp_lines and exp_lines[i].lineno == msg_lineno then
+ detect_missing_expect_lines(exp_fname, exp_lines, exp_it, i - 1)
+ exp_lines[i].text = ""
+ exp_it = i + 1
+ elseif i <= #exp_lines then
+ print_error("error: %s:%d: expect%+d must be expect%+d",
+ mk_fname, mk_lineno, tonumber(offset),
+ exp_lines[i].lineno - mk_lineno)
+ else
+ print_error("error: %s:%d: %s:%d+ must contain '%s'",
+ mk_fname, mk_lineno, exp_fname, exp_it, text)
end
- end
- end
+ end)
+
+ match("^#%s+expect[+%-:]", function()
+ print_error("error: %s:%d: invalid \"expect\" line: %s",
+ mk_fname, mk_lineno, mk_line)
+ end)
- for _, m in ipairs(missing(by_location)) do
- print_error("missing: %s: # expect+1: %s", m.location, m.message)
end
+ detect_missing_expect_lines(exp_fname, exp_lines, exp_it, #exp_lines)
end
for _, fname in ipairs(arg) do
diff --git a/contrib/bmake/unit-tests/cmd-errors-jobs.exp b/contrib/bmake/unit-tests/cmd-errors-jobs.exp
index bd3ae1e51332..3be1bb9b0773 100644
--- a/contrib/bmake/unit-tests/cmd-errors-jobs.exp
+++ b/contrib/bmake/unit-tests/cmd-errors-jobs.exp
@@ -11,7 +11,7 @@ make: Unclosed variable "UNCLOSED"
in command ": unexpected $@-${UNCLOSED"
in target "parse-error-unclosed-expression"
in make[1] in directory "<curdir>"
-make: Unclosed expression, expecting '}'
+make: Unclosed expression, expecting "}"
while evaluating variable "UNCLOSED" with value ""
in command ": unexpected $@-${UNCLOSED:"
in target "parse-error-unclosed-modifier"
@@ -28,7 +28,7 @@ make: Unclosed variable "UNCLOSED"
in command ": unexpected $@-${UNCLOSED"
in target "parse-error-unclosed-expression"
in make[1] in directory "<curdir>"
-make: Unclosed expression, expecting '}'
+make: Unclosed expression, expecting "}"
while evaluating variable "UNCLOSED" with value ""
in command ": unexpected $@-${UNCLOSED:"
in target "parse-error-unclosed-modifier"
diff --git a/contrib/bmake/unit-tests/cmd-errors-jobs.mk b/contrib/bmake/unit-tests/cmd-errors-jobs.mk
index a29883fc6676..f6261d6ad1a8 100644
--- a/contrib/bmake/unit-tests/cmd-errors-jobs.mk
+++ b/contrib/bmake/unit-tests/cmd-errors-jobs.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cmd-errors-jobs.mk,v 1.15 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: cmd-errors-jobs.mk,v 1.16 2025/06/28 22:39:28 rillig Exp $
#
# Demonstrate how errors in expressions affect whether the commands
# are actually executed in jobs mode.
@@ -50,11 +50,11 @@ parse-error-unknown-modifier:
# expect-not-matches: ^: unexpected
# expect: make: Unclosed variable "UNCLOSED"
# expect: in command ": unexpected $@-${UNCLOSED"
-# expect: make: Unclosed expression, expecting '}'
+# expect: make: Unclosed expression, expecting "}"
# expect: make: Unknown modifier ":Z"
# expect: end parse-error-direct with status 2
# expect: make: Unclosed variable "UNCLOSED"
-# expect: make: Unclosed expression, expecting '}'
+# expect: make: Unclosed expression, expecting "}"
# expect: make: Unknown modifier ":Z"
# expect: end parse-error-indirect with status 2
diff --git a/contrib/bmake/unit-tests/cmd-errors-lint.exp b/contrib/bmake/unit-tests/cmd-errors-lint.exp
index ec7336f618b8..b08a65ff96dc 100644
--- a/contrib/bmake/unit-tests/cmd-errors-lint.exp
+++ b/contrib/bmake/unit-tests/cmd-errors-lint.exp
@@ -2,7 +2,7 @@
make: Unclosed variable "UNCLOSED"
in command ": $@ ${UNCLOSED"
in target "unclosed-expression"
-make: Unclosed expression, expecting '}'
+make: Unclosed expression, expecting "}"
while evaluating variable "UNCLOSED" with value ""
in command ": $@ ${UNCLOSED:"
in target "unclosed-modifier"
diff --git a/contrib/bmake/unit-tests/cmd-errors-lint.mk b/contrib/bmake/unit-tests/cmd-errors-lint.mk
index eb2ec1171545..455ef2c0cfe7 100644
--- a/contrib/bmake/unit-tests/cmd-errors-lint.mk
+++ b/contrib/bmake/unit-tests/cmd-errors-lint.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cmd-errors-lint.mk,v 1.7 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: cmd-errors-lint.mk,v 1.8 2025/06/28 22:39:28 rillig Exp $
#
# Demonstrate how errors in expressions affect whether the commands
# are actually executed.
@@ -19,7 +19,7 @@ unclosed-expression:
: $@ ${UNCLOSED
unclosed-modifier:
-# expect: make: Unclosed expression, expecting '}'
+# expect: make: Unclosed expression, expecting "}"
# expect-not: : unclosed-modifier
: $@ ${UNCLOSED:
diff --git a/contrib/bmake/unit-tests/cmd-errors.exp b/contrib/bmake/unit-tests/cmd-errors.exp
index 62da47ff42c5..2916d423029e 100644
--- a/contrib/bmake/unit-tests/cmd-errors.exp
+++ b/contrib/bmake/unit-tests/cmd-errors.exp
@@ -2,7 +2,7 @@
make: Unclosed variable "UNCLOSED"
in command ": $@-${UNCLOSED"
in target "unclosed-expression"
-make: Unclosed expression, expecting '}'
+make: Unclosed expression, expecting "}"
while evaluating variable "UNCLOSED" with value ""
in command ": $@-${UNCLOSED:"
in target "unclosed-modifier"
diff --git a/contrib/bmake/unit-tests/cmd-errors.mk b/contrib/bmake/unit-tests/cmd-errors.mk
index 8766b6a856c7..52e314c5bd38 100644
--- a/contrib/bmake/unit-tests/cmd-errors.mk
+++ b/contrib/bmake/unit-tests/cmd-errors.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cmd-errors.mk,v 1.12 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: cmd-errors.mk,v 1.13 2025/06/28 22:39:28 rillig Exp $
#
# Demonstrate how errors in expressions affect whether the commands
# are actually executed in compat mode.
@@ -17,7 +17,7 @@ unclosed-expression:
: $@-${UNCLOSED
unclosed-modifier:
-# expect: make: Unclosed expression, expecting '}'
+# expect: make: Unclosed expression, expecting "}"
# expect-not: : unclosed-modifier-
: $@-${UNCLOSED:
diff --git a/contrib/bmake/unit-tests/cmdline-undefined.exp b/contrib/bmake/unit-tests/cmdline-undefined.exp
index 12fc45e50822..ae0b35dac420 100644
--- a/contrib/bmake/unit-tests/cmdline-undefined.exp
+++ b/contrib/bmake/unit-tests/cmdline-undefined.exp
@@ -1,17 +1,17 @@
The = assignment operator
-make: cmdline-undefined.mk:31: From the command line: Undefined is .
-make: cmdline-undefined.mk:34: From .MAKEFLAGS '=': Undefined is .
-make: cmdline-undefined.mk:37: From .MAKEFLAGS ':=': Undefined is .
-make: cmdline-undefined.mk:43: From the command line: Undefined is now defined.
-make: cmdline-undefined.mk:46: From .MAKEFLAGS '=': Undefined is now defined.
+make: cmdline-undefined.mk:41: From the command line: Undefined is .
+make: cmdline-undefined.mk:42: From .MAKEFLAGS '=': Undefined is .
+make: cmdline-undefined.mk:43: From .MAKEFLAGS ':=': Undefined is .
+make: cmdline-undefined.mk:47: From the command line: Undefined is now defined.
+make: cmdline-undefined.mk:48: From .MAKEFLAGS '=': Undefined is now defined.
make: cmdline-undefined.mk:49: From .MAKEFLAGS ':=': Undefined is now defined.
The := assignment operator
-make: cmdline-undefined.mk:31: From the command line: Undefined is .
-make: cmdline-undefined.mk:34: From .MAKEFLAGS '=': Undefined is .
-make: cmdline-undefined.mk:37: From .MAKEFLAGS ':=': Undefined is .
-make: cmdline-undefined.mk:43: From the command line: Undefined is now defined.
-make: cmdline-undefined.mk:46: From .MAKEFLAGS '=': Undefined is now defined.
+make: cmdline-undefined.mk:41: From the command line: Undefined is .
+make: cmdline-undefined.mk:42: From .MAKEFLAGS '=': Undefined is .
+make: cmdline-undefined.mk:43: From .MAKEFLAGS ':=': Undefined is .
+make: cmdline-undefined.mk:47: From the command line: Undefined is now defined.
+make: cmdline-undefined.mk:48: From .MAKEFLAGS '=': Undefined is now defined.
make: cmdline-undefined.mk:49: From .MAKEFLAGS ':=': Undefined is now defined.
exit status 0
diff --git a/contrib/bmake/unit-tests/cmdline-undefined.mk b/contrib/bmake/unit-tests/cmdline-undefined.mk
index e7c0400ad1e1..2deb944b1fab 100644
--- a/contrib/bmake/unit-tests/cmdline-undefined.mk
+++ b/contrib/bmake/unit-tests/cmdline-undefined.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cmdline-undefined.mk,v 1.5 2024/04/23 22:51:28 rillig Exp $
+# $NetBSD: cmdline-undefined.mk,v 1.6 2025/06/30 21:44:39 rillig Exp $
#
# Tests for undefined variables in expressions in the command line.
@@ -8,6 +8,12 @@ all:
# (which probably occurs rarely in practice, if at all), but their
# variable value is not expanded, as usual.
#
+# expect+30: From the command line: Undefined is .
+# expect+30: From .MAKEFLAGS '=': Undefined is .
+# expect+30: From .MAKEFLAGS ':=': Undefined is .
+# expect+33: From the command line: Undefined is now defined.
+# expect+33: From .MAKEFLAGS '=': Undefined is now defined.
+# expect+33: From .MAKEFLAGS ':=': Undefined is now defined.
@echo 'The = assignment operator'
@${.MAKE} -f ${MAKEFILE} print-undefined \
CMDLINE='Undefined is $${UNDEFINED}.'
@@ -16,6 +22,12 @@ all:
# The interesting case is using the ':=' assignment operator, which
# expands its right-hand side. But only those variables that are
# defined.
+# expect+16: From the command line: Undefined is .
+# expect+16: From .MAKEFLAGS '=': Undefined is .
+# expect+16: From .MAKEFLAGS ':=': Undefined is .
+# expect+19: From the command line: Undefined is now defined.
+# expect+19: From .MAKEFLAGS '=': Undefined is now defined.
+# expect+19: From .MAKEFLAGS ':=': Undefined is now defined.
@echo 'The := assignment operator'
@${.MAKE} -f ${MAKEFILE} print-undefined \
CMDLINE:='Undefined is $${UNDEFINED}.'
@@ -26,26 +38,14 @@ all:
.MAKEFLAGS: MAKEFLAGS_ASSIGN='Undefined is $${UNDEFINED}.'
.MAKEFLAGS: MAKEFLAGS_SUBST:='Undefined is $${UNDEFINED}.'
-# expect+2: From the command line: Undefined is .
-# expect+1: From the command line: Undefined is .
.info From the command line: ${CMDLINE}
-# expect+2: From .MAKEFLAGS '=': Undefined is .
-# expect+1: From .MAKEFLAGS '=': Undefined is .
.info From .MAKEFLAGS '=': ${MAKEFLAGS_ASSIGN}
-# expect+2: From .MAKEFLAGS ':=': Undefined is .
-# expect+1: From .MAKEFLAGS ':=': Undefined is .
.info From .MAKEFLAGS ':=': ${MAKEFLAGS_SUBST}
UNDEFINED?= now defined
-# expect+2: From the command line: Undefined is now defined.
-# expect+1: From the command line: Undefined is now defined.
.info From the command line: ${CMDLINE}
-# expect+2: From .MAKEFLAGS '=': Undefined is now defined.
-# expect+1: From .MAKEFLAGS '=': Undefined is now defined.
.info From .MAKEFLAGS '=': ${MAKEFLAGS_ASSIGN}
-# expect+2: From .MAKEFLAGS ':=': Undefined is now defined.
-# expect+1: From .MAKEFLAGS ':=': Undefined is now defined.
.info From .MAKEFLAGS ':=': ${MAKEFLAGS_SUBST}
print-undefined:
diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp b/contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp
index 1a386d53dbef..81c73d887c18 100644
--- a/contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp
+++ b/contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp
@@ -1,5 +1,5 @@
-make: cond-cmp-numeric-eq.mk:68: Malformed conditional '!(12345 = 12345)'
-make: cond-cmp-numeric-eq.mk:76: Malformed conditional '!(12345 === 12345)'
+make: cond-cmp-numeric-eq.mk:68: Malformed conditional "!(12345 = 12345)"
+make: cond-cmp-numeric-eq.mk:76: Malformed conditional "!(12345 === 12345)"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric-eq.mk b/contrib/bmake/unit-tests/cond-cmp-numeric-eq.mk
index a8630cb37f1f..ea60f6f7b18d 100755
--- a/contrib/bmake/unit-tests/cond-cmp-numeric-eq.mk
+++ b/contrib/bmake/unit-tests/cond-cmp-numeric-eq.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-cmp-numeric-eq.mk,v 1.8 2024/08/06 18:00:16 rillig Exp $
+# $NetBSD: cond-cmp-numeric-eq.mk,v 1.9 2025/06/28 22:39:28 rillig Exp $
#
# Tests for numeric comparisons with the == operator in .if conditions.
@@ -64,7 +64,7 @@
.endif
# There is no = operator for numbers.
-# expect+1: Malformed conditional '!(12345 = 12345)'
+# expect+1: Malformed conditional "!(12345 = 12345)"
.if !(12345 = 12345)
. error
.else
@@ -72,7 +72,7 @@
.endif
# There is no === operator for numbers either.
-# expect+1: Malformed conditional '!(12345 === 12345)'
+# expect+1: Malformed conditional "!(12345 === 12345)"
.if !(12345 === 12345)
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric.exp b/contrib/bmake/unit-tests/cond-cmp-numeric.exp
index 0945bef72300..2959ad99716c 100644
--- a/contrib/bmake/unit-tests/cond-cmp-numeric.exp
+++ b/contrib/bmake/unit-tests/cond-cmp-numeric.exp
@@ -1,15 +1,15 @@
CondParser_Eval: !(${:UINF} > 1e100)
-make: cond-cmp-numeric.mk:15: Comparison with '>' requires both operands 'INF' and '1e100' to be numeric
+make: cond-cmp-numeric.mk:15: Comparison with ">" requires both operands "INF" and "1e100" to be numeric
CondParser_Eval: ${:UNaN} > NaN
-make: cond-cmp-numeric.mk:21: Comparison with '>' requires both operands 'NaN' and 'NaN' to be numeric
+make: cond-cmp-numeric.mk:21: Comparison with ">" requires both operands "NaN" and "NaN" to be numeric
CondParser_Eval: !(${:UNaN} == NaN)
Comparing "NaN" == "NaN"
CondParser_Eval: 123 ! 123
-make: cond-cmp-numeric.mk:38: Malformed conditional '123 ! 123'
+make: cond-cmp-numeric.mk:38: Malformed conditional "123 ! 123"
CondParser_Eval: ${:U 123} < 124
Comparing 123.000000 < 124.000000
CondParser_Eval: ${:U123 } < 124
-make: cond-cmp-numeric.mk:54: Comparison with '<' requires both operands '123 ' and '124' to be numeric
+make: cond-cmp-numeric.mk:54: Comparison with "<" requires both operands "123 " and "124" to be numeric
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric.mk b/contrib/bmake/unit-tests/cond-cmp-numeric.mk
index 63a3bff8d560..abe5cc4cce9c 100644
--- a/contrib/bmake/unit-tests/cond-cmp-numeric.mk
+++ b/contrib/bmake/unit-tests/cond-cmp-numeric.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-cmp-numeric.mk,v 1.8 2024/08/06 18:00:16 rillig Exp $
+# $NetBSD: cond-cmp-numeric.mk,v 1.9 2025/06/28 22:39:28 rillig Exp $
#
# Tests for numeric comparisons in .if conditions.
#
@@ -11,13 +11,13 @@
# Even if strtod(3) parses "INF" as +Infinity, make does not accept this
# since it is not really a number; see TryParseNumber.
-# expect+1: Comparison with '>' requires both operands 'INF' and '1e100' to be numeric
+# expect+1: Comparison with ">" requires both operands "INF" and "1e100" to be numeric
.if !(${:UINF} > 1e100)
. error
.endif
# Neither is NaN a number; see TryParseNumber.
-# expect+1: Comparison with '>' requires both operands 'NaN' and 'NaN' to be numeric
+# expect+1: Comparison with ">" requires both operands "NaN" and "NaN" to be numeric
.if ${:UNaN} > NaN
. error
.endif
@@ -34,7 +34,7 @@
# whether the operator is valid, leaving the rest of the work to the
# evaluation functions EvalCompareNum and EvalCompareStr. Ensure that this
# parse error is properly reported.
-# expect+1: Malformed conditional '123 ! 123'
+# expect+1: Malformed conditional "123 ! 123"
.if 123 ! 123
. error
.else
@@ -50,7 +50,7 @@
# Trailing spaces are NOT allowed for numbers.
# See EvalCompare and TryParseNumber.
-# expect+1: Comparison with '<' requires both operands '123 ' and '124' to be numeric
+# expect+1: Comparison with "<" requires both operands "123 " and "124" to be numeric
.if ${:U123 } < 124
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-cmp-string.exp b/contrib/bmake/unit-tests/cond-cmp-string.exp
index b55f30182442..8291d5300c3b 100644
--- a/contrib/bmake/unit-tests/cond-cmp-string.exp
+++ b/contrib/bmake/unit-tests/cond-cmp-string.exp
@@ -1,11 +1,11 @@
-make: cond-cmp-string.mk:19: Malformed conditional 'str != str'
-make: cond-cmp-string.mk:44: Malformed conditional '"string" != "str""ing"'
-make: cond-cmp-string.mk:52: Malformed conditional '!("value" = "value")'
-make: cond-cmp-string.mk:60: Malformed conditional '!("value" === "value")'
-make: cond-cmp-string.mk:118: Comparison with '<' requires both operands 'string' and 'string' to be numeric
-make: cond-cmp-string.mk:126: Comparison with '<=' requires both operands 'string' and 'string' to be numeric
-make: cond-cmp-string.mk:134: Comparison with '>' requires both operands 'string' and 'string' to be numeric
-make: cond-cmp-string.mk:142: Comparison with '>=' requires both operands 'string' and 'string' to be numeric
+make: cond-cmp-string.mk:19: Malformed conditional "str != str"
+make: cond-cmp-string.mk:44: Malformed conditional ""string" != "str""ing""
+make: cond-cmp-string.mk:52: Malformed conditional "!("value" = "value")"
+make: cond-cmp-string.mk:60: Malformed conditional "!("value" === "value")"
+make: cond-cmp-string.mk:118: Comparison with "<" requires both operands "string" and "string" to be numeric
+make: cond-cmp-string.mk:126: Comparison with "<=" requires both operands "string" and "string" to be numeric
+make: cond-cmp-string.mk:134: Comparison with ">" requires both operands "string" and "string" to be numeric
+make: cond-cmp-string.mk:142: Comparison with ">=" requires both operands "string" and "string" to be numeric
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-cmp-string.mk b/contrib/bmake/unit-tests/cond-cmp-string.mk
index a913750a017f..56427bda11d0 100644
--- a/contrib/bmake/unit-tests/cond-cmp-string.mk
+++ b/contrib/bmake/unit-tests/cond-cmp-string.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-cmp-string.mk,v 1.20 2024/08/06 18:00:16 rillig Exp $
+# $NetBSD: cond-cmp-string.mk,v 1.21 2025/06/28 22:39:28 rillig Exp $
#
# Tests for string comparisons in .if conditions.
@@ -15,7 +15,7 @@
# The left-hand side of the comparison must be enclosed in quotes.
# This one is not enclosed in quotes and thus generates an error message.
-# expect+1: Malformed conditional 'str != str'
+# expect+1: Malformed conditional "str != str"
.if str != str
. error
.endif
@@ -40,7 +40,7 @@
# It is not possible to concatenate two string literals to form a single
# string. In C, Python and the shell this is possible, but not in make.
-# expect+1: Malformed conditional '"string" != "str""ing"'
+# expect+1: Malformed conditional ""string" != "str""ing""
.if "string" != "str""ing"
. error
.else
@@ -48,7 +48,7 @@
.endif
# There is no = operator for strings.
-# expect+1: Malformed conditional '!("value" = "value")'
+# expect+1: Malformed conditional "!("value" = "value")"
.if !("value" = "value")
. error
.else
@@ -56,7 +56,7 @@
.endif
# There is no === operator for strings either.
-# expect+1: Malformed conditional '!("value" === "value")'
+# expect+1: Malformed conditional "!("value" === "value")"
.if !("value" === "value")
. error
.else
@@ -114,7 +114,7 @@
.endif
# Strings cannot be compared relationally, only for equality.
-# expect+1: Comparison with '<' requires both operands 'string' and 'string' to be numeric
+# expect+1: Comparison with "<" requires both operands "string" and "string" to be numeric
.if "string" < "string"
. error
.else
@@ -122,7 +122,7 @@
.endif
# Strings cannot be compared relationally, only for equality.
-# expect+1: Comparison with '<=' requires both operands 'string' and 'string' to be numeric
+# expect+1: Comparison with "<=" requires both operands "string" and "string" to be numeric
.if "string" <= "string"
. error
.else
@@ -130,7 +130,7 @@
.endif
# Strings cannot be compared relationally, only for equality.
-# expect+1: Comparison with '>' requires both operands 'string' and 'string' to be numeric
+# expect+1: Comparison with ">" requires both operands "string" and "string" to be numeric
.if "string" > "string"
. error
.else
@@ -138,7 +138,7 @@
.endif
# Strings cannot be compared relationally, only for equality.
-# expect+1: Comparison with '>=' requires both operands 'string' and 'string' to be numeric
+# expect+1: Comparison with ">=" requires both operands "string" and "string" to be numeric
.if "string" >= "string"
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-eof.exp b/contrib/bmake/unit-tests/cond-eof.exp
index 44e481745a24..fb23e248178e 100644
--- a/contrib/bmake/unit-tests/cond-eof.exp
+++ b/contrib/bmake/unit-tests/cond-eof.exp
@@ -1,6 +1,6 @@
-make: cond-eof.mk:17: Malformed conditional '0 ${SIDE_EFFECT} ${SIDE_EFFECT2}'
-make: cond-eof.mk:20: Malformed conditional '1 ${SIDE_EFFECT} ${SIDE_EFFECT2}'
-make: cond-eof.mk:23: Malformed conditional '(0) ${SIDE_EFFECT} ${SIDE_EFFECT2}'
+make: cond-eof.mk:17: Malformed conditional "0 ${SIDE_EFFECT} ${SIDE_EFFECT2}"
+make: cond-eof.mk:20: Malformed conditional "1 ${SIDE_EFFECT} ${SIDE_EFFECT2}"
+make: cond-eof.mk:23: Malformed conditional "(0) ${SIDE_EFFECT} ${SIDE_EFFECT2}"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-eof.mk b/contrib/bmake/unit-tests/cond-eof.mk
index 706a7deebd1a..04d79d0783ad 100644
--- a/contrib/bmake/unit-tests/cond-eof.mk
+++ b/contrib/bmake/unit-tests/cond-eof.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-eof.mk,v 1.7 2024/08/06 18:00:16 rillig Exp $
+# $NetBSD: cond-eof.mk,v 1.8 2025/06/28 22:39:28 rillig Exp $
#
# Tests for parsing the end of '.if' conditions, which are represented as the
# token TOK_EOF.
@@ -13,12 +13,12 @@ SIDE_EFFECT2= ${:!echo 'side effect 2' 1>&2!}
# These syntax errors are an edge case that does not occur during normal
# operation. Still, it is easy to avoid evaluating these expressions, just in
# case they have side effects.
-# expect+1: Malformed conditional '0 ${SIDE_EFFECT} ${SIDE_EFFECT2}'
+# expect+1: Malformed conditional "0 ${SIDE_EFFECT} ${SIDE_EFFECT2}"
.if 0 ${SIDE_EFFECT} ${SIDE_EFFECT2}
.endif
-# expect+1: Malformed conditional '1 ${SIDE_EFFECT} ${SIDE_EFFECT2}'
+# expect+1: Malformed conditional "1 ${SIDE_EFFECT} ${SIDE_EFFECT2}"
.if 1 ${SIDE_EFFECT} ${SIDE_EFFECT2}
.endif
-# expect+1: Malformed conditional '(0) ${SIDE_EFFECT} ${SIDE_EFFECT2}'
+# expect+1: Malformed conditional "(0) ${SIDE_EFFECT} ${SIDE_EFFECT2}"
.if (0) ${SIDE_EFFECT} ${SIDE_EFFECT2}
.endif
diff --git a/contrib/bmake/unit-tests/cond-func-defined.exp b/contrib/bmake/unit-tests/cond-func-defined.exp
index ea3ced9398e8..04b57061f803 100644
--- a/contrib/bmake/unit-tests/cond-func-defined.exp
+++ b/contrib/bmake/unit-tests/cond-func-defined.exp
@@ -1,5 +1,5 @@
-make: cond-func-defined.mk:24: Missing ')' after argument 'A' for 'defined'
-make: cond-func-defined.mk:34: Missing ')' after argument 'DEF' for 'defined'
+make: cond-func-defined.mk:24: Missing ")" after argument "A" for "defined"
+make: cond-func-defined.mk:34: Missing ")" after argument "DEF" for "defined"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-func-defined.mk b/contrib/bmake/unit-tests/cond-func-defined.mk
index 66f95f3380c1..52eeaec8ccfc 100644
--- a/contrib/bmake/unit-tests/cond-func-defined.mk
+++ b/contrib/bmake/unit-tests/cond-func-defined.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-func-defined.mk,v 1.14 2025/01/10 23:00:38 rillig Exp $
+# $NetBSD: cond-func-defined.mk,v 1.15 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the defined() function in .if conditions.
@@ -20,7 +20,7 @@ ${:UA B}= variable name with spaces
.endif
# The argument of a function must not directly contain whitespace.
-# expect+1: Missing ')' after argument 'A' for 'defined'
+# expect+1: Missing ")" after argument "A" for "defined"
.if !defined(A B)
. error
.endif
@@ -30,7 +30,7 @@ ${:UA B}= variable name with spaces
. error
.endif
-# expect+1: Missing ')' after argument 'DEF' for 'defined'
+# expect+1: Missing ")" after argument "DEF" for "defined"
.if defined(DEF
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-func-make.exp b/contrib/bmake/unit-tests/cond-func-make.exp
index 4d493b3c3ccb..ab25dfc5b553 100644
--- a/contrib/bmake/unit-tests/cond-func-make.exp
+++ b/contrib/bmake/unit-tests/cond-func-make.exp
@@ -1,4 +1,4 @@
-make: cond-func-make.mk:24: warning: Unfinished character list in pattern argument '[' to function 'make'
+make: cond-func-make.mk:24: warning: Unfinished character list in pattern argument "[" to function "make"
: via-cmdline
: via-dot-makeflags
exit status 0
diff --git a/contrib/bmake/unit-tests/cond-func-make.mk b/contrib/bmake/unit-tests/cond-func-make.mk
index 1a14fd320a3c..8903f9c0e723 100644
--- a/contrib/bmake/unit-tests/cond-func-make.mk
+++ b/contrib/bmake/unit-tests/cond-func-make.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-func-make.mk,v 1.6 2025/01/10 23:00:38 rillig Exp $
+# $NetBSD: cond-func-make.mk,v 1.7 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the make() function in .if conditions, which tests whether
# the argument has been passed as a target via the command line or later
@@ -20,7 +20,7 @@
. error
.endif
-# expect+1: warning: Unfinished character list in pattern argument '[' to function 'make'
+# expect+1: warning: Unfinished character list in pattern argument "[" to function "make"
.if make([)
. error
.endif
diff --git a/contrib/bmake/unit-tests/cond-func.exp b/contrib/bmake/unit-tests/cond-func.exp
index c80f95f39c0b..77f65e77d46c 100644
--- a/contrib/bmake/unit-tests/cond-func.exp
+++ b/contrib/bmake/unit-tests/cond-func.exp
@@ -1,13 +1,13 @@
-make: cond-func.mk:37: Missing ')' after argument 'A' for 'defined'
-make: cond-func.mk:53: Missing ')' after argument 'A' for 'defined'
-make: cond-func.mk:57: Missing ')' after argument 'A' for 'defined'
-make: cond-func.mk:91: Unknown operator '&'
+make: cond-func.mk:37: Missing ")" after argument "A" for "defined"
+make: cond-func.mk:53: Missing ")" after argument "A" for "defined"
+make: cond-func.mk:57: Missing ")" after argument "A" for "defined"
+make: cond-func.mk:91: Unknown operator "&"
make: cond-func.mk:107: A plain function name is parsed as defined(...).
make: cond-func.mk:115: A plain function name is parsed as defined(...).
make: cond-func.mk:126: Symbols may start with a function name.
make: cond-func.mk:132: Symbols may start with a function name.
-make: cond-func.mk:138: Missing ')' after argument '' for 'defined'
-make: cond-func.mk:145: Missing ')' after argument '${:UVARNAME}.param' for 'defined'
+make: cond-func.mk:138: Missing ")" after argument "" for "defined"
+make: cond-func.mk:145: Missing ")" after argument "${:UVARNAME}.param" for "defined"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-func.mk b/contrib/bmake/unit-tests/cond-func.mk
index 3e4f8a9f151f..50b3f83cd4cb 100644
--- a/contrib/bmake/unit-tests/cond-func.mk
+++ b/contrib/bmake/unit-tests/cond-func.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-func.mk,v 1.18 2024/08/07 05:48:45 rillig Exp $
+# $NetBSD: cond-func.mk,v 1.19 2025/06/28 22:39:28 rillig Exp $
#
# Tests for those parts of the functions in .if conditions that are common
# among several functions.
@@ -33,7 +33,7 @@ ${VARNAME_UNBALANCED_BRACES}= variable name with unbalanced braces
.endif
# The argument of a function must not directly contain whitespace.
-# expect+1: Missing ')' after argument 'A' for 'defined'
+# expect+1: Missing ")" after argument "A" for "defined"
.if !defined(A B)
. error
.endif
@@ -49,11 +49,11 @@ ${VARNAME_UNBALANCED_BRACES}= variable name with unbalanced braces
#
# It's not entirely clear why these characters are forbidden.
# The most plausible reason seems to be typo detection.
-# expect+1: Missing ')' after argument 'A' for 'defined'
+# expect+1: Missing ")" after argument "A" for "defined"
.if !defined(A&B)
. error
.endif
-# expect+1: Missing ')' after argument 'A' for 'defined'
+# expect+1: Missing ")" after argument "A" for "defined"
.if !defined(A|B)
. error
.endif
@@ -87,7 +87,7 @@ ${VARNAME_UNBALANCED_BRACES}= variable name with unbalanced braces
# interpreted as defined(A) && defined(B). Each kind of .if directive has a
# default function that is called when a bare word is parsed. For the plain
# .if directive, this function is 'defined'; see "struct If ifs" in cond.c.
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if A&B
. error
.endif
@@ -134,14 +134,14 @@ defined-var= # defined but empty
. error
.endif
-# expect+1: Missing ')' after argument '' for 'defined'
+# expect+1: Missing ")" after argument "" for "defined"
.if defined(
. error
.else
. error
.endif
-# expect+1: Missing ')' after argument '${:UVARNAME}.param' for 'defined'
+# expect+1: Missing ")" after argument "${:UVARNAME}.param" for "defined"
.if defined(${:UVARNAME}.param extra)
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-late.exp b/contrib/bmake/unit-tests/cond-late.exp
index 13846e8c822a..e4b3fdac85f4 100644
--- a/contrib/bmake/unit-tests/cond-late.exp
+++ b/contrib/bmake/unit-tests/cond-late.exp
@@ -1,4 +1,4 @@
-make: cond-late.mk:38: Bad condition
+make: cond-late.mk:29: Bad condition
while evaluating condition " != "no""
while evaluating variable "VAR" with value "${${UNDEF} != "no":?:}"
in make[1] in directory "<curdir>"
diff --git a/contrib/bmake/unit-tests/cond-late.mk b/contrib/bmake/unit-tests/cond-late.mk
index a8f381590a6e..154617f4f2b2 100644
--- a/contrib/bmake/unit-tests/cond-late.mk
+++ b/contrib/bmake/unit-tests/cond-late.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-late.mk,v 1.9 2024/08/29 20:20:35 rillig Exp $
+# $NetBSD: cond-late.mk,v 1.10 2025/06/30 21:44:39 rillig Exp $
#
# Using the :? modifier, expressions can contain conditional
# expressions that are evaluated late, at expansion time.
@@ -23,6 +23,13 @@ parse-time: .PHONY
COND.true= "yes" == "yes"
COND.false= "yes" != "yes"
+.if make(do-parse-time)
+VAR= ${${UNDEF} != "no":?:}
+# expect+1: Bad condition
+. if empty(VAR:Mpattern)
+. endif
+.endif
+
# If the order of evaluation were to change to first parse the condition
# and then expand the variables, the output would change from the
# current "yes no" to "yes yes", since both variables are non-empty.
@@ -31,10 +38,3 @@ COND.false= "yes" != "yes"
cond-literal:
@echo ${ ${COND.true} :?yes:no}
@echo ${ ${COND.false} :?yes:no}
-
-.if make(do-parse-time)
-VAR= ${${UNDEF} != "no":?:}
-# expect+1: Bad condition
-. if empty(VAR:Mpattern)
-. endif
-.endif
diff --git a/contrib/bmake/unit-tests/cond-op-and-lint.exp b/contrib/bmake/unit-tests/cond-op-and-lint.exp
index 8896fea5c9b6..74ac32e205e6 100644
--- a/contrib/bmake/unit-tests/cond-op-and-lint.exp
+++ b/contrib/bmake/unit-tests/cond-op-and-lint.exp
@@ -1,4 +1,4 @@
-make: cond-op-and-lint.mk:10: Unknown operator '&'
+make: cond-op-and-lint.mk:10: Unknown operator "&"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-and-lint.mk b/contrib/bmake/unit-tests/cond-op-and-lint.mk
index bac4566314b0..0daa3a728f86 100644
--- a/contrib/bmake/unit-tests/cond-op-and-lint.mk
+++ b/contrib/bmake/unit-tests/cond-op-and-lint.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-and-lint.mk,v 1.2 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: cond-op-and-lint.mk,v 1.3 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the && operator in .if conditions, in lint mode.
@@ -6,7 +6,7 @@
# The '&' operator is not allowed in lint mode.
# It is not used in practice anyway.
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 0 & 0
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-and.exp b/contrib/bmake/unit-tests/cond-op-and.exp
index 1ada96a00bdd..b3e45ea1767e 100644
--- a/contrib/bmake/unit-tests/cond-op-and.exp
+++ b/contrib/bmake/unit-tests/cond-op-and.exp
@@ -1,11 +1,11 @@
make: cond-op-and.mk:36: Variable "UNDEF" is undefined
make: cond-op-and.mk:41: Variable "UNDEF" is undefined
make: cond-op-and.mk:44: Variable "UNDEF" is undefined
-make: cond-op-and.mk:60: Unknown operator '&'
-make: cond-op-and.mk:66: Unknown operator '&'
-make: cond-op-and.mk:72: Unknown operator '&'
-make: cond-op-and.mk:78: Unknown operator '&'
-make: cond-op-and.mk:87: Unknown operator '&'
+make: cond-op-and.mk:60: Unknown operator "&"
+make: cond-op-and.mk:66: Unknown operator "&"
+make: cond-op-and.mk:72: Unknown operator "&"
+make: cond-op-and.mk:78: Unknown operator "&"
+make: cond-op-and.mk:87: Unknown operator "&"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-and.mk b/contrib/bmake/unit-tests/cond-op-and.mk
index 5d7f8a06800a..cb84e39e9217 100644
--- a/contrib/bmake/unit-tests/cond-op-and.mk
+++ b/contrib/bmake/unit-tests/cond-op-and.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-and.mk,v 1.12 2025/01/11 21:21:33 rillig Exp $
+# $NetBSD: cond-op-and.mk,v 1.13 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the && operator in .if conditions.
@@ -56,25 +56,25 @@ DEF= defined
# The && operator may be abbreviated as &. This is not widely known though
# and is also not documented in the manual page.
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 0 & 0
. error
.else
. error
.endif
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 1 & 0
. error
.else
. error
.endif
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 0 & 1
. error
.else
. error
.endif
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if !(1 & 1)
. error
.else
@@ -83,7 +83,7 @@ DEF= defined
# There is no operator '&&&'. The first two '&&' form an operator, the third
# '&' forms the next (incomplete) token.
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 0 &&& 0
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-not.exp b/contrib/bmake/unit-tests/cond-op-not.exp
index 63aa928eabc3..f0dfb3b757b1 100644
--- a/contrib/bmake/unit-tests/cond-op-not.exp
+++ b/contrib/bmake/unit-tests/cond-op-not.exp
@@ -3,7 +3,7 @@ make: cond-op-not.mk:39: Not space evaluates to false.
make: cond-op-not.mk:44: Not 0 evaluates to true.
make: cond-op-not.mk:53: Not 1 evaluates to false.
make: cond-op-not.mk:60: Not word evaluates to false.
-make: cond-op-not.mk:65: Malformed conditional '!'
+make: cond-op-not.mk:65: Malformed conditional "!"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-not.mk b/contrib/bmake/unit-tests/cond-op-not.mk
index 4565b60b115d..393d68675fca 100644
--- a/contrib/bmake/unit-tests/cond-op-not.mk
+++ b/contrib/bmake/unit-tests/cond-op-not.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-not.mk,v 1.9 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-op-not.mk,v 1.10 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the ! operator in .if conditions, which negates its argument.
@@ -61,7 +61,7 @@
.endif
# A single exclamation mark is a parse error.
-# expect+1: Malformed conditional '!'
+# expect+1: Malformed conditional "!"
.if !
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-or-lint.exp b/contrib/bmake/unit-tests/cond-op-or-lint.exp
index 1c5837a9aca6..32d39dead9a1 100644
--- a/contrib/bmake/unit-tests/cond-op-or-lint.exp
+++ b/contrib/bmake/unit-tests/cond-op-or-lint.exp
@@ -1,4 +1,4 @@
-make: cond-op-or-lint.mk:10: Unknown operator '|'
+make: cond-op-or-lint.mk:10: Unknown operator "|"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-or-lint.mk b/contrib/bmake/unit-tests/cond-op-or-lint.mk
index 9ece9d5c9af6..1efc5d94cbf2 100644
--- a/contrib/bmake/unit-tests/cond-op-or-lint.mk
+++ b/contrib/bmake/unit-tests/cond-op-or-lint.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-or-lint.mk,v 1.2 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: cond-op-or-lint.mk,v 1.3 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the || operator in .if conditions, in lint mode.
@@ -6,7 +6,7 @@
# The '|' operator is not allowed in lint mode.
# It is not used in practice anyway.
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if 0 | 0
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-or.exp b/contrib/bmake/unit-tests/cond-op-or.exp
index 6213759c24f7..fe42ffd6b310 100644
--- a/contrib/bmake/unit-tests/cond-op-or.exp
+++ b/contrib/bmake/unit-tests/cond-op-or.exp
@@ -1,11 +1,11 @@
make: cond-op-or.mk:36: Variable "UNDEF" is undefined
make: cond-op-or.mk:41: Variable "UNDEF" is undefined
make: cond-op-or.mk:44: Variable "UNDEF" is undefined
-make: cond-op-or.mk:60: Unknown operator '|'
-make: cond-op-or.mk:66: Unknown operator '|'
-make: cond-op-or.mk:72: Unknown operator '|'
-make: cond-op-or.mk:78: Unknown operator '|'
-make: cond-op-or.mk:87: Unknown operator '|'
+make: cond-op-or.mk:60: Unknown operator "|"
+make: cond-op-or.mk:66: Unknown operator "|"
+make: cond-op-or.mk:72: Unknown operator "|"
+make: cond-op-or.mk:78: Unknown operator "|"
+make: cond-op-or.mk:87: Unknown operator "|"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-or.mk b/contrib/bmake/unit-tests/cond-op-or.mk
index 381516499093..1c6e081dcac1 100644
--- a/contrib/bmake/unit-tests/cond-op-or.mk
+++ b/contrib/bmake/unit-tests/cond-op-or.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-or.mk,v 1.14 2025/01/11 21:21:33 rillig Exp $
+# $NetBSD: cond-op-or.mk,v 1.15 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the || operator in .if conditions.
@@ -56,25 +56,25 @@ DEF= defined
# The || operator may be abbreviated as |. This is not widely known though
# and is also not documented in the manual page.
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if 0 | 0
. error
.else
. error
.endif
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if !(1 | 0)
. error
.else
. error
.endif
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if !(0 | 1)
. error
.else
. error
.endif
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if !(1 | 1)
. error
.else
@@ -83,7 +83,7 @@ DEF= defined
# There is no operator '|||'. The first two '||' form an operator, the third
# '|' forms the next (incomplete) token.
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if 0 ||| 0
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-parentheses.exp b/contrib/bmake/unit-tests/cond-op-parentheses.exp
index a4091226ec34..f8f9efc00772 100644
--- a/contrib/bmake/unit-tests/cond-op-parentheses.exp
+++ b/contrib/bmake/unit-tests/cond-op-parentheses.exp
@@ -1,7 +1,7 @@
-make: cond-op-parentheses.mk:22: Comparison with '>' requires both operands '3' and '(2' to be numeric
-make: cond-op-parentheses.mk:25: Malformed conditional '(3) > 2'
-make: cond-op-parentheses.mk:44: Malformed conditional '('
-make: cond-op-parentheses.mk:58: Malformed conditional ')'
+make: cond-op-parentheses.mk:22: Comparison with ">" requires both operands "3" and "(2" to be numeric
+make: cond-op-parentheses.mk:25: Malformed conditional "(3) > 2"
+make: cond-op-parentheses.mk:44: Malformed conditional "("
+make: cond-op-parentheses.mk:58: Malformed conditional ")"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-parentheses.mk b/contrib/bmake/unit-tests/cond-op-parentheses.mk
index 17d5d767cd41..17d6504ede9e 100644
--- a/contrib/bmake/unit-tests/cond-op-parentheses.mk
+++ b/contrib/bmake/unit-tests/cond-op-parentheses.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-parentheses.mk,v 1.8 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-op-parentheses.mk,v 1.9 2025/06/28 22:39:28 rillig Exp $
#
# Tests for parentheses in .if conditions, which group expressions to override
# the precedence of the operators '!', '&&' and '||'. Parentheses cannot be
@@ -18,10 +18,10 @@
#
# XXX: It's inconsistent that the right operand has unbalanced parentheses.
#
-# expect+1: Comparison with '>' requires both operands '3' and '(2' to be numeric
+# expect+1: Comparison with ">" requires both operands "3" and "(2" to be numeric
.if 3 > (2)
.endif
-# expect+1: Malformed conditional '(3) > 2'
+# expect+1: Malformed conditional "(3) > 2"
.if (3) > 2
.endif
@@ -40,7 +40,7 @@
.endif
# An unbalanced opening parenthesis is a parse error.
-# expect+1: Malformed conditional '('
+# expect+1: Malformed conditional "("
.if (
. error
.else
@@ -54,7 +54,7 @@
# TOK_TRUE, TOK_FALSE or TOK_ERROR. In cond.c 1.241, the return type of that
# function was changed to a properly restricted enum type, to prevent this bug
# from occurring again.
-# expect+1: Malformed conditional ')'
+# expect+1: Malformed conditional ")"
.if )
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op.exp b/contrib/bmake/unit-tests/cond-op.exp
index 1125a35fa3b3..692698b91a96 100644
--- a/contrib/bmake/unit-tests/cond-op.exp
+++ b/contrib/bmake/unit-tests/cond-op.exp
@@ -1,7 +1,7 @@
-make: cond-op.mk:51: Malformed conditional '"!word" == !word'
-make: cond-op.mk:72: Malformed conditional '0 ${ERR::=evaluated}'
+make: cond-op.mk:51: Malformed conditional ""!word" == !word"
+make: cond-op.mk:72: Malformed conditional "0 ${ERR::=evaluated}"
make: cond-op.mk:77: A misplaced expression after 0 is not evaluated.
-make: cond-op.mk:82: Malformed conditional '1 ${ERR::=evaluated}'
+make: cond-op.mk:82: Malformed conditional "1 ${ERR::=evaluated}"
make: cond-op.mk:87: A misplaced expression after 1 is not evaluated.
make: cond-op.mk:93: A B C => (A || B) && C A || B && C A || (B && C)
make: cond-op.mk:108: 0 0 0 => 0 0 0
@@ -12,10 +12,10 @@ make: cond-op.mk:108: 1 0 0 => 0 1 1
make: cond-op.mk:108: 1 0 1 => 1 1 1
make: cond-op.mk:108: 1 1 0 => 0 1 1
make: cond-op.mk:108: 1 1 1 => 1 1 1
-make: cond-op.mk:120: Malformed conditional '1 &&'
-make: cond-op.mk:129: Malformed conditional '0 &&'
-make: cond-op.mk:138: Malformed conditional '1 ||'
-make: cond-op.mk:148: Malformed conditional '0 ||'
+make: cond-op.mk:120: Malformed conditional "1 &&"
+make: cond-op.mk:129: Malformed conditional "0 &&"
+make: cond-op.mk:138: Malformed conditional "1 ||"
+make: cond-op.mk:148: Malformed conditional "0 ||"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op.mk b/contrib/bmake/unit-tests/cond-op.mk
index 6493d887c806..974cb938065c 100644
--- a/contrib/bmake/unit-tests/cond-op.mk
+++ b/contrib/bmake/unit-tests/cond-op.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op.mk,v 1.17 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-op.mk,v 1.18 2025/06/28 22:39:28 rillig Exp $
#
# Tests for operators like &&, ||, ! in .if conditions.
#
@@ -47,7 +47,7 @@
# appear unquoted. If any, it must be enclosed in quotes.
# In any case, it is not interpreted as a negation of an unquoted string.
# See CondParser_String.
-# expect+1: Malformed conditional '"!word" == !word'
+# expect+1: Malformed conditional ""!word" == !word"
.if "!word" == !word
. error
.endif
@@ -68,7 +68,7 @@
# next token, even though in this position of the condition, only comparison
# operators, TOK_AND, TOK_OR or TOK_RPAREN are allowed.
.undef ERR
-# expect+1: Malformed conditional '0 ${ERR::=evaluated}'
+# expect+1: Malformed conditional "0 ${ERR::=evaluated}"
.if 0 ${ERR::=evaluated}
. error
.endif
@@ -78,7 +78,7 @@
.endif
.undef ERR
-# expect+1: Malformed conditional '1 ${ERR::=evaluated}'
+# expect+1: Malformed conditional "1 ${ERR::=evaluated}"
.if 1 ${ERR::=evaluated}
. error
.endif
@@ -116,7 +116,7 @@
# This condition is obviously malformed. It is properly detected and also
# was properly detected before 2021-01-19, but only because the left hand
# side of the '&&' evaluated to true.
-# expect+1: Malformed conditional '1 &&'
+# expect+1: Malformed conditional "1 &&"
.if 1 &&
. error
.else
@@ -125,7 +125,7 @@
# This obviously malformed condition was not detected as such before cond.c
# 1.238 from 2021-01-19.
-# expect+1: Malformed conditional '0 &&'
+# expect+1: Malformed conditional "0 &&"
.if 0 &&
. error
.else
@@ -134,7 +134,7 @@
# This obviously malformed condition was not detected as such before cond.c
# 1.238 from 2021-01-19.
-# expect+1: Malformed conditional '1 ||'
+# expect+1: Malformed conditional "1 ||"
.if 1 ||
. error
.else
@@ -144,7 +144,7 @@
# This condition is obviously malformed. It is properly detected and also
# was properly detected before 2021-01-19, but only because the left hand
# side of the '||' evaluated to false.
-# expect+1: Malformed conditional '0 ||'
+# expect+1: Malformed conditional "0 ||"
.if 0 ||
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-short.exp b/contrib/bmake/unit-tests/cond-short.exp
index 19c7ef3d0b89..4100e6e5ef2b 100644
--- a/contrib/bmake/unit-tests/cond-short.exp
+++ b/contrib/bmake/unit-tests/cond-short.exp
@@ -7,7 +7,7 @@ expected M pattern
expected or
expected or exists
expected or empty
-make: cond-short.mk:231: Comparison with '<' requires both operands '' and '42' to be numeric
+make: cond-short.mk:231: Comparison with "<" requires both operands "" and "42" to be numeric
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-short.mk b/contrib/bmake/unit-tests/cond-short.mk
index bcdf372ca6e6..8c4c4140596e 100644
--- a/contrib/bmake/unit-tests/cond-short.mk
+++ b/contrib/bmake/unit-tests/cond-short.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-short.mk,v 1.23 2023/11/19 22:32:44 rillig Exp $
+# $NetBSD: cond-short.mk,v 1.24 2025/06/28 22:39:28 rillig Exp $
#
# Demonstrates that in conditions, the right-hand side of an && or ||
# is only evaluated if it can actually influence the result.
@@ -227,7 +227,7 @@ VAR= ${VAR${:U1}}
# Due to the quotes around the left-hand side of the '<', the operand is
# marked as a string, thus preventing a numerical comparison.
#
-# expect+1: Comparison with '<' requires both operands '' and '42' to be numeric
+# expect+1: Comparison with "<" requires both operands "" and "42" to be numeric
.if "${INDIR_UNDEF}" < ${NUMBER}
. info yes
.else
diff --git a/contrib/bmake/unit-tests/cond-token-number.exp b/contrib/bmake/unit-tests/cond-token-number.exp
index 401f8a2364b7..a3b53c2dcd44 100644
--- a/contrib/bmake/unit-tests/cond-token-number.exp
+++ b/contrib/bmake/unit-tests/cond-token-number.exp
@@ -1,7 +1,7 @@
-make: cond-token-number.mk:16: Malformed conditional '-0'
-make: cond-token-number.mk:27: Malformed conditional '+0'
-make: cond-token-number.mk:38: Malformed conditional '!-1'
-make: cond-token-number.mk:49: Malformed conditional '!+1'
+make: cond-token-number.mk:16: Malformed conditional "-0"
+make: cond-token-number.mk:27: Malformed conditional "+0"
+make: cond-token-number.mk:38: Malformed conditional "!-1"
+make: cond-token-number.mk:49: Malformed conditional "!+1"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-token-number.mk b/contrib/bmake/unit-tests/cond-token-number.mk
index 329a51d73b2a..1d0f8d20287e 100644
--- a/contrib/bmake/unit-tests/cond-token-number.mk
+++ b/contrib/bmake/unit-tests/cond-token-number.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-token-number.mk,v 1.11 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-token-number.mk,v 1.12 2025/06/28 22:39:28 rillig Exp $
#
# Tests for number tokens in .if conditions.
#
@@ -12,7 +12,7 @@
# accepted by the condition parser.
#
# See the ch_isdigit call in CondParser_String.
-# expect+1: Malformed conditional '-0'
+# expect+1: Malformed conditional "-0"
.if -0
. error
.else
@@ -23,7 +23,7 @@
# accepted by the condition parser.
#
# See the ch_isdigit call in CondParser_String.
-# expect+1: Malformed conditional '+0'
+# expect+1: Malformed conditional "+0"
.if +0
. error
.else
@@ -34,7 +34,7 @@
# accepted by the condition parser.
#
# See the ch_isdigit call in CondParser_String.
-# expect+1: Malformed conditional '!-1'
+# expect+1: Malformed conditional "!-1"
.if !-1
. error
.else
@@ -45,7 +45,7 @@
# accepted by the condition parser.
#
# See the ch_isdigit call in CondParser_String.
-# expect+1: Malformed conditional '!+1'
+# expect+1: Malformed conditional "!+1"
.if !+1
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-token-plain.exp b/contrib/bmake/unit-tests/cond-token-plain.exp
index 52d7e6fcddaa..0b430eba7d39 100644
--- a/contrib/bmake/unit-tests/cond-token-plain.exp
+++ b/contrib/bmake/unit-tests/cond-token-plain.exp
@@ -1,10 +1,12 @@
CondParser_Eval: ${:Uvalue} != value
Comparing "value" != "value"
CondParser_Eval: ${:U} != "
+make: cond-token-plain.mk:19: Unfinished string literal """
Comparing "" != ""
CondParser_Eval: ${:U#hash} != "#hash"
Comparing "#hash" != "#hash"
CondParser_Eval: ${:U\\} != "\\
+make: cond-token-plain.mk:43: Unfinished string literal ""\\"
Comparing "\" != "\"
CondParser_Eval: ${:U#hash} != #hash
Comparing "#hash" != "#hash"
@@ -39,9 +41,9 @@ make: cond-token-plain.mk:139: Numbers can be composed from literals and express
CondParser_Eval: 0${:Ux01}
make: cond-token-plain.mk:144: Numbers can be composed from literals and expressions.
CondParser_Eval: "" ==
-make: cond-token-plain.mk:151: Missing right-hand side of operator '=='
+make: cond-token-plain.mk:151: Missing right-hand side of operator "=="
CondParser_Eval: == ""
-make: cond-token-plain.mk:160: Malformed conditional '== ""'
+make: cond-token-plain.mk:160: Malformed conditional "== """
CondParser_Eval: \\
make: cond-token-plain.mk:176: The variable '\\' is not defined.
CondParser_Eval: \\
@@ -49,15 +51,23 @@ make: cond-token-plain.mk:182: Now the variable '\\' is defined.
CondParser_Eval: "unquoted\"quoted" != unquoted"quoted
Comparing "unquoted"quoted" != "unquoted"quoted"
CondParser_Eval: $$$$$$$$ != ""
-make: cond-token-plain.mk:197: Malformed conditional '$$$$$$$$ != ""'
+make: cond-token-plain.mk:197: Malformed conditional "$$$$$$$$ != """
CondParser_Eval: left == right
-make: cond-token-plain.mk:206: Malformed conditional 'left == right'
+make: cond-token-plain.mk:206: Malformed conditional "left == right"
CondParser_Eval: ${0:?:} || left == right
CondParser_Eval: 0
-make: cond-token-plain.mk:212: Malformed conditional '${0:?:} || left == right'
+make: cond-token-plain.mk:212: Malformed conditional "${0:?:} || left == right"
CondParser_Eval: left == right || ${0:?:}
-make: cond-token-plain.mk:217: Malformed conditional 'left == right || ${0:?:}'
-make: cond-token-plain.mk:236: Malformed conditional 'VAR.${IF_COUNT::+=1} != ""'
+make: cond-token-plain.mk:217: Malformed conditional "left == right || ${0:?:}"
+make: cond-token-plain.mk:236: Malformed conditional "VAR.${IF_COUNT::+=1} != """
+make: cond-token-plain.mk:272: Unfinished backslash escape sequence
+ while evaluating condition " str == str\"
+make: cond-token-plain.mk:282: Unfinished backslash escape sequence
+ while evaluating condition " str == "str\"
+make: cond-token-plain.mk:282: Unfinished string literal ""str\"
+ while evaluating condition " str == "str\"
+make: cond-token-plain.mk:289: Unfinished string literal ""str"
+ while evaluating condition " str == "str"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-token-plain.mk b/contrib/bmake/unit-tests/cond-token-plain.mk
index 4509c1feca80..400af22f92d7 100644
--- a/contrib/bmake/unit-tests/cond-token-plain.mk
+++ b/contrib/bmake/unit-tests/cond-token-plain.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-token-plain.mk,v 1.20 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-token-plain.mk,v 1.23 2025/07/06 07:56:16 rillig Exp $
#
# Tests for plain tokens (that is, string literals without quotes)
# in .if conditions. These are also called bare words.
@@ -14,8 +14,8 @@
# condition since comment parsing is done in an early phase and removes the
# '#' and everything after it long before the condition parser gets to see it.
#
-# XXX: The error message is missing for this malformed condition.
-# The right-hand side of the comparison is just a '"', before unescaping.
+#
+# expect+1: Unfinished string literal """
.if ${:U} != "#hash"
. error
.endif
@@ -38,8 +38,8 @@
# comments are stripped in an earlier phase. See "case '#'" in
# CondParser_Token.
#
-# XXX: Missing error message for the malformed condition. The right-hand
-# side before unescaping is double-quotes, backslash, backslash.
+#
+# expect+1: Unfinished string literal ""\\"
.if ${:U\\} != "\\#hash"
. error
.endif
@@ -147,7 +147,7 @@ VAR= defined
.endif
# If the right-hand side is missing, it's a parse error.
-# expect+1: Missing right-hand side of operator '=='
+# expect+1: Missing right-hand side of operator "=="
.if "" ==
. error
.else
@@ -156,7 +156,7 @@ VAR= defined
# If the left-hand side is missing, it's a parse error as well, but without
# a specific error message.
-# expect+1: Malformed conditional '== ""'
+# expect+1: Malformed conditional "== """
.if == ""
. error
.else
@@ -193,7 +193,7 @@ ${:U\\\\}= backslash
# FIXME: In CondParser_String, Var_Parse returns var_Error without a
# corresponding error message.
-# expect+1: Malformed conditional '$$$$$$$$ != ""'
+# expect+1: Malformed conditional "$$$$$$$$ != """
.if $$$$$$$$ != ""
. error
.else
@@ -202,18 +202,18 @@ ${:U\\\\}= backslash
# In a condition in an .if directive, the left-hand side must not be an
# unquoted string literal.
-# expect+1: Malformed conditional 'left == right'
+# expect+1: Malformed conditional "left == right"
.if left == right
.endif
# Before cond.c 1.276 from 2021-09-21, an expression containing the
# modifier ':?:' allowed unquoted string literals for the rest of the
# condition. This was an unintended implementation mistake.
-# expect+1: Malformed conditional '${0:?:} || left == right'
+# expect+1: Malformed conditional "${0:?:} || left == right"
.if ${0:?:} || left == right
.endif
# This affected only the comparisons after the expression, so the following
# was still a syntax error.
-# expect+1: Malformed conditional 'left == right || ${0:?:}'
+# expect+1: Malformed conditional "left == right || ${0:?:}"
.if left == right || ${0:?:}
.endif
@@ -232,7 +232,7 @@ ${:U\\\\}= backslash
# for the second time. The right-hand side of a comparison may be a bare
# word, but that side has no risk of being parsed more than once.
#
-# expect+1: Malformed conditional 'VAR.${IF_COUNT::+=1} != ""'
+# expect+1: Malformed conditional "VAR.${IF_COUNT::+=1} != """
.if VAR.${IF_COUNT::+=1} != ""
. error
.else
@@ -265,3 +265,29 @@ COND= VAR.$${MOD_COUNT::+=1}
. error
.endif
#.MAKEFLAGS: -d0
+
+
+# A trailing backslash in a bare word does not escape anything.
+# expect+1: Unfinished backslash escape sequence
+.if ${${:U str == str\\}:?yes:no}
+. error
+.else
+. error
+.endif
+
+# A trailing backslash in an unfinished string literal word does not escape
+# anything.
+# expect+2: Unfinished backslash escape sequence
+# expect+1: Unfinished string literal ""str\"
+.if ${${:U str == "str\\}:?yes:no}
+. error
+.else
+. error
+.endif
+
+# expect+1: Unfinished string literal ""str"
+.if ${${:U str == "str}:?yes:no}
+. error
+.else
+. error
+.endif
diff --git a/contrib/bmake/unit-tests/cond-token-string.exp b/contrib/bmake/unit-tests/cond-token-string.exp
index d0a5a25f2aa4..d31c0abda17d 100644
--- a/contrib/bmake/unit-tests/cond-token-string.exp
+++ b/contrib/bmake/unit-tests/cond-token-string.exp
@@ -1,7 +1,7 @@
make: cond-token-string.mk:14: Unknown modifier ":Z"
while evaluating "${:Uvalue:Z}"" with value "value"
make: cond-token-string.mk:24: xvalue is not defined.
-make: cond-token-string.mk:31: Malformed conditional 'x${:Uvalue} == ""'
+make: cond-token-string.mk:31: Malformed conditional "x${:Uvalue} == """
make: cond-token-string.mk:41: Expected.
CondParser_Eval: "UNDEF"
make: cond-token-string.mk:51: The string literal "UNDEF" is not empty.
diff --git a/contrib/bmake/unit-tests/cond-token-string.mk b/contrib/bmake/unit-tests/cond-token-string.mk
index fb069f830582..9afe64dca821 100644
--- a/contrib/bmake/unit-tests/cond-token-string.mk
+++ b/contrib/bmake/unit-tests/cond-token-string.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-token-string.mk,v 1.16 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: cond-token-string.mk,v 1.17 2025/06/28 22:39:28 rillig Exp $
#
# Tests for quoted string literals in .if conditions.
#
@@ -27,7 +27,7 @@
# The 'x' produces a "Malformed conditional" since the left-hand side of a
# comparison in an .if directive must be either an expression, a
# quoted string literal or a number that starts with a digit.
-# expect+1: Malformed conditional 'x${:Uvalue} == ""'
+# expect+1: Malformed conditional "x${:Uvalue} == """
.if x${:Uvalue} == ""
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-token-var.exp b/contrib/bmake/unit-tests/cond-token-var.exp
index 1bf61e79ca61..b63d606c7e5a 100644
--- a/contrib/bmake/unit-tests/cond-token-var.exp
+++ b/contrib/bmake/unit-tests/cond-token-var.exp
@@ -6,11 +6,11 @@ make: cond-token-var.mk:64: Variable "U" is undefined
make: cond-token-var.mk:69: Variable "U" is undefined
make: cond-token-var.mk:78: Variable "U" is undefined
Var_Parse: ${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3} (eval)
-make: cond-token-var.mk:106: Malformed conditional 'x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}'
+make: cond-token-var.mk:106: Malformed conditional "x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}"
Var_Parse: ${DEF}y == "${UNDEF2}" || 0x${UNDEF3} (eval)
-make: cond-token-var.mk:111: Malformed conditional 'x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}'
+make: cond-token-var.mk:111: Malformed conditional "x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}"
Var_Parse: ${DEF}y == "${DEF}" || 0x${UNDEF3} (eval)
-make: cond-token-var.mk:116: Malformed conditional 'x${DEF}y == "${DEF}" || 0x${UNDEF3}'
+make: cond-token-var.mk:116: Malformed conditional "x${DEF}y == "${DEF}" || 0x${UNDEF3}"
Global: VAR.param = value of VAR.param
Var_Parse: ${VAR.param$U} (eval-defined-loud)
Var_Parse: $U} (eval)
diff --git a/contrib/bmake/unit-tests/cond-token-var.mk b/contrib/bmake/unit-tests/cond-token-var.mk
index 8da8a2436390..842ca4d2cb12 100644
--- a/contrib/bmake/unit-tests/cond-token-var.mk
+++ b/contrib/bmake/unit-tests/cond-token-var.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-token-var.mk,v 1.13 2025/04/04 18:57:01 rillig Exp $
+# $NetBSD: cond-token-var.mk,v 1.14 2025/06/28 22:39:28 rillig Exp $
#
# Tests for expressions in .if conditions.
#
@@ -102,17 +102,17 @@ DEF= defined
.MAKEFLAGS: -dv
# The left-hand side of a comparison must not be an unquoted word.
-# expect+1: Malformed conditional 'x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}'
+# expect+1: Malformed conditional "x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}"
.if x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}
.endif
# The left-hand side of a comparison must not be an unquoted word.
-# expect+1: Malformed conditional 'x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}'
+# expect+1: Malformed conditional "x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}"
.if x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}
.endif
# The left-hand side of a comparison must not be an unquoted word.
-# expect+1: Malformed conditional 'x${DEF}y == "${DEF}" || 0x${UNDEF3}'
+# expect+1: Malformed conditional "x${DEF}y == "${DEF}" || 0x${UNDEF3}"
.if x${DEF}y == "${DEF}" || 0x${UNDEF3}
.endif
diff --git a/contrib/bmake/unit-tests/dep-op-missing.exp b/contrib/bmake/unit-tests/dep-op-missing.exp
index 8521dbf79792..7c03092e09be 100644
--- a/contrib/bmake/unit-tests/dep-op-missing.exp
+++ b/contrib/bmake/unit-tests/dep-op-missing.exp
@@ -1,4 +1,4 @@
-make: dep-op-missing.tmp:1: Invalid line 'target'
+make: dep-op-missing.tmp:1: Invalid line "target"
in make[1] in directory "<curdir>"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
diff --git a/contrib/bmake/unit-tests/deptgt-begin.exp b/contrib/bmake/unit-tests/deptgt-begin.exp
index bf6f61a51e72..5aa673e33d30 100644
--- a/contrib/bmake/unit-tests/deptgt-begin.exp
+++ b/contrib/bmake/unit-tests/deptgt-begin.exp
@@ -1,5 +1,5 @@
make: deptgt-begin.mk:19: warning: duplicate script for target ".BEGIN" ignored
-make: deptgt-begin.mk:9: warning: using previous script for ".BEGIN" defined here
+make: deptgt-begin.mk:8: warning: using previous script for ".BEGIN" defined here
: parse time
: Making before-begin before .BEGIN.
: .BEGIN
diff --git a/contrib/bmake/unit-tests/deptgt-begin.mk b/contrib/bmake/unit-tests/deptgt-begin.mk
index 8b9842641a2d..a29155cb5fc2 100644
--- a/contrib/bmake/unit-tests/deptgt-begin.mk
+++ b/contrib/bmake/unit-tests/deptgt-begin.mk
@@ -1,10 +1,9 @@
-# $NetBSD: deptgt-begin.mk,v 1.7 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: deptgt-begin.mk,v 1.8 2025/06/30 21:44:39 rillig Exp $
#
# Tests for the special target .BEGIN in dependency declarations,
# which is a container for commands that are run before any other
# commands from the shell lines.
-# expect+2: warning: using previous script for ".BEGIN" defined here
.BEGIN:
: $@
@@ -14,7 +13,8 @@
# add its commands after this.
#
# There are several ways to resolve this situation, which are detailed below.
-# expect+2: warning: duplicate script for target ".BEGIN" ignored
+# expect+3: warning: duplicate script for target ".BEGIN" ignored
+# expect-9: warning: using previous script for ".BEGIN" defined here
.BEGIN:
: Making another $@.
diff --git a/contrib/bmake/unit-tests/deptgt-path-suffix.exp b/contrib/bmake/unit-tests/deptgt-path-suffix.exp
index 6294d8a39dc0..e1c67daa8787 100644
--- a/contrib/bmake/unit-tests/deptgt-path-suffix.exp
+++ b/contrib/bmake/unit-tests/deptgt-path-suffix.exp
@@ -1,4 +1,4 @@
-make: deptgt-path-suffix.mk:8: Suffix '.c' not defined (yet)
+make: deptgt-path-suffix.mk:8: Suffix ".c" not defined (yet)
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/deptgt-path-suffix.mk b/contrib/bmake/unit-tests/deptgt-path-suffix.mk
index 494a076a5520..68bb27036b68 100644
--- a/contrib/bmake/unit-tests/deptgt-path-suffix.mk
+++ b/contrib/bmake/unit-tests/deptgt-path-suffix.mk
@@ -1,10 +1,10 @@
-# $NetBSD: deptgt-path-suffix.mk,v 1.3 2021/12/13 23:38:54 rillig Exp $
+# $NetBSD: deptgt-path-suffix.mk,v 1.4 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the special target .PATH.suffix in dependency declarations.
# TODO: Implementation
-# expect+1: Suffix '.c' not defined (yet)
+# expect+1: Suffix ".c" not defined (yet)
.PATH.c: ..
.SUFFIXES: .c
diff --git a/contrib/bmake/unit-tests/deptgt.exp b/contrib/bmake/unit-tests/deptgt.exp
index 4c7cb4e50ddc..230fa497fcbd 100644
--- a/contrib/bmake/unit-tests/deptgt.exp
+++ b/contrib/bmake/unit-tests/deptgt.exp
@@ -1,4 +1,4 @@
-make: deptgt.mk:11: warning: Extra target '.PHONY' ignored
+make: deptgt.mk:11: warning: Extra target ".PHONY" ignored
make: deptgt.mk:30: Unassociated shell command ": command3 # parse error, since targets == NULL"
Parsing deptgt.mk:36: ${:U}: empty-source
ParseDependency(: empty-source)
@@ -18,8 +18,8 @@ make: deptgt.mk:51: Unknown modifier ":Z"
while evaluating "${:U:Z}:" with value ""
make: deptgt.mk:55: Unknown modifier ":Z"
while parsing "${:U:Z}:"
-make: deptgt.mk:58: warning: Extra target 'ordinary' ignored
-make: deptgt.mk:61: warning: Extra target (ordinary) ignored
+make: deptgt.mk:58: warning: Extra target "ordinary" ignored
+make: deptgt.mk:61: warning: Extra target "ordinary" ignored
make: deptgt.mk:64: warning: Special and mundane targets don't mix. Mundane ones ignored
make: Fatal errors encountered -- cannot continue
make: stopped making "target1" in unit-tests
diff --git a/contrib/bmake/unit-tests/deptgt.mk b/contrib/bmake/unit-tests/deptgt.mk
index 779a1faf7115..fd7a716e3ebc 100644
--- a/contrib/bmake/unit-tests/deptgt.mk
+++ b/contrib/bmake/unit-tests/deptgt.mk
@@ -1,4 +1,4 @@
-# $NetBSD: deptgt.mk,v 1.23 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: deptgt.mk,v 1.24 2025/06/28 22:39:28 rillig Exp $
#
# Tests for special targets like .BEGIN or .SUFFIXES in dependency
# declarations.
@@ -7,7 +7,7 @@
# Just in case anyone tries to compile several special targets in a single
# dependency line: That doesn't work, and make immediately rejects it.
-# expect+1: warning: Extra target '.PHONY' ignored
+# expect+1: warning: Extra target ".PHONY" ignored
.SUFFIXES .PHONY: .c.o
# The following lines demonstrate how 'targets' is set and reset during
@@ -54,10 +54,10 @@ ${:U:Z}:
# expect+1: Unknown modifier ":Z"
$${:U:Z}:
-# expect+1: warning: Extra target 'ordinary' ignored
+# expect+1: warning: Extra target "ordinary" ignored
.END ordinary:
-# expect+1: warning: Extra target (ordinary) ignored
+# expect+1: warning: Extra target "ordinary" ignored
.PATH ordinary:
# expect+1: warning: Special and mundane targets don't mix. Mundane ones ignored
diff --git a/contrib/bmake/unit-tests/directive-dinclude.exp b/contrib/bmake/unit-tests/directive-dinclude.exp
index 5f5fec4d403e..55f1f77fbfde 100755
--- a/contrib/bmake/unit-tests/directive-dinclude.exp
+++ b/contrib/bmake/unit-tests/directive-dinclude.exp
@@ -1,4 +1,4 @@
-make: directive-dinclude-error.inc:1: Invalid line 'syntax error'
+make: directive-dinclude-error.inc:1: Invalid line "syntax error"
in directive-dinclude.mk:21
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
diff --git a/contrib/bmake/unit-tests/directive-dinclude.mk b/contrib/bmake/unit-tests/directive-dinclude.mk
index c363209579ad..da063083235f 100755
--- a/contrib/bmake/unit-tests/directive-dinclude.mk
+++ b/contrib/bmake/unit-tests/directive-dinclude.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-dinclude.mk,v 1.4 2025/03/30 09:51:50 rillig Exp $
+# $NetBSD: directive-dinclude.mk,v 1.5 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .dinclude directive, which includes another file,
# silently skipping it if it cannot be opened. This is primarily used for
@@ -16,7 +16,7 @@
.dinclude "${MAKEFILE}/subdir"
# Errors that are not related to opening the file are still reported.
-# expect: make: directive-dinclude-error.inc:1: Invalid line 'syntax error'
+# expect: make: directive-dinclude-error.inc:1: Invalid line "syntax error"
_!= echo 'syntax error' > directive-dinclude-error.inc
.dinclude "${.CURDIR}/directive-dinclude-error.inc"
_!= rm directive-dinclude-error.inc
diff --git a/contrib/bmake/unit-tests/directive-export-gmake.exp b/contrib/bmake/unit-tests/directive-export-gmake.exp
index f7bb07ab9da2..2c2875d669d2 100644
--- a/contrib/bmake/unit-tests/directive-export-gmake.exp
+++ b/contrib/bmake/unit-tests/directive-export-gmake.exp
@@ -1,4 +1,4 @@
-make: directive-export-gmake.mk:71: Invalid line 'export VAR=${:U1}', expanded to 'export VAR=1'
+make: directive-export-gmake.mk:71: Invalid line "export VAR=${:U1}", expanded to "export VAR=1"
in .for loop from directive-export-gmake.mk:67 with value = 1
make: directive-export-gmake.mk:85: 16:00:00
make: directive-export-gmake.mk:92: Variable/Value missing from "export"
diff --git a/contrib/bmake/unit-tests/directive-export-gmake.mk b/contrib/bmake/unit-tests/directive-export-gmake.mk
index de79470bf305..6e1d57c6a62d 100644
--- a/contrib/bmake/unit-tests/directive-export-gmake.mk
+++ b/contrib/bmake/unit-tests/directive-export-gmake.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-export-gmake.mk,v 1.9 2023/12/17 09:44:00 rillig Exp $
+# $NetBSD: directive-export-gmake.mk,v 1.10 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the export directive (without leading dot), as in GNU make.
@@ -67,7 +67,7 @@ export VAR=an ${UNDEF} variable
.for value in 1
# XXX: The ':' in this line is inside an expression and should thus not be
# interpreted as a dependency operator.
-# expect+1: Invalid line 'export VAR=${:U1}', expanded to 'export VAR=1'
+# expect+1: Invalid line "export VAR=${:U1}", expanded to "export VAR=1"
export VAR=${value}
.endfor
diff --git a/contrib/bmake/unit-tests/directive-for-errors.exp b/contrib/bmake/unit-tests/directive-for-errors.exp
index 39929864314d..1bae631b967a 100644
--- a/contrib/bmake/unit-tests/directive-for-errors.exp
+++ b/contrib/bmake/unit-tests/directive-for-errors.exp
@@ -4,10 +4,10 @@ make: directive-for-errors.mk:13: for-less endfor
make: directive-for-errors.mk:25: Unknown directive "for"
make: directive-for-errors.mk:27: warning: <>
make: directive-for-errors.mk:29: for-less endfor
-make: directive-for-errors.mk:44: invalid character '$' in .for loop variable name
-make: directive-for-errors.mk:52: no iteration variables in for
+make: directive-for-errors.mk:44: Invalid character "$" in .for loop variable name
+make: directive-for-errors.mk:52: Missing iteration variables in .for loop
make: directive-for-errors.mk:64: Wrong number of words (5) in .for substitution list with 3 variables
-make: directive-for-errors.mk:78: missing `in' in for
+make: directive-for-errors.mk:78: Missing "in" in .for loop
make: directive-for-errors.mk:85: Unknown modifier ":Z"
while evaluating "${:U3:Z} 4" with value "3"
make: Fatal errors encountered -- cannot continue
diff --git a/contrib/bmake/unit-tests/directive-for-errors.mk b/contrib/bmake/unit-tests/directive-for-errors.mk
index a58b8294289b..2571b600bf38 100644
--- a/contrib/bmake/unit-tests/directive-for-errors.mk
+++ b/contrib/bmake/unit-tests/directive-for-errors.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for-errors.mk,v 1.17 2025/05/03 08:18:33 rillig Exp $
+# $NetBSD: directive-for-errors.mk,v 1.18 2025/06/28 22:39:28 rillig Exp $
#
# Tests for error handling in .for loops.
@@ -40,7 +40,7 @@
# error everywhere outside a .for loop.
${:U\$}= dollar # see whether the "variable" '$' is local
${:U\\}= backslash # see whether the "variable" '\' is local
-# expect+1: invalid character '$' in .for loop variable name
+# expect+1: Invalid character "$" in .for loop variable name
.for a b $ \ in 1 2 3 4
. info Dollar $$ ${$} $($) and backslash $\ ${\} $(\).
.endfor
@@ -48,7 +48,7 @@ ${:U\\}= backslash # see whether the "variable" '\' is local
# If there are no variables, there is no point in expanding the .for loop
# since this would end up in an endless loop, consuming 0 of the 3 values in
# each iteration.
-# expect+1: no iteration variables in for
+# expect+1: Missing iteration variables in .for loop
.for in 1 2 3
# XXX: This should not be reached. It should be skipped, as already done
# when the number of values is not a multiple of the number of variables,
@@ -74,7 +74,7 @@ ${:U\\}= backslash # see whether the "variable" '\' is local
# A missing 'in' parses the .for loop but skips the body.
-# expect+1: missing `in' in for
+# expect+1: Missing "in" in .for loop
.for i over k
. error
.endfor
diff --git a/contrib/bmake/unit-tests/directive-for-escape.exp b/contrib/bmake/unit-tests/directive-for-escape.exp
index 6ab8a333a10f..78cc57a738a2 100644
--- a/contrib/bmake/unit-tests/directive-for-escape.exp
+++ b/contrib/bmake/unit-tests/directive-for-escape.exp
@@ -1,14 +1,14 @@
For: end for 1
For: loop body with chars = !"#$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~:
. info ${:U!"#$%&'()*+,-./0-9\:;<=>?@A-Z[\\]_^a-z{|\}~}
-make: directive-for-escape.mk:21: Unclosed expression, expecting '}' for modifier "U!""
+make: directive-for-escape.mk:21: Unclosed expression, expecting "}" for modifier "U!""
while evaluating "${:U!"" with value "!""
in .for loop from directive-for-escape.mk:20 with chars = !"#$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
make: directive-for-escape.mk:21: !"
For: end for 1
For: loop body with chars = !"\\#$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~:
. info ${:U!"\\\\#$%&'()*+,-./0-9\:;<=>?@A-Z[\\]_^a-z{|\}~}
-make: directive-for-escape.mk:33: Unclosed expression, expecting '}' for modifier "U!"\\\\"
+make: directive-for-escape.mk:33: Unclosed expression, expecting "}" for modifier "U!"\\\\"
while evaluating "${:U!"\\\\" with value "!"\\"
in .for loop from directive-for-escape.mk:32 with chars = !"\\#$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
make: directive-for-escape.mk:33: !"\\
@@ -69,9 +69,9 @@ For: end for 1
For: loop body with i = $:
. info ${:U\$}
make: directive-for-escape.mk:147: $
-make: directive-for-escape.mk:155: invalid character ':' in .for loop variable name
+make: directive-for-escape.mk:155: Invalid character ":" in .for loop variable name
For: end for 1
-make: directive-for-escape.mk:165: invalid character '}' in .for loop variable name
+make: directive-for-escape.mk:165: Invalid character "}" in .for loop variable name
For: end for 1
For: end for 1
For: loop body with i = inner:
@@ -89,7 +89,7 @@ For: end for 1
For: loop body with i = inner:
. info ${i2} ${i,} ${:Uinner}${:Uinner}${:Uinner:M*}${:Uinner}
make: directive-for-escape.mk:187: two comma innerinnerinnerinner
-make: directive-for-escape.mk:196: invalid character '$' in .for loop variable name
+make: directive-for-escape.mk:196: Invalid character "$" in .for loop variable name
For: end for 1
make: directive-for-escape.mk:208: eight and no cents.
For: end for 1
diff --git a/contrib/bmake/unit-tests/directive-for-escape.mk b/contrib/bmake/unit-tests/directive-for-escape.mk
index e688ce98f258..913d61831c46 100644
--- a/contrib/bmake/unit-tests/directive-for-escape.mk
+++ b/contrib/bmake/unit-tests/directive-for-escape.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for-escape.mk,v 1.29 2024/08/29 20:20:36 rillig Exp $
+# $NetBSD: directive-for-escape.mk,v 1.30 2025/06/28 22:39:28 rillig Exp $
#
# Test escaping of special characters in the iteration values of a .for loop.
# These values get expanded later using the :U variable modifier, and this
@@ -15,7 +15,7 @@ ASCII= !"\#$$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
# XXX: As of 2020-12-31, the '#' is not preserved in the expanded body of
# the loop. Not only would it need the escaping for the variable modifier
# ':U' but also the escaping for the line-end comment.
-# expect+3: Unclosed expression, expecting '}' for modifier "U!""
+# expect+3: Unclosed expression, expecting "}" for modifier "U!""
# expect+2: !"
.for chars in ${ASCII}
. info ${chars}
@@ -27,7 +27,7 @@ ASCII= !"\#$$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
# This means that a '#' sign cannot be passed in the value of a .for loop
# at all.
ASCII.2020-12-31= !"\\\#$$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
-# expect+3: Unclosed expression, expecting '}' for modifier "U!"\\\\"
+# expect+3: Unclosed expression, expecting "}" for modifier "U!"\\\\"
# expect+2: !"\\
.for chars in ${ASCII.2020-12-31}
. info ${chars}
@@ -151,7 +151,7 @@ VALUES= begin<$${UNDEF:Ufallback:N{{{}}}}>end
# could contain colons, which affected expressions having this exact
# modifier. This possibility was neither intended nor documented.
NUMBERS= one two three
-# expect+1: invalid character ':' in .for loop variable name
+# expect+1: Invalid character ":" in .for loop variable name
.for NUMBERS:M*e in replaced
. info ${NUMBERS} ${NUMBERS:M*e}
.endfor
@@ -161,7 +161,7 @@ NUMBERS= one two three
# expressions. This possibility was neither intended nor documented.
BASENAME= one
EXT= .c
-# expect+1: invalid character '}' in .for loop variable name
+# expect+1: Invalid character "}" in .for loop variable name
.for BASENAME}${EXT in replaced
. info ${BASENAME}${EXT}
.endfor
@@ -192,7 +192,7 @@ i,= comma
# skipped "stupid" variable names though, but ForLoop_SubstVarLong naively
# parsed the body of the loop, substituting each '${$}' with an actual
# '${:Udollar}'.
-# expect+1: invalid character '$' in .for loop variable name
+# expect+1: Invalid character "$" in .for loop variable name
.for $ in dollar
. info eight $$$$$$$$ and no cents.
. info eight ${$}${$}${$}${$} and no cents.
diff --git a/contrib/bmake/unit-tests/directive-for-lines.exp b/contrib/bmake/unit-tests/directive-for-lines.exp
index bf5b2b8b1209..23227122ffd3 100644
--- a/contrib/bmake/unit-tests/directive-for-lines.exp
+++ b/contrib/bmake/unit-tests/directive-for-lines.exp
@@ -1,9 +1,9 @@
-make: directive-for-lines.mk:27: expect 23
-make: directive-for-lines.mk:27: expect 23
-make: directive-for-lines.mk:36: expect 30
-make: directive-for-lines.mk:27: expect 23
-make: directive-for-lines.mk:27: expect 23
-make: directive-for-lines.mk:36: expect 30
+make: directive-for-lines.mk:31: This is line 31.
+make: directive-for-lines.mk:31: This is line 31.
+make: directive-for-lines.mk:38: This is line 38.
+make: directive-for-lines.mk:31: This is line 31.
+make: directive-for-lines.mk:31: This is line 31.
+make: directive-for-lines.mk:38: This is line 38.
make: no target to make.
make: stopped in unit-tests
diff --git a/contrib/bmake/unit-tests/directive-for-lines.mk b/contrib/bmake/unit-tests/directive-for-lines.mk
index cae4e0a38897..898a1960e76a 100644
--- a/contrib/bmake/unit-tests/directive-for-lines.mk
+++ b/contrib/bmake/unit-tests/directive-for-lines.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for-lines.mk,v 1.5 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: directive-for-lines.mk,v 1.6 2025/06/30 21:44:39 rillig Exp $
#
# Tests for the line numbers that are reported in .for loops.
#
@@ -7,6 +7,14 @@
# messages inside .for loops had been wrong since ParseGetLine skipped empty
# lines, even when collecting the lines for the .for loop body.
+# expect+21: This is line 31.
+# expect+20: This is line 31.
+# expect+26: This is line 38.
+
+# expect+17: This is line 31.
+# expect+16: This is line 31.
+# expect+22: This is line 38.
+
.for outer in a b
# comment \
@@ -20,19 +28,13 @@
VAR= \
multi-line
-# expect+4: expect 23
-# expect+3: expect 23
-# expect+2: expect 23
-# expect+1: expect 23
-.info expect 23
+.info This is line 31.
.endfor
# comment \
# continued comment
-# expect+2: expect 30
-# expect+1: expect 30
-.info expect 30
+.info This is line 38.
.endfor
diff --git a/contrib/bmake/unit-tests/directive-for.exp b/contrib/bmake/unit-tests/directive-for.exp
index cf87e6ea8569..d1c1064f0ef5 100755
--- a/contrib/bmake/unit-tests/directive-for.exp
+++ b/contrib/bmake/unit-tests/directive-for.exp
@@ -14,16 +14,16 @@ make: directive-for.mk:158: {{}} {{}} {{}}
make: directive-for.mk:158: )( )( )(
make: directive-for.mk:158: ][ ][ ][
make: directive-for.mk:158: }{ }{ }{
-make: directive-for.mk:166: invalid character ':' in .for loop variable name
-make: directive-for.mk:173: invalid character '$' in .for loop variable name
-make: directive-for.mk:185: invalid character '$' in .for loop variable name
-make: directive-for.mk:207: no iteration variables in for
-make: directive-for.mk:233: 1 open conditional
- in .for loop from directive-for.mk:231 with var = value
-make: directive-for.mk:249: for-less endfor
-make: directive-for.mk:250: if-less endif
-make: directive-for.mk:258: if-less endif
- in .for loop from directive-for.mk:257 with var = value
+make: directive-for.mk:166: Invalid character ":" in .for loop variable name
+make: directive-for.mk:173: Invalid character "$" in .for loop variable name
+make: directive-for.mk:185: Invalid character "$" in .for loop variable name
+make: directive-for.mk:208: Missing iteration variables in .for loop
+make: directive-for.mk:234: 1 open conditional
+ in .for loop from directive-for.mk:232 with var = value
+make: directive-for.mk:252: for-less endfor
+make: directive-for.mk:254: if-less endif
+make: directive-for.mk:263: if-less endif
+ in .for loop from directive-for.mk:261 with var = value
For: new loop 2
For: end for 2
For: end for 1
@@ -34,7 +34,7 @@ For: loop body with outer = o:
endfor
For: end for 1
For: loop body with inner = i:
-make: directive-for.mk:307: newline-item=(a)
+make: directive-for.mk:312: newline-item=(a)
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/directive-for.mk b/contrib/bmake/unit-tests/directive-for.mk
index 2f989f54f228..72ffaa142ad6 100755
--- a/contrib/bmake/unit-tests/directive-for.mk
+++ b/contrib/bmake/unit-tests/directive-for.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for.mk,v 1.30 2025/03/30 16:43:10 rillig Exp $
+# $NetBSD: directive-for.mk,v 1.32 2025/07/01 04:24:20 rillig Exp $
#
# Tests for the .for directive.
#
@@ -162,14 +162,14 @@ EXPANSION${plus}= value
# except for whitespace, allowing for creative side effects, as usual for
# arbitrary code injection.
var= outer
-# expect+1: invalid character ':' in .for loop variable name
+# expect+1: Invalid character ":" in .for loop variable name
.for var:Q in value "quoted"
. info <${var}> <${var:Q}> <${var:Q:Q}>
.endfor
# Before 2023-05-09, when variable names could contain '$', the short
# expression '$$' was preserved, the long expressions were substituted.
-# expect+1: invalid character '$' in .for loop variable name
+# expect+1: Invalid character "$" in .for loop variable name
.for $ in value
. info <$$> <${$}> <$($)>
.endfor
@@ -181,7 +181,7 @@ var= outer
# possibility, therefore the variable names are restricted to using harmless
# characters only.
INDIRECT= direct
-# expect+1: invalid character '$' in .for loop variable name
+# expect+1: Invalid character "$" in .for loop variable name
.for $(INDIRECT) in value
# If the variable name could be chosen dynamically, the iteration variable
# might have been 'direct', thereby expanding the expression '${direct}'.
@@ -204,7 +204,8 @@ INDIRECT= ${DIRECT}
# An empty list of variables to the left of the 'in' is a parse error.
-.for in value # expect+0: no iteration variables in for
+# expect+1: Missing iteration variables in .for loop
+.for in value
. error
.endfor
@@ -230,7 +231,8 @@ INDIRECT= ${DIRECT}
# is processed.
.for var in value
. if 0
-.endfor # expect+0: 1 open conditional
+.endfor
+# expect-1: 1 open conditional
# If there are no iteration values, the loop body is not processed, and the
# check for mismatched conditionals is not performed.
@@ -246,8 +248,10 @@ INDIRECT= ${DIRECT}
.if 0
. for var in value # does not need a corresponding .endfor
.endif
-.endfor # expect+0: for-less endfor
-.endif # expect+0: if-less endif
+# expect+1: for-less endfor
+.endfor
+# expect+1: if-less endif
+.endif
# When a .for without the corresponding .endfor occurs in an active branch of
@@ -255,7 +259,8 @@ INDIRECT= ${DIRECT}
# without looking at any other directives.
.if 1
. for var in value
-. endif # expect+0: if-less endif
+# expect+1: if-less endif
+. endif
. endfor # no 'for-less endfor'
.endif # no 'if-less endif'
diff --git a/contrib/bmake/unit-tests/directive-hyphen-include.exp b/contrib/bmake/unit-tests/directive-hyphen-include.exp
index 3f17f0c41f0b..d1d37e783ca9 100755
--- a/contrib/bmake/unit-tests/directive-hyphen-include.exp
+++ b/contrib/bmake/unit-tests/directive-hyphen-include.exp
@@ -1,4 +1,4 @@
-make: directive-hyphen-include-error.inc:1: Invalid line 'syntax error'
+make: directive-hyphen-include-error.inc:1: Invalid line "syntax error"
in directive-hyphen-include.mk:20
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
diff --git a/contrib/bmake/unit-tests/directive-hyphen-include.mk b/contrib/bmake/unit-tests/directive-hyphen-include.mk
index ad596f4c47db..de438dfaffac 100755
--- a/contrib/bmake/unit-tests/directive-hyphen-include.mk
+++ b/contrib/bmake/unit-tests/directive-hyphen-include.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-hyphen-include.mk,v 1.4 2025/03/30 09:51:50 rillig Exp $
+# $NetBSD: directive-hyphen-include.mk,v 1.5 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .-include directive, which includes another file,
# silently skipping it if it cannot be opened.
@@ -15,7 +15,7 @@
.-include "${MAKEFILE}/subdir"
# Errors that are not related to opening the file are still reported.
-# expect: make: directive-hyphen-include-error.inc:1: Invalid line 'syntax error'
+# expect: make: directive-hyphen-include-error.inc:1: Invalid line "syntax error"
_!= echo 'syntax error' > directive-hyphen-include-error.inc
.-include "${.CURDIR}/directive-hyphen-include-error.inc"
_!= rm directive-hyphen-include-error.inc
diff --git a/contrib/bmake/unit-tests/directive-if.exp b/contrib/bmake/unit-tests/directive-if.exp
index 0d4a7ea16d34..634c9ee6b1df 100644
--- a/contrib/bmake/unit-tests/directive-if.exp
+++ b/contrib/bmake/unit-tests/directive-if.exp
@@ -5,7 +5,7 @@ make: directive-if.mk:45: This is not conditional.
make: directive-if.mk:47: if-less else
make: directive-if.mk:49: This is not conditional.
make: directive-if.mk:51: if-less endif
-make: directive-if.mk:55: Malformed conditional ''
+make: directive-if.mk:55: Malformed conditional ""
make: directive-if.mk:66: Quotes in plain words are probably a mistake.
make: directive-if.mk:76: Don't do this, always put a space after a directive.
make: directive-if.mk:81: Don't do this, always put a space after a directive.
diff --git a/contrib/bmake/unit-tests/directive-if.mk b/contrib/bmake/unit-tests/directive-if.mk
index 7ff04da0755b..5d1232d245a9 100644
--- a/contrib/bmake/unit-tests/directive-if.mk
+++ b/contrib/bmake/unit-tests/directive-if.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-if.mk,v 1.13 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: directive-if.mk,v 1.14 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .if directive.
#
@@ -51,7 +51,7 @@
.endif
# Missing condition.
-# expect+1: Malformed conditional ''
+# expect+1: Malformed conditional ""
.if
. error
.else
diff --git a/contrib/bmake/unit-tests/directive-include.exp b/contrib/bmake/unit-tests/directive-include.exp
index 71f39c57e807..361389cf1cad 100755
--- a/contrib/bmake/unit-tests/directive-include.exp
+++ b/contrib/bmake/unit-tests/directive-include.exp
@@ -8,7 +8,7 @@ make: directive-include.mk:56: Unknown modifier ":Z"
while evaluating "${:U123:Z}.mk" with value "123"
make: directive-include.mk:56: Could not find nonexistent.mk
make: directive-include.mk:61: Cannot open /nonexistent
-make: directive-include.mk:66: Invalid line 'include'
+make: directive-include.mk:66: Invalid line "include"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/directive-include.mk b/contrib/bmake/unit-tests/directive-include.mk
index 42cdd97c43c7..ad6936ab2f3c 100755
--- a/contrib/bmake/unit-tests/directive-include.mk
+++ b/contrib/bmake/unit-tests/directive-include.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-include.mk,v 1.19 2025/03/30 09:51:50 rillig Exp $
+# $NetBSD: directive-include.mk,v 1.20 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .include directive, which includes another file.
@@ -62,7 +62,7 @@ include /nonexistent # comment
sinclude /nonexistent # comment
include ${:U/dev/null} # comment
include /dev/null /dev/null
-# expect+1: Invalid line 'include'
+# expect+1: Invalid line "include"
include
# XXX: trailing whitespace in diagnostic, missing quotes around filename
diff --git a/contrib/bmake/unit-tests/directive-misspellings.exp b/contrib/bmake/unit-tests/directive-misspellings.exp
index b918d05a2683..c551d73d5f98 100644
--- a/contrib/bmake/unit-tests/directive-misspellings.exp
+++ b/contrib/bmake/unit-tests/directive-misspellings.exp
@@ -1,6 +1,6 @@
make: directive-misspellings.mk:13: Unknown directive "dinclud"
make: directive-misspellings.mk:16: Unknown directive "dincludx"
-make: directive-misspellings.mk:18: .include filename must be delimited by '"' or '<'
+make: directive-misspellings.mk:18: .include filename must be delimited by "" or <>
make: directive-misspellings.mk:21: Unknown directive "erro"
make: directive-misspellings.mk:23: Unknown directive "errox"
make: directive-misspellings.mk:28: Unknown directive "expor"
@@ -13,18 +13,18 @@ make: directive-misspellings.mk:46: Unknown directive "export-literax"
make: directive-misspellings.mk:48: Unknown directive "export-literally"
make: directive-misspellings.mk:51: Unknown directive "-includ"
make: directive-misspellings.mk:54: Unknown directive "-includx"
-make: directive-misspellings.mk:56: .include filename must be delimited by '"' or '<'
+make: directive-misspellings.mk:56: .include filename must be delimited by "" or <>
make: directive-misspellings.mk:59: Unknown directive "includ"
make: directive-misspellings.mk:61: Could not find file
make: directive-misspellings.mk:63: Unknown directive "includx"
-make: directive-misspellings.mk:65: .include filename must be delimited by '"' or '<'
+make: directive-misspellings.mk:65: .include filename must be delimited by "" or <>
make: directive-misspellings.mk:68: Unknown directive "inf"
make: directive-misspellings.mk:70: msg
make: directive-misspellings.mk:72: Unknown directive "infx"
make: directive-misspellings.mk:74: Unknown directive "infos"
make: directive-misspellings.mk:77: Unknown directive "sinclud"
make: directive-misspellings.mk:80: Unknown directive "sincludx"
-make: directive-misspellings.mk:82: .include filename must be delimited by '"' or '<'
+make: directive-misspellings.mk:82: .include filename must be delimited by "" or <>
make: directive-misspellings.mk:85: Unknown directive "unde"
make: directive-misspellings.mk:88: Unknown directive "undex"
make: directive-misspellings.mk:90: Unknown directive "undefs"
diff --git a/contrib/bmake/unit-tests/directive-misspellings.mk b/contrib/bmake/unit-tests/directive-misspellings.mk
index 0014076d041f..cd6222b378f5 100644
--- a/contrib/bmake/unit-tests/directive-misspellings.mk
+++ b/contrib/bmake/unit-tests/directive-misspellings.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-misspellings.mk,v 1.4 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: directive-misspellings.mk,v 1.5 2025/06/28 22:39:28 rillig Exp $
#
# Tests for misspelled directives.
#
@@ -14,7 +14,7 @@
.dinclude "file"
# expect+1: Unknown directive "dincludx"
.dincludx "file"
-# expect+1: .include filename must be delimited by '"' or '<'
+# expect+1: .include filename must be delimited by "" or <>
.dincludes "file" # XXX: the 's' is not meant to be a filename
# expect+1: Unknown directive "erro"
@@ -52,7 +52,7 @@
.-include "file"
# expect+1: Unknown directive "-includx"
.-includx "file"
-# expect+1: .include filename must be delimited by '"' or '<'
+# expect+1: .include filename must be delimited by "" or <>
.-includes "file" # XXX: the 's' is not meant to be a filename
# expect+1: Unknown directive "includ"
@@ -61,7 +61,7 @@
.include "file"
# expect+1: Unknown directive "includx"
.includx "file"
-# expect+1: .include filename must be delimited by '"' or '<'
+# expect+1: .include filename must be delimited by "" or <>
.includex "file" # XXX: the 's' is not meant to be a filename
# expect+1: Unknown directive "inf"
@@ -78,7 +78,7 @@
.sinclude "file"
# expect+1: Unknown directive "sincludx"
.sincludx "file"
-# expect+1: .include filename must be delimited by '"' or '<'
+# expect+1: .include filename must be delimited by "" or <>
.sincludes "file" # XXX: the 's' is not meant to be a filename
# expect+1: Unknown directive "unde"
diff --git a/contrib/bmake/unit-tests/directive-sinclude.exp b/contrib/bmake/unit-tests/directive-sinclude.exp
index b7503e18c9b5..74db51227f07 100755
--- a/contrib/bmake/unit-tests/directive-sinclude.exp
+++ b/contrib/bmake/unit-tests/directive-sinclude.exp
@@ -1,4 +1,4 @@
-make: directive-include-error.inc:1: Invalid line 'syntax error'
+make: directive-include-error.inc:1: Invalid line "syntax error"
in directive-sinclude.mk:20
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
diff --git a/contrib/bmake/unit-tests/directive-sinclude.mk b/contrib/bmake/unit-tests/directive-sinclude.mk
index d40915fa86d5..4c856d22be4f 100755
--- a/contrib/bmake/unit-tests/directive-sinclude.mk
+++ b/contrib/bmake/unit-tests/directive-sinclude.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-sinclude.mk,v 1.6 2025/03/30 09:51:50 rillig Exp $
+# $NetBSD: directive-sinclude.mk,v 1.7 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .sinclude directive, which includes another file,
# silently skipping it if it cannot be opened.
@@ -15,7 +15,7 @@
.sinclude "${MAKEFILE}/subdir"
# Errors that are not related to opening the file are still reported.
-# expect: make: directive-include-error.inc:1: Invalid line 'syntax error'
+# expect: make: directive-include-error.inc:1: Invalid line "syntax error"
_!= echo 'syntax error' > directive-include-error.inc
.sinclude "${.CURDIR}/directive-include-error.inc"
_!= rm directive-include-error.inc
diff --git a/contrib/bmake/unit-tests/directive-unexport.exp b/contrib/bmake/unit-tests/directive-unexport.exp
index 1be4b03e3874..25bab7d7fd35 100644
--- a/contrib/bmake/unit-tests/directive-unexport.exp
+++ b/contrib/bmake/unit-tests/directive-unexport.exp
@@ -1,5 +1,5 @@
make: directive-unexport.mk:19: UT_A=a UT_B=b UT_C=c
make: directive-unexport.mk:21: UT_A UT_B UT_C
make: directive-unexport.mk:30: UT_A=a UT_B=b UT_C=c
-make: directive-unexport.mk:31:
+make: directive-unexport.mk:32:
exit status 0
diff --git a/contrib/bmake/unit-tests/directive-unexport.mk b/contrib/bmake/unit-tests/directive-unexport.mk
index e759fe3e35f2..3c10ffa07d6a 100644
--- a/contrib/bmake/unit-tests/directive-unexport.mk
+++ b/contrib/bmake/unit-tests/directive-unexport.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-unexport.mk,v 1.8 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: directive-unexport.mk,v 1.9 2025/06/30 21:44:39 rillig Exp $
#
# Tests for the .unexport directive.
#
@@ -28,6 +28,7 @@ UT_C= c
# expect+1: UT_A=a UT_B=b UT_C=c
.info ${:!env|sort|grep '^UT_'!}
+# expect+1:
.info ${.MAKE.EXPORTED}
.unexport # oops: missing argument
diff --git a/contrib/bmake/unit-tests/directive-warning.exp b/contrib/bmake/unit-tests/directive-warning.exp
index 2dd4e8ceb7f9..250e32583847 100644
--- a/contrib/bmake/unit-tests/directive-warning.exp
+++ b/contrib/bmake/unit-tests/directive-warning.exp
@@ -3,9 +3,9 @@ make: directive-warning.mk:12: Unknown directive "warn"
make: directive-warning.mk:14: Unknown directive "warnin"
make: directive-warning.mk:16: Unknown directive "warnin"
make: directive-warning.mk:18: Missing argument for ".warning"
-make: directive-warning.mk:19: warning: message
-make: directive-warning.mk:21: Unknown directive "warnings"
-make: directive-warning.mk:23: Unknown directive "warnings"
+make: directive-warning.mk:20: warning: message
+make: directive-warning.mk:22: Unknown directive "warnings"
+make: directive-warning.mk:24: Unknown directive "warnings"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/directive-warning.mk b/contrib/bmake/unit-tests/directive-warning.mk
index bf0683f8911f..50666487c13f 100644
--- a/contrib/bmake/unit-tests/directive-warning.mk
+++ b/contrib/bmake/unit-tests/directive-warning.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-warning.mk,v 1.9 2023/12/17 09:44:00 rillig Exp $
+# $NetBSD: directive-warning.mk,v 1.10 2025/07/01 04:24:20 rillig Exp $
#
# Tests for the .warning directive.
#
@@ -16,7 +16,8 @@
.warnin message # misspelled
# expect+1: Missing argument for ".warning"
.warning # "Missing argument"
-.warning message # expect+0: warning: message
+# expect+1: warning: message
+.warning message
# expect+1: Unknown directive "warnings"
.warnings # misspelled
# expect+1: Unknown directive "warnings"
diff --git a/contrib/bmake/unit-tests/directive.exp b/contrib/bmake/unit-tests/directive.exp
index 2f1da18cdbb5..dce759abfe52 100644
--- a/contrib/bmake/unit-tests/directive.exp
+++ b/contrib/bmake/unit-tests/directive.exp
@@ -7,8 +7,8 @@ Global: .info = value
make: directive.mk:31: := value
Global: .MAKEFLAGS = -r -k -d v -d
Global: .MAKEFLAGS = -r -k -d v -d 0
-make: directive.mk:40: Invalid line 'target-without-colon'
-make: directive.mk:43: Invalid line 'target-without-colon another-target'
+make: directive.mk:40: Invalid line "target-without-colon"
+make: directive.mk:43: Invalid line "target-without-colon another-target"
make: Fatal errors encountered -- cannot continue
make: stopped making ".target" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/directive.mk b/contrib/bmake/unit-tests/directive.mk
index 61938360dfc7..5f5be5aa0fab 100644
--- a/contrib/bmake/unit-tests/directive.mk
+++ b/contrib/bmake/unit-tests/directive.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive.mk,v 1.9 2023/11/19 22:32:44 rillig Exp $
+# $NetBSD: directive.mk,v 1.10 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the preprocessing directives, such as .if or .info.
@@ -36,8 +36,8 @@
# Not even the space after the '.info' can change anything about this.
.${:Uinfo} : source
-# expect+1: Invalid line 'target-without-colon'
+# expect+1: Invalid line "target-without-colon"
target-without-colon
-# expect+1: Invalid line 'target-without-colon another-target'
+# expect+1: Invalid line "target-without-colon another-target"
target-without-colon another-target
diff --git a/contrib/bmake/unit-tests/moderrs.exp b/contrib/bmake/unit-tests/moderrs.exp
index 08aa2582f6be..4758294f0993 100644
--- a/contrib/bmake/unit-tests/moderrs.exp
+++ b/contrib/bmake/unit-tests/moderrs.exp
@@ -7,11 +7,11 @@ make: Unknown modifier ":Z"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 'VAR:${MOD_UNKN}=before-${VAR:${MOD_UNKN}:inner}-after'"
in target "mod-unknown-indirect"
-make: Unclosed expression, expecting '}' for modifier "S,V,v,"
+make: Unclosed expression, expecting "}" for modifier "S,V,v,"
while evaluating variable "VAR" with value "Thevariable"
in command "@echo VAR:S,V,v,=${VAR:S,V,v,"
in target "unclosed-direct"
-make: Unclosed expression after indirect modifier, expecting '}'
+make: Unclosed expression after indirect modifier, expecting "}"
while evaluating variable "VAR" with value "Thevariable"
in command "@echo VAR:${MOD_TERM},=${VAR:${MOD_S}"
in target "unclosed-indirect"
@@ -29,7 +29,7 @@ make: Unfinished modifier after "...}", expecting "@"
in command "@echo ${UNDEF:U1 2 3:@var@...}"
in target "unfinished-loop-2"
1 2 3
-make: Unclosed expression, expecting '}' for modifier "@var@${var}}...@"
+make: Unclosed expression, expecting "}" for modifier "@var@${var}}...@"
while evaluating variable "UNDEF" with value "1}... 2}... 3}..."
in command "@echo ${UNDEF:U1 2 3:@var@${var}}...@"
in target "loop-close-1"
@@ -55,7 +55,7 @@ make: Unfinished modifier after "=exclam}", expecting "!"
while evaluating variable "!" with value "!"
in command "@echo ${!:L:!=exclam}"
in target "exclam-2"
-make: Missing delimiter for modifier ':S'
+make: Missing delimiter for modifier ":S"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 1: ${VAR:S"
in target "mod-subst-delimiter-1"
@@ -75,12 +75,12 @@ make: Unfinished modifier after "to", expecting ","
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 5: ${VAR:S,from,to"
in target "mod-subst-delimiter-5"
-make: Unclosed expression, expecting '}' for modifier "S,from,to,"
+make: Unclosed expression, expecting "}" for modifier "S,from,to,"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 6: ${VAR:S,from,to,"
in target "mod-subst-delimiter-6"
7: TheVariable
-make: Missing delimiter for modifier ':C'
+make: Missing delimiter for modifier ":C"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 1: ${VAR:C"
in target "mod-regex-delimiter-1"
@@ -100,7 +100,7 @@ make: Unfinished modifier after "to", expecting ","
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 5: ${VAR:C,from,to"
in target "mod-regex-delimiter-5"
-make: Unclosed expression, expecting '}' for modifier "C,from,to,"
+make: Unclosed expression, expecting "}" for modifier "C,from,to,"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 6: ${VAR:C,from,to,"
in target "mod-regex-delimiter-6"
diff --git a/contrib/bmake/unit-tests/moderrs.mk b/contrib/bmake/unit-tests/moderrs.mk
index ca5cc082e6b8..c2ee320e2df2 100644
--- a/contrib/bmake/unit-tests/moderrs.mk
+++ b/contrib/bmake/unit-tests/moderrs.mk
@@ -1,4 +1,4 @@
-# $NetBSD: moderrs.mk,v 1.46 2025/03/30 00:35:52 rillig Exp $
+# $NetBSD: moderrs.mk,v 1.47 2025/06/28 22:39:29 rillig Exp $
#
# various modifier error tests
@@ -33,11 +33,11 @@ mod-unknown-indirect:
@echo 'VAR:${MOD_UNKN}=before-${VAR:${MOD_UNKN}:inner}-after'
unclosed-direct:
-# expect: make: Unclosed expression, expecting '}' for modifier "S,V,v,"
+# expect: make: Unclosed expression, expecting "}" for modifier "S,V,v,"
@echo VAR:S,V,v,=${VAR:S,V,v,
unclosed-indirect:
-# expect: make: Unclosed expression after indirect modifier, expecting '}'
+# expect: make: Unclosed expression after indirect modifier, expecting "}"
@echo VAR:${MOD_TERM},=${VAR:${MOD_S}
unfinished-indirect:
@@ -60,7 +60,7 @@ unfinished-loop-3:
# This is also contrary to the SysV modifier, where only the actually
# used delimiter (either braces or parentheses) must be balanced.
loop-close-1:
-# expect: make: Unclosed expression, expecting '}' for modifier "@var@${var}}...@"
+# expect: make: Unclosed expression, expecting "}" for modifier "@var@${var}}...@"
@echo ${UNDEF:U1 2 3:@var@${var}}...@
loop-close-2:
@echo ${UNDEF:U1 2 3:@var@${var}}...@}
@@ -107,7 +107,7 @@ exclam-2:
@echo ${!:L:!=exclam}
mod-subst-delimiter-1:
-# expect: make: Missing delimiter for modifier ':S'
+# expect: make: Missing delimiter for modifier ":S"
@echo 1: ${VAR:S
mod-subst-delimiter-2:
# expect: make: Unfinished modifier after "", expecting ","
@@ -122,13 +122,13 @@ mod-subst-delimiter-5:
# expect: make: Unfinished modifier after "to", expecting ","
@echo 5: ${VAR:S,from,to
mod-subst-delimiter-6:
-# expect: make: Unclosed expression, expecting '}' for modifier "S,from,to,"
+# expect: make: Unclosed expression, expecting "}" for modifier "S,from,to,"
@echo 6: ${VAR:S,from,to,
mod-subst-delimiter-7:
@echo 7: ${VAR:S,from,to,}
mod-regex-delimiter-1:
-# expect: make: Missing delimiter for modifier ':C'
+# expect: make: Missing delimiter for modifier ":C"
@echo 1: ${VAR:C
mod-regex-delimiter-2:
# expect: make: Unfinished modifier after "", expecting ","
@@ -143,7 +143,7 @@ mod-regex-delimiter-5:
# expect: make: Unfinished modifier after "to", expecting ","
@echo 5: ${VAR:C,from,to
mod-regex-delimiter-6:
-# expect: make: Unclosed expression, expecting '}' for modifier "C,from,to,"
+# expect: make: Unclosed expression, expecting "}" for modifier "C,from,to,"
@echo 6: ${VAR:C,from,to,
mod-regex-delimiter-7:
@echo 7: ${VAR:C,from,to,}
diff --git a/contrib/bmake/unit-tests/opt-debug-file.exp b/contrib/bmake/unit-tests/opt-debug-file.exp
index 1059351188e4..4a497f3011d9 100644
--- a/contrib/bmake/unit-tests/opt-debug-file.exp
+++ b/contrib/bmake/unit-tests/opt-debug-file.exp
@@ -1,6 +1,6 @@
-make: opt-debug-file.mk:44: This goes to stderr only, once.
-make: opt-debug-file.mk:47: This goes to stderr only, once.
-make: opt-debug-file.mk:50: This goes to stderr, and in addition to the debug log.
+make: opt-debug-file.mk:54: This goes to stderr only, once.
+make: opt-debug-file.mk:57: This goes to stderr only, once.
+make: opt-debug-file.mk:60: This goes to stderr, and in addition to the debug log.
CondParser_Eval: ${:!cat opt-debug-file.debuglog!:Maddition:[#]} != 1
Comparing 1.000000 != 1.000000
make: Unterminated quoted string [make 'This goes to stdout only, once.]
diff --git a/contrib/bmake/unit-tests/opt-debug-file.mk b/contrib/bmake/unit-tests/opt-debug-file.mk
index 33a35e0a458a..d107f177dae3 100644
--- a/contrib/bmake/unit-tests/opt-debug-file.mk
+++ b/contrib/bmake/unit-tests/opt-debug-file.mk
@@ -1,4 +1,4 @@
-# $NetBSD: opt-debug-file.mk,v 1.11 2024/06/30 15:21:24 rillig Exp $
+# $NetBSD: opt-debug-file.mk,v 1.12 2025/07/06 08:48:34 rillig Exp $
#
# Tests for the -dF command line option, which redirects the debug log
# to a file instead of writing it to stderr.
@@ -27,7 +27,9 @@ DEBUG_OUTPUT:= ${:!cat opt-debug-file.debuglog!}
.endif
# To get the unexpanded text that was actually written to the debug log
-# file, the content of that log file must not be stored in a variable.
+# file, the content of that log file must not be stored in a variable
+# directly. Instead, it can be processed in a single expression by a chain
+# of modifiers.
#
# XXX: In the :M modifier, a dollar is escaped using '$$', not '\$'. This
# escaping scheme unnecessarily differs from all other modifiers.
@@ -35,6 +37,14 @@ DEBUG_OUTPUT:= ${:!cat opt-debug-file.debuglog!}
. error
.endif
+# To get the unexpanded text that was actually written to the debug log
+# file, the content of that log file must not be stored in a variable
+# directly. Instead, each dollar sign must be escaped first.
+DEBUG_OUTPUT:= ${:!cat opt-debug-file.debuglog!:S,\$,\$\$,g}
+.if ${DEBUG_OUTPUT:M*Uexpanded*} != "\${:Uexpanded}"
+. error
+.endif
+
.MAKEFLAGS: -d0
diff --git a/contrib/bmake/unit-tests/opt-debug-lint.exp b/contrib/bmake/unit-tests/opt-debug-lint.exp
index 8e7339fcd2e9..7173ec476ec5 100644
--- a/contrib/bmake/unit-tests/opt-debug-lint.exp
+++ b/contrib/bmake/unit-tests/opt-debug-lint.exp
@@ -1,8 +1,8 @@
make: opt-debug-lint.mk:20: Variable "X" is undefined
make: opt-debug-lint.mk:43: Variable "UNDEF" is undefined
-make: opt-debug-lint.mk:65: Missing delimiter ':' after modifier "L"
+make: opt-debug-lint.mk:65: Missing delimiter ":" after modifier "L"
while evaluating variable "value" with value "value"
-make: opt-debug-lint.mk:65: Missing delimiter ':' after modifier "P"
+make: opt-debug-lint.mk:65: Missing delimiter ":" after modifier "P"
while evaluating variable "value" with value "value"
make: opt-debug-lint.mk:74: Unknown modifier ":${"
while evaluating variable "value" with value ""
diff --git a/contrib/bmake/unit-tests/opt-debug-lint.mk b/contrib/bmake/unit-tests/opt-debug-lint.mk
index 59cd36fb05e9..2f73c9bf645c 100644
--- a/contrib/bmake/unit-tests/opt-debug-lint.mk
+++ b/contrib/bmake/unit-tests/opt-debug-lint.mk
@@ -1,4 +1,4 @@
-# $NetBSD: opt-debug-lint.mk,v 1.24 2025/04/04 18:57:01 rillig Exp $
+# $NetBSD: opt-debug-lint.mk,v 1.25 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the -dL command line option, which runs additional checks
# to catch common mistakes, such as unclosed expressions.
@@ -60,8 +60,8 @@ ${UNDEF}: ${UNDEF}
# Since 2020-10-03, in lint mode the variable modifier must be separated
# by colons. See varparse-mod.mk.
-# expect+2: Missing delimiter ':' after modifier "L"
-# expect+1: Missing delimiter ':' after modifier "P"
+# expect+2: Missing delimiter ":" after modifier "L"
+# expect+1: Missing delimiter ":" after modifier "P"
.if ${value:LPL} != "value"
. error
.endif
diff --git a/contrib/bmake/unit-tests/opt-jobs-internal.exp b/contrib/bmake/unit-tests/opt-jobs-internal.exp
index e3e8ee498224..61c96256a2e4 100644
--- a/contrib/bmake/unit-tests/opt-jobs-internal.exp
+++ b/contrib/bmake/unit-tests/opt-jobs-internal.exp
@@ -1,25 +1,13 @@
direct: mode=parallel
make: error: invalid internal option "-J garbage" in "<curdir>"
-make: warning: internal option "-J" in "<curdir>" refers to unopened file descriptors; falling back to compat mode.
- To run the target even in -n mode, add the .MAKE pseudo-source to the target.
- To run the target in default mode only, add a ${:D make} marker to a target's command. (This marker expression expands to an empty string.)
- To make the sub-make run in compat mode, add -B to its invocation.
- To make the sub-make independent from the parent make, unset the MAKEFLAGS environment variable in the target's commands.
+make: warning: Invalid internal option "-J" in "<curdir>"; see the manual page
in make[2] in directory "<curdir>"
direct-open: mode=compat
-make: warning: internal option "-J" in "<curdir>" refers to unopened file descriptors; falling back to compat mode.
- To run the target even in -n mode, add the .MAKE pseudo-source to the target.
- To run the target in default mode only, add a ${:D make} marker to a target's command. (This marker expression expands to an empty string.)
- To make the sub-make run in compat mode, add -B to its invocation.
- To make the sub-make independent from the parent make, unset the MAKEFLAGS environment variable in the target's commands.
+make: warning: Invalid internal option "-J" in "<curdir>"; see the manual page
in make[2] in directory "<curdir>"
indirect-open: mode=compat
indirect-expr: mode=parallel
-make: warning: internal option "-J" in "<curdir>" refers to unopened file descriptors; falling back to compat mode.
- To run the target even in -n mode, add the .MAKE pseudo-source to the target.
- To run the target in default mode only, add a ${:D make} marker to a target's command. (This marker expression expands to an empty string.)
- To make the sub-make run in compat mode, add -B to its invocation.
- To make the sub-make independent from the parent make, unset the MAKEFLAGS environment variable in the target's commands.
+make: warning: Invalid internal option "-J" in "<curdir>"; see the manual page
in make[2] in directory "<curdir>"
indirect-comment: mode=compat
indirect-silent-comment: mode=parallel
diff --git a/contrib/bmake/unit-tests/parse.exp b/contrib/bmake/unit-tests/parse.exp
index 86d12effb5c7..4f97a9350550 100644
--- a/contrib/bmake/unit-tests/parse.exp
+++ b/contrib/bmake/unit-tests/parse.exp
@@ -1,6 +1,6 @@
-make: parse.mk:7: Invalid line '<<<<<< old'
-make: parse.mk:14: Invalid line '>>>>>> new'
-make: parse.mk:25: Invalid line 'one-target ${:U }', expanded to 'one-target '
+make: parse.mk:7: Invalid line "<<<<<< old"
+make: parse.mk:14: Invalid line ">>>>>> new"
+make: parse.mk:25: Invalid line "one-target ${:U }", expanded to "one-target "
make: Fatal errors encountered -- cannot continue
make: stopped making "Try_to_crash_FreeBSD.xxxxxxxxxxxxxxxxxx" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/parse.mk b/contrib/bmake/unit-tests/parse.mk
index 80a51f2de11e..fb959a4a5e1b 100644
--- a/contrib/bmake/unit-tests/parse.mk
+++ b/contrib/bmake/unit-tests/parse.mk
@@ -1,16 +1,16 @@
-# $NetBSD: parse.mk,v 1.7 2023/08/19 11:09:02 rillig Exp $
+# $NetBSD: parse.mk,v 1.8 2025/06/28 22:39:29 rillig Exp $
#
# Test those parts of the parsing that do not belong in any of the other
# categories.
-# expect+1: Invalid line '<<<<<< old'
+# expect+1: Invalid line "<<<<<< old"
<<<<<< old
# No diagnostic since the following line is parsed as a variable assignment,
# even though the variable name is empty. See also varname-empty.mk.
====== middle
-# expect+1: Invalid line '>>>>>> new'
+# expect+1: Invalid line ">>>>>> new"
>>>>>> new
@@ -21,7 +21,7 @@
# the expanded line's terminating '\0'.
#
# https://bugs.freebsd.org/265119
-# expect+1: Invalid line 'one-target ${:U }', expanded to 'one-target '
+# expect+1: Invalid line "one-target ${:U }", expanded to "one-target "
one-target ${:U }
diff --git a/contrib/bmake/unit-tests/var-op-assign.exp b/contrib/bmake/unit-tests/var-op-assign.exp
index 4e287e518eb7..83459de4184d 100644
--- a/contrib/bmake/unit-tests/var-op-assign.exp
+++ b/contrib/bmake/unit-tests/var-op-assign.exp
@@ -1,5 +1,5 @@
this will be evaluated later
-make: var-op-assign.mk:60: Invalid line 'VARIABLE NAME= variable value'
+make: var-op-assign.mk:60: Invalid line "VARIABLE NAME= variable value"
make: var-op-assign.mk:95: Parsing still continues until here.
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
diff --git a/contrib/bmake/unit-tests/var-op-assign.mk b/contrib/bmake/unit-tests/var-op-assign.mk
index a900c28a918d..a218dbfdac0a 100644
--- a/contrib/bmake/unit-tests/var-op-assign.mk
+++ b/contrib/bmake/unit-tests/var-op-assign.mk
@@ -1,4 +1,4 @@
-# $NetBSD: var-op-assign.mk,v 1.11 2023/11/19 21:47:52 rillig Exp $
+# $NetBSD: var-op-assign.mk,v 1.12 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the = variable assignment operator, which overwrites an existing
# variable or creates it.
@@ -56,7 +56,7 @@ VAR= ${:! echo 'this will be evaluated later' 1>&2 !}
# In a variable assignment, the variable name must consist of a single word.
# The following line therefore generates a parse error.
-# expect+1: Invalid line 'VARIABLE NAME= variable value'
+# expect+1: Invalid line "VARIABLE NAME= variable value"
VARIABLE NAME= variable value
# But if the whitespace appears inside parentheses or braces, everything is
diff --git a/contrib/bmake/unit-tests/var-op-expand.exp b/contrib/bmake/unit-tests/var-op-expand.exp
index 105d2f50acc8..5e2c3d1936d7 100644
--- a/contrib/bmake/unit-tests/var-op-expand.exp
+++ b/contrib/bmake/unit-tests/var-op-expand.exp
@@ -1,22 +1,20 @@
make: var-op-expand.mk:274: Unknown modifier ":s,value,replaced,"
while evaluating variable "later" with value ""
while evaluating variable "indirect" with value "${later:s,value,replaced,} ok ${later:value=sysv}"
-make: var-op-expand.mk:278: warning: XXX Neither branch should be taken.
-make: var-op-expand.mk:283: Unknown modifier ":s,value,replaced,"
+make: var-op-expand.mk:282: Unknown modifier ":s,value,replaced,"
while evaluating variable "later" with value "lowercase-value"
while evaluating variable "indirect" with value "${later:s,value,replaced,} ok ${later:value=sysv}"
-make: var-op-expand.mk:285: warning: XXX Neither branch should be taken.
-make: var-op-expand.mk:297: Bad condition
+make: var-op-expand.mk:295: Bad condition
while evaluating condition " < 0 "
-make: var-op-expand.mk:297: Unknown modifier ":Z1"
+make: var-op-expand.mk:295: Unknown modifier ":Z1"
while parsing "${:Z1}:${:Z2}}"
while evaluating then-branch of condition " < 0 "
-make: var-op-expand.mk:297: Unknown modifier ":Z2"
+make: var-op-expand.mk:295: Unknown modifier ":Z2"
while parsing "${:Z2}}"
while evaluating else-branch of condition " < 0 "
-make: var-op-expand.mk:297: Unknown modifier ":Z1"
+make: var-op-expand.mk:295: Unknown modifier ":Z1"
while evaluating "${:Z1}:${:Z2}}" with value ""
-make: var-op-expand.mk:297: Unknown modifier ":Z2"
+make: var-op-expand.mk:295: Unknown modifier ":Z2"
while evaluating "${:Z2}}" with value ""
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
diff --git a/contrib/bmake/unit-tests/var-op-expand.mk b/contrib/bmake/unit-tests/var-op-expand.mk
index 6a49648f0618..fb9e1713438b 100644
--- a/contrib/bmake/unit-tests/var-op-expand.mk
+++ b/contrib/bmake/unit-tests/var-op-expand.mk
@@ -1,4 +1,4 @@
-# $NetBSD: var-op-expand.mk,v 1.24 2025/04/30 06:01:07 rillig Exp $
+# $NetBSD: var-op-expand.mk,v 1.25 2025/06/29 11:27:21 rillig Exp $
#
# Tests for the := variable assignment operator, which expands its
# right-hand side.
@@ -274,15 +274,13 @@ indirect:= ${INDIRECT:tl}
.if ${indirect} != " ok "
. error
.else
-# expect+1: warning: XXX Neither branch should be taken.
-. warning XXX Neither branch should be taken.
+. error
.endif
LATER= uppercase-value
later= lowercase-value
# expect+1: Unknown modifier ":s,value,replaced,"
.if ${indirect} != "uppercase-replaced ok uppercase-sysv"
-# expect+1: warning: XXX Neither branch should be taken.
-. warning XXX Neither branch should be taken.
+. error
.else
. error
.endif
diff --git a/contrib/bmake/unit-tests/varmisc.exp b/contrib/bmake/unit-tests/varmisc.exp
index 509dbcc5e689..44b3c8e759cb 100644
--- a/contrib/bmake/unit-tests/varmisc.exp
+++ b/contrib/bmake/unit-tests/varmisc.exp
@@ -57,7 +57,7 @@ make: Unclosed variable "PATTERN"
while evaluating variable "UNCLOSED" with value ""
in command "@echo ${UNCLOSED:M${PATTERN"
in target "varerror-unclosed-5"
-make: Unclosed expression, expecting '}' for modifier "M${PATTERN"
+make: Unclosed expression, expecting "}" for modifier "M${PATTERN"
while evaluating variable "UNCLOSED" with value ""
in command "@echo ${UNCLOSED:M${PATTERN"
in target "varerror-unclosed-5"
diff --git a/contrib/bmake/unit-tests/varmisc.mk b/contrib/bmake/unit-tests/varmisc.mk
index b067742e9ac4..e36396633dc2 100644
--- a/contrib/bmake/unit-tests/varmisc.mk
+++ b/contrib/bmake/unit-tests/varmisc.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmisc.mk,v 1.37 2024/08/29 20:20:36 rillig Exp $
+# $NetBSD: varmisc.mk,v 1.38 2025/06/28 22:39:29 rillig Exp $
#
# Miscellaneous variable tests.
@@ -200,7 +200,7 @@ varerror-unclosed-4:
# expect: make: Unclosed variable "UNCLOSED"
@echo ${UNCLOSED
varerror-unclosed-5:
-# expect: make: Unclosed expression, expecting '}' for modifier "M${PATTERN"
+# expect: make: Unclosed expression, expecting "}" for modifier "M${PATTERN"
@echo ${UNCLOSED:M${PATTERN
varerror-unclosed-6:
# expect: make: Unclosed variable "param"
diff --git a/contrib/bmake/unit-tests/varmod-edge.exp b/contrib/bmake/unit-tests/varmod-edge.exp
index 2b41623bb66c..b80380fb702c 100644
--- a/contrib/bmake/unit-tests/varmod-edge.exp
+++ b/contrib/bmake/unit-tests/varmod-edge.exp
@@ -1,8 +1,8 @@
-make: varmod-edge.mk:60: Unclosed expression, expecting '}' for modifier "U*)"
+make: varmod-edge.mk:60: Unclosed expression, expecting "}" for modifier "U*)"
while evaluating "${:U*)" with value "*)"
while evaluating variable "INP" with value "(parentheses)"
while evaluating variable "MOD" with value "${INP:M${:U*)}}"
-make: varmod-edge.mk:88: Unfinished character list in pattern '[[' of modifier ':M'
+make: varmod-edge.mk:88: Unfinished character list in pattern "[[" of modifier ":M"
while evaluating variable "INP" with value "[ [[ [[["
while evaluating variable "MOD" with value "${INP:M${:U[[}}"
make: varmod-edge.mk:178: Unfinished modifier after "a\=b}", expecting "="
diff --git a/contrib/bmake/unit-tests/varmod-edge.mk b/contrib/bmake/unit-tests/varmod-edge.mk
index 473c7ad171e5..b5f879372afd 100644
--- a/contrib/bmake/unit-tests/varmod-edge.mk
+++ b/contrib/bmake/unit-tests/varmod-edge.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-edge.mk,v 1.36 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: varmod-edge.mk,v 1.37 2025/06/28 22:39:29 rillig Exp $
#
# Tests for edge cases in variable modifiers.
#
@@ -56,7 +56,7 @@ EXP= \(\{}\):
INP= (parentheses)
MOD= ${INP:M${:U*)}}
EXP= (parentheses)}
-# expect+1: Unclosed expression, expecting '}' for modifier "U*)"
+# expect+1: Unclosed expression, expecting "}" for modifier "U*)"
.if ${MOD} != ${EXP}
. warning expected "${EXP}", got "${MOD}"
.endif
@@ -84,7 +84,7 @@ EXP= [
INP= [ [[ [[[
MOD= ${INP:M${:U[[}}
EXP= [
-# expect+1: Unfinished character list in pattern '[[' of modifier ':M'
+# expect+1: Unfinished character list in pattern "[[" of modifier ":M"
.if ${MOD} != ${EXP}
. warning expected "${EXP}", got "${MOD}"
.endif
diff --git a/contrib/bmake/unit-tests/varmod-ifelse.exp b/contrib/bmake/unit-tests/varmod-ifelse.exp
index 039f0fd0b9a7..bf642c86fc8c 100644
--- a/contrib/bmake/unit-tests/varmod-ifelse.exp
+++ b/contrib/bmake/unit-tests/varmod-ifelse.exp
@@ -12,26 +12,25 @@ Comparing 1.000000 == 0.000000
make: varmod-ifelse.mk:94: Bad condition
while evaluating condition "1 == == 2"
Comparing "" != ""
-make: varmod-ifelse.mk:98: warning: Oops, the parse error should have been propagated.
CondParser_Eval: ${ ${:U\$}{VAR} == value:?ok:bad} != "ok"
CondParser_Eval: ${VAR} == value
Comparing "value" == "value"
Comparing "ok" != "ok"
-make: varmod-ifelse.mk:160: no.
-make: varmod-ifelse.mk:163: Comparison with '>=' requires both operands 'no' and '10' to be numeric
+make: varmod-ifelse.mk:159: no.
+make: varmod-ifelse.mk:162: Comparison with ">=" requires both operands "no" and "10" to be numeric
while evaluating condition "string == "literal" || no >= 10"
-make: varmod-ifelse.mk:163: .
-make: varmod-ifelse.mk:170: Bad condition
+make: varmod-ifelse.mk:162: .
+make: varmod-ifelse.mk:169: Bad condition
while evaluating condition "string == "literal" && >= 10"
-make: varmod-ifelse.mk:170: .
-make: varmod-ifelse.mk:173: Bad condition
+make: varmod-ifelse.mk:169: .
+make: varmod-ifelse.mk:172: Bad condition
while evaluating condition "string == "literal" || >= 10"
-make: varmod-ifelse.mk:173: .
-make: varmod-ifelse.mk:181: <true>
-make: varmod-ifelse.mk:184: <false>
-make: varmod-ifelse.mk:188: Bad condition
+make: varmod-ifelse.mk:172: .
+make: varmod-ifelse.mk:180: <true>
+make: varmod-ifelse.mk:183: <false>
+make: varmod-ifelse.mk:187: Bad condition
while evaluating condition " "
-make: varmod-ifelse.mk:188: <>
+make: varmod-ifelse.mk:187: <>
CondParser_Eval: 0 && ${1:?${:Uthen0:S,}},,}:${:Uelse0:S,}},,}} != "not evaluated"
CondParser_Eval: 1 && ${0:?${:Uthen1:S,}},,}:${:Uelse1:S,}},,}} != "else1"
CondParser_Eval: 0
@@ -41,31 +40,31 @@ CondParser_Eval: 1
Comparing "then2" != "then2"
CondParser_Eval: ${DELAYED} == "one"
Comparing "two" == "one"
-make: varmod-ifelse.mk:284: no
+make: varmod-ifelse.mk:283: no
CondParser_Eval: ${DELAYED} == "two"
Comparing "two" == "two"
-make: varmod-ifelse.mk:286: yes
+make: varmod-ifelse.mk:285: yes
CondParser_Eval: ${DELAYED} == "one"
Comparing "two" == "one"
-make: varmod-ifelse.mk:289: no
+make: varmod-ifelse.mk:288: no
CondParser_Eval: ${DELAYED} == "two"
Comparing "two" == "two"
-make: varmod-ifelse.mk:292: yes
-make: varmod-ifelse.mk:314: Unknown modifier ":X-then"
+make: varmod-ifelse.mk:291: yes
+make: varmod-ifelse.mk:313: Unknown modifier ":X-then"
while evaluating "${:X-then}:${:X-else}}" with value ""
while evaluating then-branch of condition "1"
-make: varmod-ifelse.mk:314: Unknown modifier ":X-else"
+make: varmod-ifelse.mk:313: Unknown modifier ":X-else"
while parsing "${:X-else}}"
while evaluating else-branch of condition "1"
-make: varmod-ifelse.mk:322: Bad condition
+make: varmod-ifelse.mk:321: Bad condition
while evaluating condition " < 0 "
-make: varmod-ifelse.mk:322: Unknown modifier ":Z1"
+make: varmod-ifelse.mk:321: Unknown modifier ":Z1"
while parsing "${:Z1}:${:Z2}}>"
while evaluating then-branch of condition " < 0 "
-make: varmod-ifelse.mk:322: Unknown modifier ":Z2"
+make: varmod-ifelse.mk:321: Unknown modifier ":Z2"
while parsing "${:Z2}}>"
while evaluating else-branch of condition " < 0 "
-make: varmod-ifelse.mk:322: <>
+make: varmod-ifelse.mk:321: <>
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/varmod-ifelse.mk b/contrib/bmake/unit-tests/varmod-ifelse.mk
index 986524330a97..fcd483d0c497 100644
--- a/contrib/bmake/unit-tests/varmod-ifelse.mk
+++ b/contrib/bmake/unit-tests/varmod-ifelse.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-ifelse.mk,v 1.39 2025/04/30 06:01:07 rillig Exp $
+# $NetBSD: varmod-ifelse.mk,v 1.41 2025/06/29 11:27:21 rillig Exp $
#
# Tests for the ${cond:?then:else} variable modifier, which evaluates either
# the then-expression or the else-expression, depending on the condition.
@@ -73,9 +73,9 @@ COND:= ${${UNDEF} == "":?bad-assign:bad-assign}
. error
.endif
-# If the "Bad conditional expression" appears in a quoted string literal, the
+# If the "Bad condition" appears in a quoted string literal, the
# error message "Malformed conditional" is not printed, leaving only the "Bad
-# conditional expression".
+# condition".
#
# XXX: The left-hand side is enclosed in quotes. This results in Var_Parse
# being called without VARE_EVAL_DEFINED. When ApplyModifier_IfElse
@@ -94,8 +94,7 @@ COND:= ${${UNDEF} == "":?bad-assign:bad-assign}
.if "${1 == == 2:?yes:no}" != ""
. error
.else
-# expect+1: warning: Oops, the parse error should have been propagated.
-. warning Oops, the parse error should have been propagated.
+. error
.endif
.MAKEFLAGS: -d0
@@ -158,7 +157,7 @@ STRING= string
NUMBER= no # not really a number
# expect+1: no.
.info ${${STRING} == "literal" && ${NUMBER} >= 10:?yes:no}.
-# expect+2: Comparison with '>=' requires both operands 'no' and '10' to be numeric
+# expect+2: Comparison with ">=" requires both operands "no" and "10" to be numeric
# expect+1: .
.info ${${STRING} == "literal" || ${NUMBER} >= 10:?yes:no}.
diff --git a/contrib/bmake/unit-tests/varmod-match-escape.exp b/contrib/bmake/unit-tests/varmod-match-escape.exp
index 25d78226345c..42e470310d4c 100755
--- a/contrib/bmake/unit-tests/varmod-match-escape.exp
+++ b/contrib/bmake/unit-tests/varmod-match-escape.exp
@@ -33,14 +33,18 @@ Comparing ":" != "::"
make: varmod-match-escape.mk:43: warning: XXX: Oops
Global: .MAKEFLAGS = -r -k -d cv -d
Global: .MAKEFLAGS = -r -k -d cv -d 0
-make: varmod-match-escape.mk:69: Dollar followed by nothing
+make: varmod-match-escape.mk:63: Unfinished backslash at the end in pattern "\" of modifier ":M"
while evaluating "${:U\$:M\$} != """ with value "$"
-make: varmod-match-escape.mk:110: Unfinished character list in pattern '[A-]' of modifier ':M'
+make: varmod-match-escape.mk:71: Dollar followed by nothing
+ while evaluating "${:U\$:M\$} != """ with value "$"
+make: varmod-match-escape.mk:71: Unfinished backslash at the end in pattern "\" of modifier ":M"
+ while evaluating "${:U\$:M\$} != """ with value "$"
+make: varmod-match-escape.mk:112: Unfinished character list in pattern "[A-]" of modifier ":M"
while evaluating variable "WORDS" with value "A A] A]] B B] B]] ] ]] ]]] a a] a]]"
- in .for loop from varmod-match-escape.mk:107 with pattern = [A-]
-make: varmod-match-escape.mk:110: Unfinished character list in pattern '[^A-]' of modifier ':M'
+ in .for loop from varmod-match-escape.mk:109 with pattern = [A-]
+make: varmod-match-escape.mk:112: Unfinished character list in pattern "[^A-]" of modifier ":M"
while evaluating variable "WORDS" with value "A A] A]] B B] B]] ] ]] ]]] a a] a]]"
- in .for loop from varmod-match-escape.mk:107 with pattern = [^A-]
+ in .for loop from varmod-match-escape.mk:109 with pattern = [^A-]
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/varmod-match-escape.mk b/contrib/bmake/unit-tests/varmod-match-escape.mk
index d9e2009f9b60..5c492d9d1f72 100755
--- a/contrib/bmake/unit-tests/varmod-match-escape.mk
+++ b/contrib/bmake/unit-tests/varmod-match-escape.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-match-escape.mk,v 1.18 2024/08/29 20:20:36 rillig Exp $
+# $NetBSD: varmod-match-escape.mk,v 1.20 2025/06/28 22:39:29 rillig Exp $
#
# As of 2020-08-01, the :M and :N modifiers interpret backslashes differently,
# depending on whether there was an expression somewhere before the
@@ -59,13 +59,15 @@ VALUES= : :: :\:
# '\{' nor '\}'. But the text is expanded, and a lonely '$' at the end
# is silently discarded. The resulting expanded pattern is thus '\', that
# is a single backslash.
+# expect+1: Unfinished backslash at the end in pattern "\" of modifier ":M"
.if ${:U\$:M\$} != ""
. error
.endif
# In lint mode, the case of a lonely '$' is covered with an error message.
.MAKEFLAGS: -dL
-# expect+1: Dollar followed by nothing
+# expect+2: Dollar followed by nothing
+# expect+1: Unfinished backslash at the end in pattern "\" of modifier ":M"
.if ${:U\$:M\$} != ""
. error
.endif
@@ -105,8 +107,8 @@ EXP.[^A-]]= a
EXP.[^A-]]]= a]
.for pattern in [A-] [A-]] [A-]]] [^A-] [^A-]] [^A-]]]
-# expect+2: Unfinished character list in pattern '[A-]' of modifier ':M'
-# expect+1: Unfinished character list in pattern '[^A-]' of modifier ':M'
+# expect+2: Unfinished character list in pattern "[A-]" of modifier ":M"
+# expect+1: Unfinished character list in pattern "[^A-]" of modifier ":M"
. if ${WORDS:M${pattern}} != ${EXP.${pattern}}
. warning ${pattern}: ${WORDS:M${pattern}} != ${EXP.${pattern}}
. endif
diff --git a/contrib/bmake/unit-tests/varmod-match.exp b/contrib/bmake/unit-tests/varmod-match.exp
index 14eb7862d815..7bccc4283e32 100644
--- a/contrib/bmake/unit-tests/varmod-match.exp
+++ b/contrib/bmake/unit-tests/varmod-match.exp
@@ -1,22 +1,22 @@
-make: varmod-match.mk:289: Unfinished character list in pattern 'a[' of modifier ':M'
+make: varmod-match.mk:293: Unfinished character list in pattern "a[" of modifier ":M"
while evaluating variable "WORDS" with value "a a["
-make: varmod-match.mk:297: Unfinished character list in pattern 'a[^' of modifier ':M'
+make: varmod-match.mk:301: Unfinished character list in pattern "a[^" of modifier ":M"
while evaluating variable "WORDS" with value "a a[ aX"
-make: varmod-match.mk:305: Unfinished character list in pattern '[-x1-3' of modifier ':M'
+make: varmod-match.mk:309: Unfinished character list in pattern "[-x1-3" of modifier ":M"
while evaluating variable "WORDS" with value "- + x xx 0 1 2 3 4 [x1-3"
-make: varmod-match.mk:313: Unfinished character list in pattern '*[-x1-3' of modifier ':M'
+make: varmod-match.mk:317: Unfinished character list in pattern "*[-x1-3" of modifier ":M"
while evaluating variable "WORDS" with value "- + x xx 0 1 2 3 4 00 01 10 11 000 001 010 011 100 101 110 111 [x1-3"
-make: varmod-match.mk:322: Unfinished character list in pattern '[^-x1-3' of modifier ':M'
+make: varmod-match.mk:326: Unfinished character list in pattern "[^-x1-3" of modifier ":M"
while evaluating variable "WORDS" with value "- + x xx 0 1 2 3 4 [x1-3"
-make: varmod-match.mk:336: Unfinished character list in pattern '?[\' of modifier ':M'
+make: varmod-match.mk:340: Unfinished character list in pattern "?[\" of modifier ":M"
while evaluating variable "WORDS" with value "\\ \a x\"
-make: varmod-match.mk:344: Unfinished character range in pattern '[x-' of modifier ':M'
+make: varmod-match.mk:348: Unfinished character range in pattern "[x-" of modifier ":M"
while evaluating variable "WORDS" with value "[x- x x- y"
-make: varmod-match.mk:356: Unfinished character range in pattern '[^x-' of modifier ':M'
+make: varmod-match.mk:360: Unfinished character range in pattern "[^x-" of modifier ":M"
while evaluating variable "WORDS" with value "[x- x x- y yyyyy"
-make: varmod-match.mk:363: Unfinished character list in pattern '[' of modifier ':M'
+make: varmod-match.mk:367: Unfinished character list in pattern "[" of modifier ":M"
while evaluating variable " : :: " with value " : :: "
-make: varmod-match.mk:363: Unknown modifier ":]"
+make: varmod-match.mk:367: Unknown modifier ":]"
while evaluating variable " : :: " with value ""
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
diff --git a/contrib/bmake/unit-tests/varmod-match.mk b/contrib/bmake/unit-tests/varmod-match.mk
index 99184989fb83..5894196c9cd5 100644
--- a/contrib/bmake/unit-tests/varmod-match.mk
+++ b/contrib/bmake/unit-tests/varmod-match.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-match.mk,v 1.30 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: varmod-match.mk,v 1.32 2025/06/29 09:40:13 rillig Exp $
#
# Tests for the ':M' modifier, which keeps only those words that match the
# given pattern.
@@ -13,8 +13,12 @@
# 6. Error handling
# 7. Historical bugs
#
-# See ApplyModifier_Match, ParseModifier_Match, ModifyWord_Match and
-# Str_Match.
+# See also:
+# char-005c-reverse-solidus.mk
+# ApplyModifier_Match
+# ParseModifier_Match
+# ModifyWord_Match
+# Str_Match
# 1. Pattern characters '*', '?' and '\'
@@ -285,7 +289,7 @@ ${:U*}= asterisk
# [ Incomplete empty character list, never matches.
WORDS= a a[
-# expect+1: Unfinished character list in pattern 'a[' of modifier ':M'
+# expect+1: Unfinished character list in pattern "a[" of modifier ":M"
.if ${WORDS:Ma[} != ""
. error
.endif
@@ -293,7 +297,7 @@ WORDS= a a[
# [^ Incomplete negated empty character list, matches any single
# character.
WORDS= a a[ aX
-# expect+1: Unfinished character list in pattern 'a[^' of modifier ':M'
+# expect+1: Unfinished character list in pattern "a[^" of modifier ":M"
.if ${WORDS:Ma[^} != "a[ aX"
. error
.endif
@@ -301,7 +305,7 @@ WORDS= a a[ aX
# [-x1-3 Incomplete character list, matches those elements that can be
# parsed without lookahead.
WORDS= - + x xx 0 1 2 3 4 [x1-3
-# expect+1: Unfinished character list in pattern '[-x1-3' of modifier ':M'
+# expect+1: Unfinished character list in pattern "[-x1-3" of modifier ":M"
.if ${WORDS:M[-x1-3} != "- x 1 2 3"
. error
.endif
@@ -309,7 +313,7 @@ WORDS= - + x xx 0 1 2 3 4 [x1-3
# *[-x1-3 Incomplete character list after a wildcard, matches those
# words that end with one of the characters from the list.
WORDS= - + x xx 0 1 2 3 4 00 01 10 11 000 001 010 011 100 101 110 111 [x1-3
-# expect+1: Unfinished character list in pattern '*[-x1-3' of modifier ':M'
+# expect+1: Unfinished character list in pattern "*[-x1-3" of modifier ":M"
.if ${WORDS:M*[-x1-3} != "- x xx 1 2 3 01 11 001 011 101 111 [x1-3"
. warning ${WORDS:M*[-x1-3}
.endif
@@ -318,7 +322,7 @@ WORDS= - + x xx 0 1 2 3 4 00 01 10 11 000 001 010 011 100 101 110 111 [x1-3
# Incomplete negated character list, matches any character
# except those elements that can be parsed without lookahead.
WORDS= - + x xx 0 1 2 3 4 [x1-3
-# expect+1: Unfinished character list in pattern '[^-x1-3' of modifier ':M'
+# expect+1: Unfinished character list in pattern "[^-x1-3" of modifier ":M"
.if ${WORDS:M[^-x1-3} != "+ 0 4"
. error
.endif
@@ -332,7 +336,7 @@ WORDS= - + x xx 0 1 2 3 4 [x1-3
# '\', as there is no following space that could be escaped.
WORDS= \\ \a ${:Ux\\}
PATTERN= ${:U?[\\}
-# expect+1: Unfinished character list in pattern '?[\' of modifier ':M'
+# expect+1: Unfinished character list in pattern "?[\" of modifier ":M"
.if ${WORDS:M${PATTERN}} != "\\\\ x\\"
. error
.endif
@@ -340,7 +344,7 @@ PATTERN= ${:U?[\\}
# [x- Incomplete character list containing an incomplete character
# range, matches only the 'x'.
WORDS= [x- x x- y
-# expect+1: Unfinished character range in pattern '[x-' of modifier ':M'
+# expect+1: Unfinished character range in pattern "[x-" of modifier ":M"
.if ${WORDS:M[x-} != "x"
. error
.endif
@@ -352,13 +356,13 @@ WORDS= [x- x x- y
# XXX: Even matches strings that are longer than a single
# character.
WORDS= [x- x x- y yyyyy
-# expect+1: Unfinished character range in pattern '[^x-' of modifier ':M'
+# expect+1: Unfinished character range in pattern "[^x-" of modifier ":M"
.if ${WORDS:M[^x-} != "[x- y yyyyy"
. error
.endif
# [:] matches never since the ':' starts the next modifier
-# expect+2: Unfinished character list in pattern '[' of modifier ':M'
+# expect+2: Unfinished character list in pattern "[" of modifier ":M"
# expect+1: Unknown modifier ":]"
.if ${ ${:U\:} ${:U\:\:} :L:M[:]} != ":"
. error
diff --git a/contrib/bmake/unit-tests/varmod-mtime.exp b/contrib/bmake/unit-tests/varmod-mtime.exp
index 9960dd877768..53b86b99b867 100644
--- a/contrib/bmake/unit-tests/varmod-mtime.exp
+++ b/contrib/bmake/unit-tests/varmod-mtime.exp
@@ -1,12 +1,12 @@
-make: varmod-mtime.mk:46: Invalid argument '123x' for modifier ':mtime'
+make: varmod-mtime.mk:46: Invalid argument "123x" for modifier ":mtime"
while evaluating variable "no/such/file" with value "no/such/file"
make: varmod-mtime.mk:68: Cannot determine mtime for "no/such/file1": <ENOENT>
while evaluating variable "no/such/file1 no/such/file2" with value "no/such/file1 no/such/file2"
make: varmod-mtime.mk:68: Cannot determine mtime for "no/such/file2": <ENOENT>
while evaluating variable "no/such/file1 no/such/file2" with value "no/such/file1 no/such/file2"
-make: varmod-mtime.mk:78: Invalid argument 'errorhandler-no' for modifier ':mtime'
+make: varmod-mtime.mk:78: Invalid argument "errorhandler-no" for modifier ":mtime"
while evaluating variable "MAKEFILE" with value "varmod-mtime.mk"
-make: varmod-mtime.mk:86: Invalid argument 'warn' for modifier ':mtime'
+make: varmod-mtime.mk:86: Invalid argument "warn" for modifier ":mtime"
while evaluating variable "MAKEFILE" with value "varmod-mtime.mk"
make: varmod-mtime.mk:110: Unknown modifier ":mtim"
while evaluating variable "anything" with value "anything"
diff --git a/contrib/bmake/unit-tests/varmod-mtime.mk b/contrib/bmake/unit-tests/varmod-mtime.mk
index ec33cd698b41..aed7024efd6b 100644
--- a/contrib/bmake/unit-tests/varmod-mtime.mk
+++ b/contrib/bmake/unit-tests/varmod-mtime.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-mtime.mk,v 1.16 2025/06/12 18:51:05 rillig Exp $
+# $NetBSD: varmod-mtime.mk,v 1.17 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the ':mtime' variable modifier, which maps each word of the
# expression to that file's modification time.
@@ -42,7 +42,7 @@ not_found_mtime:= ${no/such/file:L:mtime}
# The fallback timestamp must only be an integer, without trailing characters.
-# expect+1: Invalid argument '123x' for modifier ':mtime'
+# expect+1: Invalid argument "123x" for modifier ":mtime"
.if ${no/such/file:L:mtime=123x}
. error
.else
@@ -74,7 +74,7 @@ _!= rm -f ${COOKIE}
# Only the word 'error' is a special argument to the ':mtime' modifier, all
# other words result in a parse error.
-# expect+1: Invalid argument 'errorhandler-no' for modifier ':mtime'
+# expect+1: Invalid argument "errorhandler-no" for modifier ":mtime"
.if ${MAKEFILE:mtime=errorhandler-no} > 0
.else
. error
@@ -82,7 +82,7 @@ _!= rm -f ${COOKIE}
# Only the word 'error' can be used as a fallback argument to the modifier.
-# expect+1: Invalid argument 'warn' for modifier ':mtime'
+# expect+1: Invalid argument "warn" for modifier ":mtime"
.if ${MAKEFILE:mtime=warn} > 0
. error
.else
diff --git a/contrib/bmake/unit-tests/varmod-order.exp b/contrib/bmake/unit-tests/varmod-order.exp
index f48256c6ae0e..fd18f0e11ee1 100644
--- a/contrib/bmake/unit-tests/varmod-order.exp
+++ b/contrib/bmake/unit-tests/varmod-order.exp
@@ -2,11 +2,11 @@ make: varmod-order.mk:14: Unknown modifier ":OX"
while evaluating variable "WORDS" with value "one two three four five six seven eight nine ten"
make: varmod-order.mk:17: Unknown modifier ":OxXX"
while evaluating variable "WORDS" with value "one two three four five six seven eight nine ten"
-make: varmod-order.mk:20: Unclosed expression, expecting '}' for modifier "O"
+make: varmod-order.mk:20: Unclosed expression, expecting "}" for modifier "O"
while evaluating variable "WORDS" with value "eight five four nine one seven six ten three two"
-make: varmod-order.mk:22: Unclosed expression, expecting '}' for modifier "On"
+make: varmod-order.mk:22: Unclosed expression, expecting "}" for modifier "On"
while evaluating variable "NUMBERS" with value "1 2 3 4 5 6 7 8 9 10"
-make: varmod-order.mk:24: Unclosed expression, expecting '}' for modifier "Onr"
+make: varmod-order.mk:24: Unclosed expression, expecting "}" for modifier "Onr"
while evaluating variable "NUMBERS" with value "10 9 8 7 6 5 4 3 2 1"
make: varmod-order.mk:30: Unknown modifier ":Oxn"
while evaluating variable "NUMBERS" with value "8 5 4 9 1 7 6 10 3 2"
diff --git a/contrib/bmake/unit-tests/varmod-order.mk b/contrib/bmake/unit-tests/varmod-order.mk
index c8386ef951dc..f4fa5d10cdf8 100644
--- a/contrib/bmake/unit-tests/varmod-order.mk
+++ b/contrib/bmake/unit-tests/varmod-order.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-order.mk,v 1.19 2025/03/29 23:50:07 rillig Exp $
+# $NetBSD: varmod-order.mk,v 1.20 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the :O variable modifier and its variants, which either sort the
# words of the value or shuffle them.
@@ -16,11 +16,11 @@ _:= ${WORDS:OX}
# expect+1: Unknown modifier ":OxXX"
_:= ${WORDS:OxXX}
-# expect+1: Unclosed expression, expecting '}' for modifier "O"
+# expect+1: Unclosed expression, expecting "}" for modifier "O"
_:= ${WORDS:O
-# expect+1: Unclosed expression, expecting '}' for modifier "On"
+# expect+1: Unclosed expression, expecting "}" for modifier "On"
_:= ${NUMBERS:On
-# expect+1: Unclosed expression, expecting '}' for modifier "Onr"
+# expect+1: Unclosed expression, expecting "}" for modifier "Onr"
_:= ${NUMBERS:Onr
# Shuffling numerically doesn't make sense, so don't allow 'x' and 'n' to be
diff --git a/contrib/bmake/unit-tests/varmod-range.exp b/contrib/bmake/unit-tests/varmod-range.exp
index 768ba9ac2f2d..b98865a4084a 100644
--- a/contrib/bmake/unit-tests/varmod-range.exp
+++ b/contrib/bmake/unit-tests/varmod-range.exp
@@ -1,6 +1,6 @@
make: varmod-range.mk:43: Variable "" is undefined
while evaluating "${:range=5} != """ with value "1 2 3 4 5"
-make: varmod-range.mk:66: Invalid number "x}Rest" != "Rest"" for ':range' modifier
+make: varmod-range.mk:66: Invalid number "x}Rest" != "Rest"" for modifier ":range"
while evaluating "${:U:range=x}Rest" != "Rest"" with value ""
make: varmod-range.mk:76: Unknown modifier ":x0"
while evaluating "${:U:range=0x0}Rest" != "Rest"" with value "1"
diff --git a/contrib/bmake/unit-tests/varmod-range.mk b/contrib/bmake/unit-tests/varmod-range.mk
index 7a60bcc23d86..69dcf6ad1a7d 100644
--- a/contrib/bmake/unit-tests/varmod-range.mk
+++ b/contrib/bmake/unit-tests/varmod-range.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-range.mk,v 1.18 2025/04/04 18:57:01 rillig Exp $
+# $NetBSD: varmod-range.mk,v 1.19 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the :range variable modifier, which generates sequences
# of integers from the given range.
@@ -62,7 +62,7 @@
#
# Since 2020-11-01, the parser issues a more precise "Invalid number" error
# instead.
-# expect+1: Invalid number "x}Rest" != "Rest"" for ':range' modifier
+# expect+1: Invalid number "x}Rest" != "Rest"" for modifier ":range"
.if "${:U:range=x}Rest" != "Rest"
. error
.else
diff --git a/contrib/bmake/unit-tests/varmod.exp b/contrib/bmake/unit-tests/varmod.exp
index 09c922aa16bd..022181d05cf1 100644
--- a/contrib/bmake/unit-tests/varmod.exp
+++ b/contrib/bmake/unit-tests/varmod.exp
@@ -1,47 +1,54 @@
make: varmod.mk:111: To escape a dollar, use \$, not $$, at "$$:L} != """
-make: varmod.mk:111: Invalid variable name ':', at "$:L} != """
+make: varmod.mk:111: Invalid variable name ":", at "$:L} != """
make: varmod.mk:117: Dollar followed by nothing
while evaluating "${:Uword:@word@${word}$@} != "word"" with value "word"
-make: varmod.mk:127: Missing delimiter ':' after modifier "P"
+make: varmod.mk:125: Missing delimiter ":" after modifier "P"
while evaluating variable "VAR" with value "VAR"
-make: varmod.mk:129: Missing argument for ".error"
-make: varmod.mk:135: Invalid modifier ":[99333000222000111000]"
+make: varmod.mk:134: Invalid modifier ":[99333000222000111000]"
while evaluating variable "word" with value "word"
-make: varmod.mk:138: Invalid modifier ":[2147483648]"
+make: varmod.mk:137: Invalid modifier ":[2147483648]"
while evaluating variable "word" with value "word"
-make: varmod.mk:144: Invalid number "99333000222000111000}" for ':range' modifier
+make: varmod.mk:143: Invalid number "99333000222000111000}" for modifier ":range"
while evaluating variable "word" with value "word"
-make: varmod.mk:151: Invalid time value "\"
+make: varmod.mk:150: Invalid time value "\"
while evaluating indirect modifiers "gmtime=\"
while evaluating "${:${:Ugmtime=\\}}" with value ""
-make: varmod.mk:166: Dollar followed by nothing
+make: varmod.mk:165: Dollar followed by nothing
while evaluating variable "VAR" with value "value$"
-make: varmod.mk:172: Dollar followed by nothing
+make: varmod.mk:171: Dollar followed by nothing
while evaluating variable "VAR" with value "value$"
-make: varmod.mk:172: Dollar followed by nothing
+make: varmod.mk:171: Dollar followed by nothing
while evaluating variable "VAR" with value "value$ appended$"
-make: varmod.mk:182: Dollar followed by nothing
+make: varmod.mk:181: Dollar followed by nothing
while evaluating variable "word" with value "word"
-make: varmod.mk:186: Invalid modifier ":[$]"
+make: varmod.mk:185: Invalid modifier ":[$]"
while evaluating variable "word" with value ""
-make: varmod.mk:203: Dollar followed by nothing
+make: varmod.mk:202: Dollar followed by nothing
while evaluating variable "VAR" with value "value$ appended$"
-make: varmod.mk:203: Invalid variable name '}', at "$} != "set""
+make: varmod.mk:202: Invalid variable name "}", at "$} != "set""
while evaluating variable "VAR" with value "value<space>appended"
-make: varmod.mk:207: Invalid variable name '}', at "$} != "fallback""
+make: varmod.mk:206: Invalid variable name "}", at "$} != "fallback""
while evaluating "${:Ufallback$} != "fallback"" with value ""
-make: varmod.mk:211: Invalid time value "1000$"
+make: varmod.mk:210: Invalid time value "1000$"
while evaluating variable "%y" with value "%y"
-make: varmod.mk:217: Invalid time value "1000$"
+make: varmod.mk:216: Invalid time value "1000$"
while evaluating variable "%y" with value "%y"
-make: varmod.mk:223: Dollar followed by nothing
+make: varmod.mk:222: Dollar followed by nothing
while evaluating variable "word" with value "word"
-make: varmod.mk:227: Dollar followed by nothing
+make: varmod.mk:226: Dollar followed by nothing
while evaluating variable "word" with value "word"
-make: varmod.mk:231: Invalid argument 'fallback$' for modifier ':mtime'
+make: varmod.mk:230: Invalid argument "fallback$" for modifier ":mtime"
while evaluating variable "." with value "."
-make: varmod.mk:245: Missing delimiter ':' after modifier "L"
+make: varmod.mk:244: Missing delimiter ":" after modifier "L"
while evaluating variable "VAR" with value "VAR"
+make: varmod.mk:256: Invalid time value " : } \ $ ) \) ( "
+ while evaluating variable "%Y" with value "%Y"
+make: varmod.mk:263: Invalid time value " : \) \ $ "
+ while evaluating variable "%Y" with value "%Y"
+make: varmod.mk:268: Invalid time value " : } \ $ ) \) ( "
+ while evaluating variable "%Y" with value "%Y"
+make: varmod.mk:273: Invalid time value " : \) \ $ "
+ while evaluating variable "%Y" with value "%Y"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/varmod.mk b/contrib/bmake/unit-tests/varmod.mk
index cc7b08c447e9..af976f9d0086 100644
--- a/contrib/bmake/unit-tests/varmod.mk
+++ b/contrib/bmake/unit-tests/varmod.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod.mk,v 1.26 2025/03/30 01:27:13 rillig Exp $
+# $NetBSD: varmod.mk,v 1.30 2025/06/29 11:27:21 rillig Exp $
#
# Tests for variable modifiers, such as :Q, :S,from,to or :Ufallback.
#
@@ -107,7 +107,7 @@ DOLLAR2= ${:U\$}
# Should it?
.MAKEFLAGS: -dL
# expect+2: To escape a dollar, use \$, not $$, at "$$:L} != """
-# expect+1: Invalid variable name ':', at "$:L} != """
+# expect+1: Invalid variable name ":", at "$:L} != """
.if ${$$:L} != ""
. error
.endif
@@ -118,14 +118,13 @@ DOLLAR2= ${:U\$}
. error
.endif
-# The variable modifier :P does not fall back to the SysV modifier.
+# The modifier :P does not fall back to the SysV modifier.
# Therefore the modifier :P=RE generates a parse error.
-# XXX: The .error should not be reached since the expression is
-# malformed, and this error should be propagated up to Cond_EvalLine.
VAR= STOP
-# expect+1: Missing delimiter ':' after modifier "P"
+# expect+1: Missing delimiter ":" after modifier "P"
.if ${VAR:P=RE} != "STORE"
-# expect+1: Missing argument for ".error"
+. error
+.else
. error
.endif
@@ -140,7 +139,7 @@ VAR= STOP
# Test the range generation modifier ':range=n' with a very large number that
# is larger than SIZE_MAX for any supported platform.
-# expect+1: Invalid number "99333000222000111000}" for ':range' modifier
+# expect+1: Invalid number "99333000222000111000}" for modifier ":range"
.if ${word:L:range=99333000222000111000}
.endif
@@ -199,11 +198,11 @@ VAR_DOLLAR= VAR$$
. error
.endif
# expect+2: Dollar followed by nothing
-# expect+1: Invalid variable name '}', at "$} != "set""
+# expect+1: Invalid variable name "}", at "$} != "set""
.if ${VAR:Dset$} != "set"
. error
.endif
-# expect+1: Invalid variable name '}', at "$} != "fallback""
+# expect+1: Invalid variable name "}", at "$} != "fallback""
.if ${:Ufallback$} != "fallback"
. error
.endif
@@ -227,7 +226,7 @@ VAR_DOLLAR= VAR$$
.if ${word:L:NX*$} != "word"
. error
.endif
-# expect+1: Invalid argument 'fallback$' for modifier ':mtime'
+# expect+1: Invalid argument "fallback$" for modifier ":mtime"
.if ${.:L:mtime=fallback$}
. error
.else
@@ -241,10 +240,36 @@ VAR_DOLLAR= VAR$$
.endif
.undef VAR
-# expect+1: Missing delimiter ':' after modifier "L"
+# expect+1: Missing delimiter ":" after modifier "L"
.if ${VAR:LAR=ALUE} != "VALUE"
. error
.endif
.if ${VAR:L:AR=ALUE} != "VALUE"
. error
.endif
+
+
+# When an expression has the usual form ${...} with braces,
+# in the part of a modifier, ":}\$" can be escaped using a backslash.
+# All other characters are passed through unmodified.
+# expect+1: Invalid time value " : } \ $ ) \) ( "
+.if ${%Y:L:localtime= \: \} \\ \$ ) \) ( :M*} != ": } \\ \$ ) \\) ("
+. error
+.endif
+# When an expression has the unusual form $(...) with parentheses,
+# in the part of a modifier, ":)\$" can be escaped using a backslash.
+# All other characters are passed through unmodified.
+# expect+1: Invalid time value " : \) \ $ "
+.if ${%Y:L:localtime= \: \) \\ \$ } \} { :M*} != ": ) \\ \$ } \\} {"
+. error
+.endif
+# Same when the modifier is the last modifier in an expression.
+# expect+1: Invalid time value " : } \ $ ) \) ( "
+.if ${%Y:L:localtime= \: \} \\ \$ ) \) ( } != " : } \\ \$ ) \\) ( "
+. error
+.endif
+# Same when the modifier is the last modifier in an expression.
+# expect+1: Invalid time value " : \) \ $ "
+.if ${%Y:L:localtime= \: \) \\ \$ } \} { } != " : ) \\ \$ } \\} { "
+. error
+.endif
diff --git a/contrib/bmake/unit-tests/varname-circumflex.exp b/contrib/bmake/unit-tests/varname-circumflex.exp
new file mode 100644
index 000000000000..184b021fd5e5
--- /dev/null
+++ b/contrib/bmake/unit-tests/varname-circumflex.exp
@@ -0,0 +1,9 @@
+no_prerequisites:
+prerequisite: file1.o
+unique: file1.o file2.o file3.o
+duplicate: file1.o file2.o file3.o
+dir_part: /usr/include /usr/include .
+file_part: stdio.h unistd.h foo.h
+implicit.tout: implicit.tin
+wait: file1.o .WAIT_1 file2.o
+exit status 0
diff --git a/contrib/bmake/unit-tests/varname-circumflex.mk b/contrib/bmake/unit-tests/varname-circumflex.mk
new file mode 100644
index 000000000000..270f7123781b
--- /dev/null
+++ b/contrib/bmake/unit-tests/varname-circumflex.mk
@@ -0,0 +1,47 @@
+# $NetBSD: varname-circumflex.mk,v 1.1 2025/06/27 20:20:56 rillig Exp $
+#
+# Tests for the target-local variable "^", which is required by POSIX 2024
+# and provided by GNU make.
+
+# TODO: Support $^.
+
+all: .PHONY
+all: no_prerequisites prerequisite
+all: unique duplicate
+all: dir_part file_part
+all: implicit.tout
+all: wait
+
+.if defined(^)
+. error
+.endif
+
+no_prerequisites:
+ @echo $@: $^
+
+prerequisite: file1.o
+ @echo $@: $^
+
+unique: file1.o file2.o file3.o
+ @echo $@: $^
+
+duplicate: file1.o file2.o file3.o file3.o
+ @echo $@: $^
+
+dir_part: /usr/include/stdio.h /usr/include/unistd.h foo.h
+ @echo $@: $(^D)
+
+file_part: /usr/include/stdio.h /usr/include/unistd.h foo.h
+ @echo $@: ${^F}
+
+wait: file1.o .WAIT file2.o
+ @echo $@: $^
+
+.SUFFIXES:
+.SUFFIXES: .tin .tout
+
+.tin.tout:
+ @echo $@: $^
+
+file1.o file2.o file3.o:
+/usr/include/stdio.h /usr/include/unistd.h foo.h implicit.tin:
diff --git a/contrib/bmake/unit-tests/varname-vpath.exp b/contrib/bmake/unit-tests/varname-vpath.exp
index bf7a3036e99d..a750957b92ac 100644
--- a/contrib/bmake/unit-tests/varname-vpath.exp
+++ b/contrib/bmake/unit-tests/varname-vpath.exp
@@ -1,12 +1,12 @@
CondParser_Eval: !defined(TEST_MAIN)
CondParser_Eval: exists(file-in-subdirectory)
-exists(file-in-subdirectory) result is ""
+"file-in-subdirectory" does not exist
CondParser_Eval: exists(file2-in-subdirectory)
-exists(file2-in-subdirectory) result is ""
+"file2-in-subdirectory" does not exist
CondParser_Eval: exists(file-in-subdirectory)
-exists(file-in-subdirectory) result is "varname-vpath.dir/file-in-subdirectory"
+"file-in-subdirectory" exists in "varname-vpath.dir/file-in-subdirectory"
: yes 1
CondParser_Eval: exists(file2-in-subdirectory)
-exists(file2-in-subdirectory) result is "varname-vpath.dir2/file2-in-subdirectory"
+"file2-in-subdirectory" exists in "varname-vpath.dir2/file2-in-subdirectory"
: yes 2
exit status 0
diff --git a/contrib/bmake/unit-tests/varname.exp b/contrib/bmake/unit-tests/varname.exp
index d173d2025e9f..454e40cdf9cf 100644
--- a/contrib/bmake/unit-tests/varname.exp
+++ b/contrib/bmake/unit-tests/varname.exp
@@ -5,13 +5,13 @@ Var_Parse: ${VARNAME} (eval)
Global: VAR((( = 3 open parentheses
Var_Parse: ${VAR(((}}}}" != "3 open parentheses}}}" (eval)
Global: .ALLTARGETS = VAR(((=)
-make: varname.mk:31: Missing ')' in archive specification
+make: varname.mk:31: Missing ")" in archive specification
make: varname.mk:31: Error in archive specification: "VAR"
Var_Parse: ${:UVAR\(\(\(}= try2 (eval)
Evaluating modifier ${:U...} on value "" (eval, undefined)
Result of ${:UVAR\(\(\(} is "VAR\(\(\(" (eval, defined)
Global: .ALLTARGETS = VAR(((=) VAR\(\(\(=
-make: varname.mk:37: Invalid line '${:UVAR\(\(\(}= try2', expanded to 'VAR\(\(\(= try2'
+make: varname.mk:37: Invalid line "${:UVAR\(\(\(}= try2", expanded to "VAR\(\(\(= try2"
Var_Parse: ${VARNAME} (eval)
Global: VAR((( = try3
Global: .MAKEFLAGS = -r -k -d v -d
diff --git a/contrib/bmake/unit-tests/varname.mk b/contrib/bmake/unit-tests/varname.mk
index ae18819aa19e..17f29da7ef4c 100644
--- a/contrib/bmake/unit-tests/varname.mk
+++ b/contrib/bmake/unit-tests/varname.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varname.mk,v 1.17 2025/06/12 04:33:00 rillig Exp $
+# $NetBSD: varname.mk,v 1.18 2025/06/28 22:39:29 rillig Exp $
#
# Tests for variable names.
@@ -26,14 +26,14 @@ ${VARNAME}= 3 open parentheses
# This is not a variable assignment since the parentheses and braces are not
# balanced. At the end of the line, there are still 3 levels open, which
# means the variable name is not finished.
-# expect+2: Missing ')' in archive specification
+# expect+2: Missing ")" in archive specification
# expect+1: Error in archive specification: "VAR"
${:UVAR(((}= try1
# On the left-hand side of a variable assignments, the backslash is not parsed
# as an escape character, therefore the parentheses still count to the nesting
# level, which at the end of the line is still 3. Therefore this is not a
# variable assignment as well.
-# expect+1: Invalid line '${:UVAR\(\(\(}= try2', expanded to 'VAR\(\(\(= try2'
+# expect+1: Invalid line "${:UVAR\(\(\(}= try2", expanded to "VAR\(\(\(= try2"
${:UVAR\(\(\(}= try2
# To assign to a variable with an arbitrary name, the variable name has to
# come from an external source, not the text that is parsed in the assignment
diff --git a/contrib/bmake/unit-tests/varparse-errors.exp b/contrib/bmake/unit-tests/varparse-errors.exp
index d4d01c96627e..2a9be069075f 100644
--- a/contrib/bmake/unit-tests/varparse-errors.exp
+++ b/contrib/bmake/unit-tests/varparse-errors.exp
@@ -12,33 +12,33 @@ make: varparse-errors.mk:73: Unknown modifier ":OX"
make: varparse-errors.mk:73: Unknown modifier ":OX"
while evaluating "${:OX}" with value ""
while evaluating variable "IND" with value "${:OX}"
-make: varparse-errors.mk:81: Unclosed expression, expecting '}' for modifier "Q"
+make: varparse-errors.mk:81: Unclosed expression, expecting "}" for modifier "Q"
while evaluating "${:U:Q" with value ""
-make: varparse-errors.mk:83: Unclosed expression, expecting '}' for modifier "sh"
+make: varparse-errors.mk:83: Unclosed expression, expecting "}" for modifier "sh"
while evaluating "${:U:sh" with value ""
-make: varparse-errors.mk:85: Unclosed expression, expecting '}' for modifier "tA"
+make: varparse-errors.mk:85: Unclosed expression, expecting "}" for modifier "tA"
while evaluating "${:U:tA" with value ""
-make: varparse-errors.mk:87: Unclosed expression, expecting '}' for modifier "tsX"
+make: varparse-errors.mk:87: Unclosed expression, expecting "}" for modifier "tsX"
while evaluating "${:U:tsX" with value ""
-make: varparse-errors.mk:89: Unclosed expression, expecting '}' for modifier "ts"
+make: varparse-errors.mk:89: Unclosed expression, expecting "}" for modifier "ts"
while evaluating "${:U:ts" with value ""
-make: varparse-errors.mk:91: Unclosed expression, expecting '}' for modifier "ts\040"
+make: varparse-errors.mk:91: Unclosed expression, expecting "}" for modifier "ts\040"
while evaluating "${:U:ts\040" with value ""
-make: varparse-errors.mk:93: Unclosed expression, expecting '}' for modifier "u"
+make: varparse-errors.mk:93: Unclosed expression, expecting "}" for modifier "u"
while evaluating "${:U:u" with value ""
-make: varparse-errors.mk:95: Unclosed expression, expecting '}' for modifier "H"
+make: varparse-errors.mk:95: Unclosed expression, expecting "}" for modifier "H"
while evaluating "${:U:H" with value "."
-make: varparse-errors.mk:97: Unclosed expression, expecting '}' for modifier "[1]"
+make: varparse-errors.mk:97: Unclosed expression, expecting "}" for modifier "[1]"
while evaluating "${:U:[1]" with value ""
-make: varparse-errors.mk:99: Unclosed expression, expecting '}' for modifier "hash"
+make: varparse-errors.mk:99: Unclosed expression, expecting "}" for modifier "hash"
while evaluating "${:U:hash" with value "b2af338b"
-make: varparse-errors.mk:101: Unclosed expression, expecting '}' for modifier "range"
+make: varparse-errors.mk:101: Unclosed expression, expecting "}" for modifier "range"
while evaluating "${:U:range" with value "1"
-make: varparse-errors.mk:103: Unclosed expression, expecting '}' for modifier "_"
+make: varparse-errors.mk:103: Unclosed expression, expecting "}" for modifier "_"
while evaluating "${:U:_" with value ""
-make: varparse-errors.mk:105: Unclosed expression, expecting '}' for modifier "gmtime"
+make: varparse-errors.mk:105: Unclosed expression, expecting "}" for modifier "gmtime"
while evaluating "${:U:gmtime" with value "<timestamp>"
-make: varparse-errors.mk:107: Unclosed expression, expecting '}' for modifier "localtime"
+make: varparse-errors.mk:107: Unclosed expression, expecting "}" for modifier "localtime"
while evaluating "${:U:localtime" with value "<timestamp>"
make: varparse-errors.tmp:1: Unknown modifier ":Z"
while evaluating "${:Z}" with value ""
diff --git a/contrib/bmake/unit-tests/varparse-errors.mk b/contrib/bmake/unit-tests/varparse-errors.mk
index 2d1142fbb65c..bd74c442e789 100644
--- a/contrib/bmake/unit-tests/varparse-errors.mk
+++ b/contrib/bmake/unit-tests/varparse-errors.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varparse-errors.mk,v 1.25 2025/05/03 08:18:33 rillig Exp $
+# $NetBSD: varparse-errors.mk,v 1.26 2025/06/28 22:39:29 rillig Exp $
# Tests for parsing and evaluating all kinds of expressions.
#
@@ -77,33 +77,33 @@ _:= ${:U:OX:U${IND}} ${:U:OX:U${IND}}
# Before var.c 1.032 from 2022-08-24, make complained about 'Unknown modifier'
# or 'Bad modifier' when in fact the modifier was entirely correct, it was
# just not delimited by either ':' or '}' but instead by '\0'.
-# expect+1: Unclosed expression, expecting '}' for modifier "Q"
+# expect+1: Unclosed expression, expecting "}" for modifier "Q"
UNCLOSED:= ${:U:Q
-# expect+1: Unclosed expression, expecting '}' for modifier "sh"
+# expect+1: Unclosed expression, expecting "}" for modifier "sh"
UNCLOSED:= ${:U:sh
-# expect+1: Unclosed expression, expecting '}' for modifier "tA"
+# expect+1: Unclosed expression, expecting "}" for modifier "tA"
UNCLOSED:= ${:U:tA
-# expect+1: Unclosed expression, expecting '}' for modifier "tsX"
+# expect+1: Unclosed expression, expecting "}" for modifier "tsX"
UNCLOSED:= ${:U:tsX
-# expect+1: Unclosed expression, expecting '}' for modifier "ts"
+# expect+1: Unclosed expression, expecting "}" for modifier "ts"
UNCLOSED:= ${:U:ts
-# expect+1: Unclosed expression, expecting '}' for modifier "ts\040"
+# expect+1: Unclosed expression, expecting "}" for modifier "ts\040"
UNCLOSED:= ${:U:ts\040
-# expect+1: Unclosed expression, expecting '}' for modifier "u"
+# expect+1: Unclosed expression, expecting "}" for modifier "u"
UNCLOSED:= ${:U:u
-# expect+1: Unclosed expression, expecting '}' for modifier "H"
+# expect+1: Unclosed expression, expecting "}" for modifier "H"
UNCLOSED:= ${:U:H
-# expect+1: Unclosed expression, expecting '}' for modifier "[1]"
+# expect+1: Unclosed expression, expecting "}" for modifier "[1]"
UNCLOSED:= ${:U:[1]
-# expect+1: Unclosed expression, expecting '}' for modifier "hash"
+# expect+1: Unclosed expression, expecting "}" for modifier "hash"
UNCLOSED:= ${:U:hash
-# expect+1: Unclosed expression, expecting '}' for modifier "range"
+# expect+1: Unclosed expression, expecting "}" for modifier "range"
UNCLOSED:= ${:U:range
-# expect+1: Unclosed expression, expecting '}' for modifier "_"
+# expect+1: Unclosed expression, expecting "}" for modifier "_"
UNCLOSED:= ${:U:_
-# expect+1: Unclosed expression, expecting '}' for modifier "gmtime"
+# expect+1: Unclosed expression, expecting "}" for modifier "gmtime"
UNCLOSED:= ${:U:gmtime
-# expect+1: Unclosed expression, expecting '}' for modifier "localtime"
+# expect+1: Unclosed expression, expecting "}" for modifier "localtime"
UNCLOSED:= ${:U:localtime
diff --git a/contrib/bmake/var.c b/contrib/bmake/var.c
index 55d20bd324ac..66b18f769371 100644
--- a/contrib/bmake/var.c
+++ b/contrib/bmake/var.c
@@ -1,4 +1,4 @@
-/* $NetBSD: var.c,v 1.1168 2025/06/13 18:31:08 rillig Exp $ */
+/* $NetBSD: var.c,v 1.1171 2025/06/29 11:02:17 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -143,7 +143,7 @@
#endif
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: var.c,v 1.1168 2025/06/13 18:31:08 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.1171 2025/06/29 11:02:17 rillig Exp $");
/*
* Variables are defined using one of the VAR=value assignments. Their
@@ -452,6 +452,8 @@ VarNew(FStr name, const char *value,
static Substring
CanonicalVarname(Substring name)
{
+ if (Substring_Equals(name, "^"))
+ return Substring_InitStr(ALLSRC);
if (!(Substring_Length(name) > 0 && name.start[0] == '.'))
return name;
@@ -471,8 +473,6 @@ CanonicalVarname(Substring name)
if (Substring_Equals(name, ".TARGET"))
return Substring_InitStr(TARGET);
- /* GNU make has an additional alias $^ == ${.ALLSRC}. */
-
if (Substring_Equals(name, ".SHELL") && shellPath == NULL)
Shell_Init();
@@ -2134,16 +2134,16 @@ typedef enum ApplyModifierResult {
} ApplyModifierResult;
/*
- * Allow backslashes to escape the delimiter, $, and \, but don't touch other
+ * Allow backslashes to escape the delimiters, $, and \, but don't touch other
* backslashes.
*/
static bool
-IsEscapedModifierPart(const char *p, char delim,
+IsEscapedModifierPart(const char *p, char end1, char end2,
struct ModifyWord_SubstArgs *subst)
{
if (p[0] != '\\' || p[1] == '\0')
return false;
- if (p[1] == delim || p[1] == '\\' || p[1] == '$')
+ if (p[1] == end1 || p[1] == end2 || p[1] == '\\' || p[1] == '$')
return true;
return p[1] == '&' && subst != NULL;
}
@@ -2236,7 +2236,7 @@ ParseModifierPart(
LazyBuf_Init(part, p);
while (*p != '\0' && *p != end1 && *p != end2) {
- if (IsEscapedModifierPart(p, end2, subst)) {
+ if (IsEscapedModifierPart(p, end1, end2, subst)) {
LazyBuf_Add(part, p[1]);
p += 2;
} else if (*p != '$') { /* Unescaped, simple text */
@@ -2703,7 +2703,7 @@ ApplyModifier_Range(const char **pp, ModChain *ch)
const char *p = mod + 6;
if (!TryParseSize(&p, &n)) {
Parse_Error(PARSE_FATAL,
- "Invalid number \"%s\" for ':range' modifier",
+ "Invalid number \"%s\" for modifier \":range\"",
mod + 6);
return AMR_CLEANUP;
}
@@ -2834,7 +2834,7 @@ ModifyWord_Match(Substring word, SepBuf *buf, void *data)
if (res.error != NULL && !args->error_reported) {
args->error_reported = true;
Parse_Error(PARSE_FATAL,
- "%s in pattern '%s' of modifier '%s'",
+ "%s in pattern \"%s\" of modifier \"%s\"",
res.error, args->pattern, args->neg ? ":N" : ":M");
}
if (res.matched != args->neg)
@@ -2927,7 +2927,7 @@ ApplyModifier_Mtime(const char **pp, ModChain *ch)
invalid_argument:
Parse_Error(PARSE_FATAL,
- "Invalid argument '%.*s' for modifier ':mtime'",
+ "Invalid argument \"%.*s\" for modifier \":mtime\"",
(int)strcspn(*pp + 1, ":{}()"), *pp + 1);
return AMR_CLEANUP;
}
@@ -2965,7 +2965,7 @@ ApplyModifier_Subst(const char **pp, ModChain *ch)
char delim = (*pp)[1];
if (delim == '\0') {
Parse_Error(PARSE_FATAL,
- "Missing delimiter for modifier ':S'");
+ "Missing delimiter for modifier \":S\"");
(*pp)++;
return AMR_CLEANUP;
}
@@ -3017,7 +3017,7 @@ ApplyModifier_Regex(const char **pp, ModChain *ch)
char delim = (*pp)[1];
if (delim == '\0') {
Parse_Error(PARSE_FATAL,
- "Missing delimiter for modifier ':C'");
+ "Missing delimiter for modifier \":C\"");
(*pp)++;
return AMR_CLEANUP;
}
@@ -3995,7 +3995,7 @@ ApplyModifiersIndirect(ModChain *ch, const char **pp)
else if (*p == '\0' && ch->endc != '\0') {
Parse_Error(PARSE_FATAL,
"Unclosed expression after indirect modifier, "
- "expecting '%c'",
+ "expecting \"%c\"",
ch->endc);
*pp = p;
return AMIR_OUT;
@@ -4051,14 +4051,14 @@ ApplySingleModifier(const char **pp, ModChain *ch)
if (*p == '\0' && ch->endc != '\0') {
Parse_Error(PARSE_FATAL,
- "Unclosed expression, expecting '%c' for "
+ "Unclosed expression, expecting \"%c\" for "
"modifier \"%.*s\"",
ch->endc, (int)(p - mod), mod);
} else if (*p == ':') {
p++;
} else if (opts.strict && *p != '\0' && *p != ch->endc) {
Parse_Error(PARSE_FATAL,
- "Missing delimiter ':' after modifier \"%.*s\"",
+ "Missing delimiter \":\" after modifier \"%.*s\"",
(int)(p - mod), mod);
/*
* TODO: propagate parse error to the enclosing
@@ -4106,7 +4106,7 @@ ApplyModifiers(
if (*p == '\0' && endc != '\0') {
Parse_Error(PARSE_FATAL,
- "Unclosed expression, expecting '%c'", ch.endc);
+ "Unclosed expression, expecting \"%c\"", ch.endc);
goto cleanup;
}
@@ -4263,7 +4263,7 @@ IsShortVarnameValid(char varname, const char *start)
Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
else if (save_dollars)
Parse_Error(PARSE_FATAL,
- "Invalid variable name '%c', at \"%s\"", varname, start);
+ "Invalid variable name \"%c\", at \"%s\"", varname, start);
return false;
}
@@ -4330,7 +4330,7 @@ FindLocalLegacyVar(Substring varname, GNode *scope,
return NULL;
if (varname.start[1] != 'F' && varname.start[1] != 'D')
return NULL;
- if (strchr("@%?*!<>", varname.start[0]) == NULL)
+ if (strchr("@%?*!<>^", varname.start[0]) == NULL)
return NULL;
v = VarFindSubstring(Substring_Init(varname.start, varname.start + 1),
diff --git a/contrib/bsnmp/lib/snmpclient.c b/contrib/bsnmp/lib/snmpclient.c
index b312a37ed3ed..d5d4af998a0c 100644
--- a/contrib/bsnmp/lib/snmpclient.c
+++ b/contrib/bsnmp/lib/snmpclient.c
@@ -981,14 +981,8 @@ open_client_local(const char *path)
char *ptr;
int stype;
- if (snmp_client.chost == NULL) {
- if ((snmp_client.chost = malloc(1 + sizeof(DEFAULT_LOCAL)))
- == NULL) {
- seterr(&snmp_client, "%s", strerror(errno));
- return (-1);
- }
- strcpy(snmp_client.chost, DEFAULT_LOCAL);
- }
+ if (snmp_client.chost == NULL && path == NULL)
+ path = SNMP_DEFAULT_LOCAL;
if (path != NULL) {
if ((ptr = malloc(1 + strlen(path))) == NULL) {
seterr(&snmp_client, "%s", strerror(errno));
@@ -1012,7 +1006,7 @@ open_client_local(const char *path)
snprintf(snmp_client.local_path, sizeof(snmp_client.local_path),
"%s", SNMP_LOCAL_PATH);
- if (mkstemp(snmp_client.local_path) == -1) {
+ if (mktemp(snmp_client.local_path) == NULL) {
seterr(&snmp_client, "%s", strerror(errno));
(void)close(snmp_client.fd);
snmp_client.fd = -1;
diff --git a/contrib/bsnmp/lib/snmpclient.h b/contrib/bsnmp/lib/snmpclient.h
index a19bdb2ea653..662dc7c4a204 100644
--- a/contrib/bsnmp/lib/snmpclient.h
+++ b/contrib/bsnmp/lib/snmpclient.h
@@ -40,6 +40,7 @@
#define SNMP_STRERROR_LEN 200
+#define SNMP_DEFAULT_LOCAL "/var/run/snmpd.sock"
#define SNMP_LOCAL_PATH "/tmp/snmpXXXXXXXXXXXXXX"
diff --git a/contrib/bsnmp/lib/snmppriv.h b/contrib/bsnmp/lib/snmppriv.h
index 5b66992ca985..6ed51cf39369 100644
--- a/contrib/bsnmp/lib/snmppriv.h
+++ b/contrib/bsnmp/lib/snmppriv.h
@@ -44,4 +44,3 @@ enum snmp_code snmp_pdu_decrypt(const struct snmp_pdu *);
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT "snmp"
-#define DEFAULT_LOCAL "/var/run/snmp.sock"
diff --git a/contrib/bsnmp/snmpd/main.c b/contrib/bsnmp/snmpd/main.c
index 928b84121f82..c77572934d24 100644
--- a/contrib/bsnmp/snmpd/main.c
+++ b/contrib/bsnmp/snmpd/main.c
@@ -42,6 +42,7 @@
#include <sys/un.h>
#include <sys/ucred.h>
#include <sys/uio.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -1509,7 +1510,7 @@ main(int argc, char *argv[])
{
int opt;
FILE *fp;
- int background = 1;
+ bool background = true;
struct tport *p;
const char *prefix = "snmpd";
struct lmodule *m;
@@ -1526,11 +1527,6 @@ main(int argc, char *argv[])
NULL
};
- snmp_printf = snmp_printf_func;
- snmp_error = snmp_error_func;
- snmp_debug = snmp_debug_func;
- asn_error = asn_error_func;
-
while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF)
switch (opt) {
@@ -1539,7 +1535,7 @@ main(int argc, char *argv[])
break;
case 'd':
- background = 0;
+ background = false;
break;
case 'D':
@@ -1601,6 +1597,13 @@ main(int argc, char *argv[])
break;
}
+ if (background) {
+ snmp_printf = snmp_printf_func;
+ snmp_error = snmp_error_func;
+ snmp_debug = snmp_debug_func;
+ asn_error = asn_error_func;
+ }
+
openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER);
setlogmask(LOG_UPTO(debug.logpri - 1));
diff --git a/contrib/bsnmp/snmpd/trans_lsock.c b/contrib/bsnmp/snmpd/trans_lsock.c
index fa3bd34d14f0..ca2311be7cc3 100644
--- a/contrib/bsnmp/snmpd/trans_lsock.c
+++ b/contrib/bsnmp/snmpd/trans_lsock.c
@@ -417,7 +417,7 @@ lsock_send(struct tport *tp, const u_char *buf, size_t len,
}
}
- return (sendto(peer->input.fd, buf, len, 0, addr, addrlen));
+ return (sendto(peer->input.fd, buf, len, MSG_NOSIGNAL, addr, addrlen));
}
static void
diff --git a/contrib/elftoolchain/libelf/elf_open.3 b/contrib/elftoolchain/libelf/elf_open.3
index 054036a24935..896bf8455ae5 100644
--- a/contrib/elftoolchain/libelf/elf_open.3
+++ b/contrib/elftoolchain/libelf/elf_open.3
@@ -23,11 +23,12 @@
.\"
.\" $Id: elf_open.3 3743 2019-06-12 19:36:30Z jkoshy $
.\"
-.Dd June 12, 2019
+.Dd July 15, 2025
.Dt ELF_OPEN 3
.Os
.Sh NAME
-.Nm elf_open
+.Nm elf_open ,
+.Nm elf_openmemory
.Nd open ELF objects and ar(1) archives
.Sh LIBRARY
.Lb libelf
diff --git a/contrib/elftoolchain/libelf/gelf_xlatetof.3 b/contrib/elftoolchain/libelf/gelf_xlatetof.3
index 2e5ee0fe15e0..4a7b25c99b5a 100644
--- a/contrib/elftoolchain/libelf/gelf_xlatetof.3
+++ b/contrib/elftoolchain/libelf/gelf_xlatetof.3
@@ -23,13 +23,16 @@
.\"
.\" $Id: gelf_xlatetof.3 3639 2018-10-14 14:07:02Z jkoshy $
.\"
-.Dd October 11, 2018
+.Dd July 15, 2025
.Dt GELF_XLATETOF 3
.Os
.Sh NAME
-.Nm elf32_xlate ,
-.Nm elf64_xlate ,
-.Nm gelf_xlate
+.Nm elf32_xlatetof ,
+.Nm elf32_xlatetom ,
+.Nm elf64_xlatetof ,
+.Nm elf64_xlatetom ,
+.Nm gelf_xlatetof ,
+.Nm gelf_xlatetom
.Nd translate data between files and memory
.Sh LIBRARY
.Lb libelf
diff --git a/contrib/kyua/utils/fs/operations.cpp b/contrib/kyua/utils/fs/operations.cpp
index 7a96d0b2058a..185d164b88d7 100644
--- a/contrib/kyua/utils/fs/operations.cpp
+++ b/contrib/kyua/utils/fs/operations.cpp
@@ -692,6 +692,7 @@ fs::rm_r(const fs::path& directory)
{
const fs::directory dir(directory);
+ ::chmod(directory.c_str(), 0700);
for (fs::directory::const_iterator iter = dir.begin(); iter != dir.end();
++iter) {
if (iter->name == "." || iter->name == "..")
@@ -701,6 +702,7 @@ fs::rm_r(const fs::path& directory)
if (fs::is_directory(entry)) {
LD(F("Descending into %s") % entry);
+ ::chmod(entry.c_str(), 0700);
fs::rm_r(entry);
} else {
LD(F("Removing file %s") % entry);
diff --git a/contrib/kyua/utils/fs/operations_test.cpp b/contrib/kyua/utils/fs/operations_test.cpp
index f1349351166e..6f0fa52811c9 100644
--- a/contrib/kyua/utils/fs/operations_test.cpp
+++ b/contrib/kyua/utils/fs/operations_test.cpp
@@ -664,6 +664,19 @@ ATF_TEST_CASE_BODY(rm_r__files_and_directories)
}
+ATF_TEST_CASE_WITHOUT_HEAD(rm_r__bad_perms);
+ATF_TEST_CASE_BODY(rm_r__bad_perms)
+{
+ fs::mkdir(fs::path("root"), 0755);
+ fs::mkdir(fs::path("root/dir"), 0755);
+ atf::utils::create_file("root/dir/file", "");
+ ::chmod(fs::path("root/dir").c_str(), 0000);
+ ATF_REQUIRE(lookup(".", "root", S_IFDIR));
+ fs::rm_r(fs::path("root"));
+ ATF_REQUIRE(!lookup(".", "root", S_IFDIR));
+}
+
+
ATF_TEST_CASE_WITHOUT_HEAD(rmdir__ok)
ATF_TEST_CASE_BODY(rmdir__ok)
{
@@ -811,6 +824,7 @@ ATF_INIT_TEST_CASES(tcs)
ATF_ADD_TEST_CASE(tcs, rm_r__empty);
ATF_ADD_TEST_CASE(tcs, rm_r__files_and_directories);
+ ATF_ADD_TEST_CASE(tcs, rm_r__bad_perms);
ATF_ADD_TEST_CASE(tcs, rmdir__ok);
ATF_ADD_TEST_CASE(tcs, rmdir__fail);
diff --git a/contrib/less/NEWS b/contrib/less/NEWS
index 5767ded21a00..cdc8196a5f16 100644
--- a/contrib/less/NEWS
+++ b/contrib/less/NEWS
@@ -11,6 +11,16 @@
======================================================================
+ Major changes between "less" versions 678 and 679
+
+* Fix bad parsing of lesskey file an env var is a prefix of another
+ env var (github #626).
+
+* Fix unexpected exit using -K if a key press is received while reading
+ the input file (github #628).
+
+======================================================================
+
Major changes between "less" versions 668 and 678
* Treat -r in LESS environment variable as -R.
diff --git a/contrib/less/decode.c b/contrib/less/decode.c
index 2942a30863cb..8e451d1810c9 100644
--- a/contrib/less/decode.c
+++ b/contrib/less/decode.c
@@ -750,7 +750,7 @@ static int cmd_search(constant char *cmd, constant unsigned char *table, constan
{
action = taction;
*extra = textra;
- } else if (match > 0) /* cmd is a prefix of this table entry */
+ } else if (match > 0 && action == A_INVALID) /* cmd is a prefix of this table entry */
{
action = A_PREFIX;
}
diff --git a/contrib/less/help.c b/contrib/less/help.c
index 81e0943fe4e2..5d8ba9a1b0fe 100644
--- a/contrib/less/help.c
+++ b/contrib/less/help.c
@@ -1,4 +1,4 @@
-/* This file was generated by mkhelp.pl from less.hlp at 20:41 on 2025/5/1 */
+/* This file was generated by mkhelp.pl from less.hlp at 19:46 on 2025/5/28 */
#include "less.h"
constant char helpdata[] = {
'\n',
diff --git a/contrib/less/less.h b/contrib/less/less.h
index 94a3e2235906..7b2d2c25bfc6 100644
--- a/contrib/less/less.h
+++ b/contrib/less/less.h
@@ -575,10 +575,11 @@ typedef enum {
#endif
#endif
-#define S_INTERRUPT 01
-#define S_STOP 02
-#define S_WINCH 04
-#define ABORT_SIGS() (sigs & (S_INTERRUPT|S_STOP))
+#define S_INTERRUPT (1<<0)
+#define S_SWINTERRUPT (1<<1)
+#define S_STOP (1<<2)
+#define S_WINCH (1<<3)
+#define ABORT_SIGS() (sigs & (S_INTERRUPT|S_SWINTERRUPT|S_STOP))
#ifdef EXIT_SUCCESS
#define QUIT_OK EXIT_SUCCESS
diff --git a/contrib/less/less.nro b/contrib/less/less.nro
index 6b74ec5f161b..25a9869a9c59 100644
--- a/contrib/less/less.nro
+++ b/contrib/less/less.nro
@@ -1,5 +1,5 @@
'\" t
-.TH LESS 1 "Version 678: 01 May 2025"
+.TH LESS 1 "Version 679: 28 May 2025"
.SH NAME
less \- display the contents of a file in a terminal
.SH SYNOPSIS
diff --git a/contrib/less/lessecho.nro b/contrib/less/lessecho.nro
index 696fcb13b214..f0cccc4de6da 100644
--- a/contrib/less/lessecho.nro
+++ b/contrib/less/lessecho.nro
@@ -1,4 +1,4 @@
-.TH LESSECHO 1 "Version 678: 01 May 2025"
+.TH LESSECHO 1 "Version 679: 28 May 2025"
.SH NAME
lessecho \- expand metacharacters
.SH SYNOPSIS
diff --git a/contrib/less/lesskey.nro b/contrib/less/lesskey.nro
index 61ba056b04c6..0a17c9deff71 100644
--- a/contrib/less/lesskey.nro
+++ b/contrib/less/lesskey.nro
@@ -1,5 +1,5 @@
'\" t
-.TH LESSKEY 1 "Version 678: 01 May 2025"
+.TH LESSKEY 1 "Version 679: 28 May 2025"
.SH NAME
lesskey \- customize key bindings for less
.SH "SYNOPSIS (deprecated)"
diff --git a/contrib/less/os.c b/contrib/less/os.c
index 98a7ecf70c3c..357cbb356a16 100644
--- a/contrib/less/os.c
+++ b/contrib/less/os.c
@@ -275,7 +275,7 @@ start:
if (ret != 0)
{
if (ret == READ_INTR)
- sigs |= S_INTERRUPT;
+ sigs |= S_SWINTERRUPT;
reading = FALSE;
return (ret);
}
@@ -287,7 +287,7 @@ start:
int c;
c = WIN32getch();
- sigs |= S_INTERRUPT;
+ sigs |= S_SWINTERRUPT;
reading = FALSE;
if (c != CONTROL('C') && c != intr_char)
WIN32ungetch((char) c);
@@ -348,7 +348,7 @@ public int iopen(constant char *filename, int flags)
while (!opening && SET_JUMP(open_label))
{
opening = FALSE;
- if (sigs & S_INTERRUPT)
+ if (sigs & (S_INTERRUPT|S_SWINTERRUPT))
{
sigs = 0;
#if HAVE_SETTABLE_ERRNO
diff --git a/contrib/less/version.c b/contrib/less/version.c
index 9a97f1658940..68a42a6272fa 100644
--- a/contrib/less/version.c
+++ b/contrib/less/version.c
@@ -1047,6 +1047,8 @@ v675 4/3/25 Add ESC-b.
v676 4/16/25 Fix two OSC 8 display bugs.
v677 4/27/25 Fix & filtering bug.
v678 5/1/25 Don't change stty tab setting.
+v679 5/28/25 Fix lesskey parsing bug when env var is prefix of another;
+ fix unexpected exit when using -K.
*/
-char version[] = "678";
+char version[] = "679";
diff --git a/contrib/libbegemot/rpoll.c b/contrib/libbegemot/rpoll.c
index c61b84057eba..f5ce43140205 100644
--- a/contrib/libbegemot/rpoll.c
+++ b/contrib/libbegemot/rpoll.c
@@ -285,8 +285,8 @@ poll_register(int fd, poll_f func, void *arg, int mask)
poll_unblocksig();
if(rpoll_trace)
- fprintf(stderr, "poll_register(%d, %p, %p, %#x)->%tu",
- fd, (void *)func, (void *)arg, mask, p - regs);
+ fprintf(stderr, "%s(%d, %p, %p, %#x)->%tu\n", __func__, fd,
+ (void *)func, (void *)arg, mask, p - regs);
return p - regs;
}
@@ -297,7 +297,7 @@ void
poll_unregister(int handle)
{
if(rpoll_trace)
- fprintf(stderr, "poll_unregister(%d)", handle);
+ fprintf(stderr, "%s(%d)\n", __func__, handle);
poll_blocksig();
@@ -399,8 +399,8 @@ poll_start_utimer(unsigned long long usecs, int repeat, timer_f func, void *arg)
resort = 1;
if(rpoll_trace)
- fprintf(stderr, "poll_start_utimer(%llu, %d, %p, %p)->%tu",
- usecs, repeat, (void *)func, (void *)arg, p - tims);
+ fprintf(stderr, "%s(%llu, %d, %p, %p)->%tu\n", __func__, usecs,
+ repeat, (void *)func, (void *)arg, p - tims);
return p - tims;
}
@@ -418,7 +418,7 @@ poll_stop_timer(int handle)
u_int i;
if(rpoll_trace)
- fprintf(stderr, "poll_stop_timer(%d)", handle);
+ fprintf(stderr, "%s(%d)\n", __func__, handle);
tims[handle].func = NULL;
tims_used--;
@@ -597,9 +597,10 @@ poll_dispatch(int wait)
if(mask) {
if(rpoll_trace)
- fprintf(stderr, "poll_dispatch() -- "
- "file %d/%d %x",
- regs[idx].fd, idx, mask);
+ fprintf(stderr,
+ "%s() -- file %d/%d %x\n",
+ __func__, regs[idx].fd,
+ idx, mask);
(*regs[idx].func)(regs[idx].fd, mask, regs[idx].arg);
}
}
@@ -617,7 +618,8 @@ poll_dispatch(int wait)
if(tims[tfd[i]].when > now)
break;
if(rpoll_trace)
- fprintf(stderr, "rpoll_dispatch() -- timeout %d",tfd[i]);
+ fprintf(stderr, "%s() -- timeout %d\n",
+ __func__, tfd[i]);
(*tims[tfd[i]].func)(tfd[i], tims[tfd[i]].arg);
if(tfd[i] < 0)
continue;
diff --git a/contrib/llvm-project/clang/include/clang/Sema/Sema.h b/contrib/llvm-project/clang/include/clang/Sema/Sema.h
index 7bfdaaae45a9..a59a9342341d 100644
--- a/contrib/llvm-project/clang/include/clang/Sema/Sema.h
+++ b/contrib/llvm-project/clang/include/clang/Sema/Sema.h
@@ -13052,12 +13052,19 @@ public:
/// ForConstraintInstantiation indicates we should continue looking when
/// encountering a lambda generic call operator, and continue looking for
/// arguments on an enclosing class template.
+ ///
+ /// \param SkipForSpecialization when specified, any template specializations
+ /// in a traversal would be ignored.
+ /// \param ForDefaultArgumentSubstitution indicates we should continue looking
+ /// when encountering a specialized member function template, rather than
+ /// returning immediately.
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
bool ForConstraintInstantiation = false,
- bool SkipForSpecialization = false);
+ bool SkipForSpecialization = false,
+ bool ForDefaultArgumentSubstitution = false);
/// RAII object to handle the state changes required to synthesize
/// a function body.
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a09e3be83c45..c2e8ed0c602e 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -269,7 +269,8 @@ HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
MultiLevelTemplateArgumentList &Result,
const FunctionDecl *Pattern, bool RelativeToPrimary,
- bool ForConstraintInstantiation) {
+ bool ForConstraintInstantiation,
+ bool ForDefaultArgumentSubstitution) {
// Add template arguments from a function template specialization.
if (!RelativeToPrimary &&
Function->getTemplateSpecializationKindForInstantiation() ==
@@ -299,7 +300,8 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
// If this function was instantiated from a specialized member that is
// a function template, we're done.
assert(Function->getPrimaryTemplate() && "No function template?");
- if (Function->getPrimaryTemplate()->isMemberSpecialization())
+ if (!ForDefaultArgumentSubstitution &&
+ Function->getPrimaryTemplate()->isMemberSpecialization())
return Response::Done();
// If this function is a generic lambda specialization, we are done.
@@ -465,7 +467,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
const NamedDecl *ND, const DeclContext *DC, bool Final,
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
const FunctionDecl *Pattern, bool ForConstraintInstantiation,
- bool SkipForSpecialization) {
+ bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
@@ -507,7 +509,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
SkipForSpecialization);
} else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
R = HandleFunction(*this, Function, Result, Pattern, RelativeToPrimary,
- ForConstraintInstantiation);
+ ForConstraintInstantiation,
+ ForDefaultArgumentSubstitution);
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
R = HandleRecordDecl(*this, Rec, Result, Context,
ForConstraintInstantiation);
@@ -3231,7 +3234,6 @@ bool Sema::SubstDefaultArgument(
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
std::unique_ptr<LocalInstantiationScope> LIS;
- MultiLevelTemplateArgumentList NewTemplateArgs = TemplateArgs;
if (ForCallExpr) {
// When instantiating a default argument due to use in a call expression,
@@ -3244,19 +3246,10 @@ bool Sema::SubstDefaultArgument(
/*ForDefinition*/ false);
if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs))
return true;
- const FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
- if (PrimaryTemplate && PrimaryTemplate->isOutOfLine()) {
- TemplateArgumentList *CurrentTemplateArgumentList =
- TemplateArgumentList::CreateCopy(getASTContext(),
- TemplateArgs.getInnermost());
- NewTemplateArgs = getTemplateInstantiationArgs(
- FD, FD->getDeclContext(), /*Final=*/false,
- CurrentTemplateArgumentList->asArray(), /*RelativeToPrimary=*/true);
- }
}
runWithSufficientStackSpace(Loc, [&] {
- Result = SubstInitializer(PatternExpr, NewTemplateArgs,
+ Result = SubstInitializer(PatternExpr, TemplateArgs,
/*DirectInit*/ false);
});
}
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a12d2eff1d2c..614e6ea12541 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4659,10 +4659,12 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
- /*Final=*/false, /*Innermost=*/std::nullopt,
- /*RelativeToPrimary=*/true);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ FD, FD->getLexicalDeclContext(),
+ /*Final=*/false, /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
+ /*ForDefaultArgumentSubstitution=*/true);
if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
diff --git a/contrib/sqlite3/INSTALL b/contrib/sqlite3/INSTALL
deleted file mode 100644
index a1e89e18ad20..000000000000
--- a/contrib/sqlite3/INSTALL
+++ /dev/null
@@ -1,370 +0,0 @@
-Installation Instructions
-*************************
-
-Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
-Inc.
-
- 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 warranty of any kind.
-
-Basic Installation
-==================
-
- Briefly, the shell commands `./configure; make; make install' should
-configure, build, and install this package. The following
-more-detailed instructions are generic; see the `README' file for
-instructions specific to this package. Some packages provide this
-`INSTALL' file but do not implement all of the features documented
-below. The lack of an optional feature in a given package is not
-necessarily a bug. More recommendations for GNU packages can be found
-in *note Makefile Conventions: (standards)Makefile Conventions.
-
- The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation. It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
- It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring. Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.
-
- If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
- The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'. You need `configure.ac' if
-you want to change it or regenerate `configure' using a newer version
-of `autoconf'.
-
- The simplest way to compile this package is:
-
- 1. `cd' to the directory containing the package's source code and type
- `./configure' to configure the package for your system.
-
- Running `configure' might take a while. While running, it prints
- some messages telling which features it is checking for.
-
- 2. Type `make' to compile the package.
-
- 3. Optionally, type `make check' to run any self-tests that come with
- the package, generally using the just-built uninstalled binaries.
-
- 4. Type `make install' to install the programs and any data files and
- documentation. When installing into a prefix owned by root, it is
- recommended that the package be configured and built as a regular
- user, and only the `make install' phase executed with root
- privileges.
-
- 5. Optionally, type `make installcheck' to repeat any self-tests, but
- this time using the binaries in their final installed location.
- This target does not install anything. Running this target as a
- regular user, particularly if the prior `make install' required
- root privileges, verifies that the installation completed
- correctly.
-
- 6. You can remove the program binaries and object files from the
- source code directory by typing `make clean'. To also remove the
- files that `configure' created (so you can compile the package for
- a different kind of computer), type `make distclean'. There is
- also a `make maintainer-clean' target, but that is intended mainly
- for the package's developers. If you use it, you may have to get
- all sorts of other programs in order to regenerate files that came
- with the distribution.
-
- 7. Often, you can also type `make uninstall' to remove the installed
- files again. In practice, not all packages have tested that
- uninstallation works correctly, even though it is required by the
- GNU Coding Standards.
-
- 8. Some packages, particularly those that use Automake, provide `make
- distcheck', which can by used by developers to test that all other
- targets like `make install' and `make uninstall' work correctly.
- This target is generally not run by end users.
-
-Compilers and Options
-=====================
-
- Some systems require unusual options for compilation or linking that
-the `configure' script does not know about. Run `./configure --help'
-for details on some of the pertinent environment variables.
-
- You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment. Here
-is an example:
-
- ./configure CC=c99 CFLAGS=-g LIBS=-lposix
-
- *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
- You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory. To do this, you can use GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'. This
-is known as a "VPATH" build.
-
- With a non-GNU `make', it is safer to compile the package for one
-architecture at a time in the source code directory. After you have
-installed the package for one architecture, use `make distclean' before
-reconfiguring for another architecture.
-
- On MacOS X 10.5 and later systems, you can create libraries and
-executables that work on multiple system types--known as "fat" or
-"universal" binaries--by specifying multiple `-arch' options to the
-compiler but only a single `-arch' option to the preprocessor. Like
-this:
-
- ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
- CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
- CPP="gcc -E" CXXCPP="g++ -E"
-
- This is not guaranteed to produce working output in all cases, you
-may have to build one architecture at a time and combine the results
-using the `lipo' tool if you have problems.
-
-Installation Names
-==================
-
- By default, `make install' installs the package's commands under
-`/usr/local/bin', include files under `/usr/local/include', etc. You
-can specify an installation prefix other than `/usr/local' by giving
-`configure' the option `--prefix=PREFIX', where PREFIX must be an
-absolute file name.
-
- You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files. If you
-pass the option `--exec-prefix=PREFIX' to `configure', the package uses
-PREFIX as the prefix for installing programs and libraries.
-Documentation and other data files still use the regular prefix.
-
- In addition, if you use an unusual directory layout you can give
-options like `--bindir=DIR' to specify different values for particular
-kinds of files. Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them. In general, the
-default for these options is expressed in terms of `${prefix}', so that
-specifying just `--prefix' will affect all of the other directory
-specifications that were not explicitly provided.
-
- The most portable way to affect installation locations is to pass the
-correct locations to `configure'; however, many packages provide one or
-both of the following shortcuts of passing variable assignments to the
-`make install' command line to change installation locations without
-having to reconfigure or recompile.
-
- The first method involves providing an override variable for each
-affected directory. For example, `make install
-prefix=/alternate/directory' will choose an alternate location for all
-directory configuration variables that were expressed in terms of
-`${prefix}'. Any directories that were specified during `configure',
-but not in terms of `${prefix}', must each be overridden at install
-time for the entire installation to be relocated. The approach of
-makefile variable overrides for each directory variable is required by
-the GNU Coding Standards, and ideally causes no recompilation.
-However, some platforms have known limitations with the semantics of
-shared libraries that end up requiring recompilation when using this
-method, particularly noticeable in packages that use GNU Libtool.
-
- The second method involves providing the `DESTDIR' variable. For
-example, `make install DESTDIR=/alternate/directory' will prepend
-`/alternate/directory' before all installation names. The approach of
-`DESTDIR' overrides is not required by the GNU Coding Standards, and
-does not work on platforms that have drive letters. On the other hand,
-it does better at avoiding recompilation issues, and works well even
-when some directory options were not specified in terms of `${prefix}'
-at `configure' time.
-
-Optional Features
-=================
-
- If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
- Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System). The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
- For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
- Some packages offer the ability to configure how verbose the
-execution of `make' will be. For these packages, running `./configure
---enable-silent-rules' sets the default to minimal output, which can be
-overridden with `make V=1'; while running `./configure
---disable-silent-rules' sets the default to verbose, which can be
-overridden with `make V=0'.
-
-Particular systems
-==================
-
- On HP-UX, the default C compiler is not ANSI C compatible. If GNU
-CC is not installed, it is recommended to use the following options in
-order to use an ANSI C compiler:
-
- ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
-
-and if that doesn't work, install pre-built binaries of GCC for HP-UX.
-
- HP-UX `make' updates targets which have the same time stamps as
-their prerequisites, which makes it generally unusable when shipped
-generated files such as `configure' are involved. Use GNU `make'
-instead.
-
- On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
-parse its `<wchar.h>' header file. The option `-nodtk' can be used as
-a workaround. If GNU CC is not installed, it is therefore recommended
-to try
-
- ./configure CC="cc"
-
-and if that doesn't work, try
-
- ./configure CC="cc -nodtk"
-
- On Solaris, don't put `/usr/ucb' early in your `PATH'. This
-directory contains several dysfunctional programs; working variants of
-these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
-in your `PATH', put it _after_ `/usr/bin'.
-
- On Haiku, software installed for all users goes in `/boot/common',
-not `/usr/local'. It is recommended to use the following options:
-
- ./configure --prefix=/boot/common
-
-Specifying the System Type
-==========================
-
- There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on. Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
- CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
- OS
- KERNEL-OS
-
- See the file `config.sub' for the possible values of each field. If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
- If you are _building_ compiler tools for cross-compiling, you should
-use the option `--target=TYPE' to select the type of system they will
-produce code for.
-
- If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
- If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists. Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
- Variables not defined in a site shell script can be set in the
-environment passed to `configure'. However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost. In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'. For example:
-
- ./configure CC=/usr/local2/bin/gcc
-
-causes the specified `gcc' to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-Unfortunately, this technique does not work for `CONFIG_SHELL' due to
-an Autoconf bug. Until the bug is fixed you can use this workaround:
-
- CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
-
-`configure' Invocation
-======================
-
- `configure' recognizes the following options to control how it
-operates.
-
-`--help'
-`-h'
- Print a summary of all of the options to `configure', and exit.
-
-`--help=short'
-`--help=recursive'
- Print a summary of the options unique to this package's
- `configure', and exit. The `short' variant lists options used
- only in the top level, while the `recursive' variant lists options
- also present in any nested packages.
-
-`--version'
-`-V'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`--cache-file=FILE'
- Enable the cache: use and save the results of the tests in FILE,
- traditionally `config.cache'. FILE defaults to `/dev/null' to
- disable caching.
-
-`--config-cache'
-`-C'
- Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
- Do not print messages saying which checks are being made. To
- suppress all normal output, redirect it to `/dev/null' (any error
- messages will still be shown).
-
-`--srcdir=DIR'
- Look for the package's source code in directory DIR. Usually
- `configure' can determine that directory automatically.
-
-`--prefix=DIR'
- Use DIR as the installation prefix. *note Installation Names::
- for more details, including other options available for fine-tuning
- the installation locations.
-
-`--no-create'
-`-n'
- Run the configure checks, but stop before creating any output
- files.
-
-`configure' also accepts some other, not widely useful, options. Run
-`configure --help' for more details.
-
diff --git a/contrib/sqlite3/Makefile.am b/contrib/sqlite3/Makefile.am
deleted file mode 100644
index 09f83086b1ea..000000000000
--- a/contrib/sqlite3/Makefile.am
+++ /dev/null
@@ -1,19 +0,0 @@
-AM_CFLAGS = @BUILD_CFLAGS@
-lib_LTLIBRARIES = libsqlite3.la
-libsqlite3_la_SOURCES = sqlite3.c
-libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8
-
-bin_PROGRAMS = sqlite3
-sqlite3_SOURCES = shell.c sqlite3.h
-EXTRA_sqlite3_SOURCES = sqlite3.c
-sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
-sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
-sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_DQS=0 -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS)
-
-include_HEADERS = sqlite3.h sqlite3ext.h
-
-EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc sqlite3rc.h README.txt Replace.cs Makefile.fallback
-pkgconfigdir = ${libdir}/pkgconfig
-pkgconfig_DATA = sqlite3.pc
-
-man_MANS = sqlite3.1
diff --git a/contrib/sqlite3/Makefile.in b/contrib/sqlite3/Makefile.in
index fe708a0a9d84..a77386faed7c 100644
--- a/contrib/sqlite3/Makefile.in
+++ b/contrib/sqlite3/Makefile.in
@@ -1,1050 +1,298 @@
-# Makefile.in generated by automake 1.16.5 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2021 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@
-
+########################################################################
+# This is a main makefile for the "autoconf" bundle of SQLite. This is
+# a trimmed-down version of the canonical makefile, devoid of most
+# documentation. For the full docs, see /main.mk in the canonical
+# source tree.
+#
+# Maintenance reminders:
+#
+# - To keep this working with an out-of-tree build, be sure to prefix
+# input file names with $(TOP)/ where appropriate (which is most
+# places).
+#
+# - The original/canonical recipes can be found in /main.mk in the
+# canonical source tree.
+all:
+
+TOP = @abs_top_srcdir@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+#
+# Filename extensions for binaries and libraries
+#
+B.exe = @BUILD_EXEEXT@
+T.exe = @TARGET_EXEEXT@
+B.dll = @BUILD_DLLEXT@
+T.dll = @TARGET_DLLEXT@
+B.lib = @BUILD_LIBEXT@
+T.lib = @TARGET_LIBEXT@
+
+#
+# Autotools-compatibility dirs
+#
+prefix = @prefix@
+datadir = @datadir@
+mandir = @mandir@
+includedir = @includedir@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
-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 = sqlite3$(EXEEXT)
-subdir = .
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
- $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
- $(am__configure_deps) $(include_HEADERS) $(am__DIST_COMMON)
-am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
- configure.lineno config.status.lineno
-mkinstalldirs = $(install_sh) -d
-CONFIG_CLEAN_FILES = sqlite3.pc
-CONFIG_CLEAN_VPATH_FILES =
-am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" \
- "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(pkgconfigdir)" \
- "$(DESTDIR)$(includedir)"
-PROGRAMS = $(bin_PROGRAMS)
-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; }; \
- }
-LTLIBRARIES = $(lib_LTLIBRARIES)
-libsqlite3_la_LIBADD =
-am_libsqlite3_la_OBJECTS = sqlite3.lo
-libsqlite3_la_OBJECTS = $(am_libsqlite3_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 =
-libsqlite3_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(libsqlite3_la_LDFLAGS) $(LDFLAGS) -o $@
-am_sqlite3_OBJECTS = sqlite3-shell.$(OBJEXT)
-sqlite3_OBJECTS = $(am_sqlite3_OBJECTS)
-sqlite3_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
- $(LIBTOOLFLAGS) --mode=link $(CCLD) $(sqlite3_CFLAGS) \
- $(CFLAGS) $(AM_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@
-depcomp = $(SHELL) $(top_srcdir)/depcomp
-am__maybe_remake_depfiles = depfiles
-am__depfiles_remade = ./$(DEPDIR)/sqlite3-shell.Po \
- ./$(DEPDIR)/sqlite3-sqlite3.Po ./$(DEPDIR)/sqlite3.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 = $(libsqlite3_la_SOURCES) $(sqlite3_SOURCES) \
- $(EXTRA_sqlite3_SOURCES)
-DIST_SOURCES = $(libsqlite3_la_SOURCES) $(sqlite3_SOURCES) \
- $(EXTRA_sqlite3_SOURCES)
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
-man1dir = $(mandir)/man1
-NROFF = nroff
-MANS = $(man_MANS)
-DATA = $(pkgconfig_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)`
-AM_RECURSIVE_TARGETS = cscope
-am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/sqlite3.pc.in \
- INSTALL compile config.guess config.sub depcomp install-sh \
- ltmain.sh 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)
-DIST_ARCHIVES = $(distdir).tar.gz
-GZIP_ENV = --best
-DIST_TARGETS = dist-gzip
-# Exists only to be overridden by the user if desired.
-AM_DISTCHECK_DVI_TARGET = dvi
-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_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+#
+# Required binaries
+#
+INSTALL = @BIN_INSTALL@
AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-BUILD_CFLAGS = @BUILD_CFLAGS@
+AR.flags = cr
CC = @CC@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPPFLAGS = @CPPFLAGS@
-CSCOPE = @CSCOPE@
-CTAGS = @CTAGS@
-CYGPATH_W = @CYGPATH_W@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-ETAGS = @ETAGS@
-EXEEXT = @EXEEXT@
-EXTRA_SHELL_OBJ = @EXTRA_SHELL_OBJ@
-FGREP = @FGREP@
-GREP = @GREP@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-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@
-READLINE_LIBS = @READLINE_LIBS@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SHELL_CFLAGS = @SHELL_CFLAGS@
-STRIP = @STRIP@
-VERSION = @VERSION@
-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_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@
-AM_CFLAGS = @BUILD_CFLAGS@
-lib_LTLIBRARIES = libsqlite3.la
-libsqlite3_la_SOURCES = sqlite3.c
-libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8
-sqlite3_SOURCES = shell.c sqlite3.h
-EXTRA_sqlite3_SOURCES = sqlite3.c
-sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
-sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
-sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_DQS=0 -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS)
-include_HEADERS = sqlite3.h sqlite3ext.h
-EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc sqlite3rc.h README.txt Replace.cs Makefile.fallback
-pkgconfigdir = ${libdir}/pkgconfig
-pkgconfig_DATA = sqlite3.pc
-man_MANS = sqlite3.1
-all: all-am
-
-.SUFFIXES:
-.SUFFIXES: .c .lo .o .obj
-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):
-sqlite3.pc: $(top_builddir)/config.status $(srcdir)/sqlite3.pc.in
- cd $(top_builddir) && $(SHELL) ./config.status $@
-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
-
-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}; \
- }
-
-libsqlite3.la: $(libsqlite3_la_OBJECTS) $(libsqlite3_la_DEPENDENCIES) $(EXTRA_libsqlite3_la_DEPENDENCIES)
- $(AM_V_CCLD)$(libsqlite3_la_LINK) -rpath $(libdir) $(libsqlite3_la_OBJECTS) $(libsqlite3_la_LIBADD) $(LIBS)
-
-sqlite3$(EXEEXT): $(sqlite3_OBJECTS) $(sqlite3_DEPENDENCIES) $(EXTRA_sqlite3_DEPENDENCIES)
- @rm -f sqlite3$(EXEEXT)
- $(AM_V_CCLD)$(sqlite3_LINK) $(sqlite3_OBJECTS) $(sqlite3_LDADD) $(LIBS)
-
-mostlyclean-compile:
- -rm -f *.$(OBJEXT)
-
-distclean-compile:
- -rm -f *.tab.c
-
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlite3-shell.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlite3-sqlite3.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlite3.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 $@ $<
-
-sqlite3-shell.o: shell.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sqlite3_CFLAGS) $(CFLAGS) -MT sqlite3-shell.o -MD -MP -MF $(DEPDIR)/sqlite3-shell.Tpo -c -o sqlite3-shell.o `test -f 'shell.c' || echo '$(srcdir)/'`shell.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sqlite3-shell.Tpo $(DEPDIR)/sqlite3-shell.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='shell.c' object='sqlite3-shell.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) $(AM_CPPFLAGS) $(CPPFLAGS) $(sqlite3_CFLAGS) $(CFLAGS) -c -o sqlite3-shell.o `test -f 'shell.c' || echo '$(srcdir)/'`shell.c
-
-sqlite3-shell.obj: shell.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sqlite3_CFLAGS) $(CFLAGS) -MT sqlite3-shell.obj -MD -MP -MF $(DEPDIR)/sqlite3-shell.Tpo -c -o sqlite3-shell.obj `if test -f 'shell.c'; then $(CYGPATH_W) 'shell.c'; else $(CYGPATH_W) '$(srcdir)/shell.c'; fi`
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sqlite3-shell.Tpo $(DEPDIR)/sqlite3-shell.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='shell.c' object='sqlite3-shell.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) $(AM_CPPFLAGS) $(CPPFLAGS) $(sqlite3_CFLAGS) $(CFLAGS) -c -o sqlite3-shell.obj `if test -f 'shell.c'; then $(CYGPATH_W) 'shell.c'; else $(CYGPATH_W) '$(srcdir)/shell.c'; fi`
-
-sqlite3-sqlite3.o: sqlite3.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sqlite3_CFLAGS) $(CFLAGS) -MT sqlite3-sqlite3.o -MD -MP -MF $(DEPDIR)/sqlite3-sqlite3.Tpo -c -o sqlite3-sqlite3.o `test -f 'sqlite3.c' || echo '$(srcdir)/'`sqlite3.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sqlite3-sqlite3.Tpo $(DEPDIR)/sqlite3-sqlite3.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sqlite3.c' object='sqlite3-sqlite3.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) $(AM_CPPFLAGS) $(CPPFLAGS) $(sqlite3_CFLAGS) $(CFLAGS) -c -o sqlite3-sqlite3.o `test -f 'sqlite3.c' || echo '$(srcdir)/'`sqlite3.c
-
-sqlite3-sqlite3.obj: sqlite3.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sqlite3_CFLAGS) $(CFLAGS) -MT sqlite3-sqlite3.obj -MD -MP -MF $(DEPDIR)/sqlite3-sqlite3.Tpo -c -o sqlite3-sqlite3.obj `if test -f 'sqlite3.c'; then $(CYGPATH_W) 'sqlite3.c'; else $(CYGPATH_W) '$(srcdir)/sqlite3.c'; fi`
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sqlite3-sqlite3.Tpo $(DEPDIR)/sqlite3-sqlite3.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sqlite3.c' object='sqlite3-sqlite3.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) $(AM_CPPFLAGS) $(CPPFLAGS) $(sqlite3_CFLAGS) $(CFLAGS) -c -o sqlite3-sqlite3.obj `if test -f 'sqlite3.c'; then $(CYGPATH_W) 'sqlite3.c'; else $(CYGPATH_W) '$(srcdir)/sqlite3.c'; fi`
-
-mostlyclean-libtool:
- -rm -f *.lo
-
-clean-libtool:
- -rm -rf .libs _libs
-
-distclean-libtool:
- -rm -f libtool config.lt
-install-man1: $(man_MANS)
- @$(NORMAL_INSTALL)
- @list1=''; \
- list2='$(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='$(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)
-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
-
-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)
-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"
-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-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
- -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
-distdir: $(BUILT_SOURCES)
- $(MAKE) $(AM_MAKEFLAGS) distdir-am
-
-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
- -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)
-
-dist-zstd: distdir
- tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst
- $(am__post_remove_distdir)
-
-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)
-
-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)
-
-dist-zip: distdir
- -rm -f $(distdir).zip
- zip -rq $(distdir).zip $(distdir)
- $(am__post_remove_distdir)
-
-dist dist-all:
- $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
- $(am__post_remove_distdir)
-
-# 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) $(AM_DISTCHECK_DVI_TARGET) \
- && $(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 ; \
+ENABLE_LIB_SHARED = @ENABLE_LIB_SHARED@
+ENABLE_LIB_STATIC = @ENABLE_LIB_STATIC@
+HAVE_WASI_SDK = @HAVE_WASI_SDK@
+
+CFLAGS = @CFLAGS@ @CPPFLAGS@
+#
+# $(LDFLAGS.configure) represents any LDFLAGS=... the client passes to
+# configure. See main.mk.
+#
+LDFLAGS.configure = @LDFLAGS@
+
+CFLAGS.core = @SH_CFLAGS@
+LDFLAGS.shlib = @SH_LDFLAGS@
+LDFLAGS.zlib = @LDFLAGS_ZLIB@
+LDFLAGS.math = @LDFLAGS_MATH@
+LDFLAGS.rpath = @LDFLAGS_RPATH@
+LDFLAGS.pthread = @LDFLAGS_PTHREAD@
+LDFLAGS.dlopen = @LDFLAGS_DLOPEN@
+LDFLAGS.readline = @LDFLAGS_READLINE@
+CFLAGS.readline = @CFLAGS_READLINE@
+LDFLAGS.rt = @LDFLAGS_RT@
+LDFLAGS.icu = @LDFLAGS_ICU@
+CFLAGS.icu = @CFLAGS_ICU@
+
+# INSTALL reminder: we specifically do not strip binaries,
+# as discussed in https://sqlite.org/forum/forumpost/9a67df63eda9925c.
+INSTALL.noexec = $(INSTALL) -m 0644
+
+install-dir.bin = $(DESTDIR)$(bindir)
+install-dir.lib = $(DESTDIR)$(libdir)
+install-dir.include = $(DESTDIR)$(includedir)
+install-dir.pkgconfig = $(DESTDIR)$(libdir)/pkgconfig
+install-dir.man1 = $(DESTDIR)$(mandir)/man1
+install-dir.all = $(install-dir.bin) $(install-dir.include) \
+ $(install-dir.lib) $(install-dir.man1) \
+ $(install-dir.pkgconfig)
+$(install-dir.all):
+ @if [ ! -d "$@" ]; then set -x; $(INSTALL) -d "$@"; fi
+# ^^^^ on some platforms, install -d fails if the target already exists.
+
+
+#
+# Vars with the AS_ prefix are specifically related to AutoSetup.
+#
+# AS_AUTO_DEF is the main configure script.
+#
+AS_AUTO_DEF = $(TOP)/auto.def
+
+#
+# Shell commands to re-run $(TOP)/configure with the same args it was
+# invoked with to produce this makefile.
+#
+AS_AUTORECONFIG = @SQLITE_AUTORECONFIG@
+Makefile: $(TOP)/Makefile.in $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+
+sqlite3.pc: $(TOP)/sqlite3.pc.in $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+
+sqlite_cfg.h: $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+
+#
+# CFLAGS for sqlite3$(T.exe)
+#
+SHELL_OPT ?= @OPT_SHELL@
+
+#
+# Library-level feature flags
+#
+OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@
+
+LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@
+# soname: see https://sqlite.org/src/forumpost/5a3b44f510df8ded
+LDFLAGS.libsqlite3.os-specific = \
+ @LDFLAGS_MAC_CVERSION@ @LDFLAGS_MAC_INSTALL_NAME@ @LDFLAGS_OUT_IMPLIB@
+
+LDFLAGS.libsqlite3 = \
+ $(LDFLAGS.rpath) $(LDFLAGS.pthread) \
+ $(LDFLAGS.math) $(LDFLAGS.dlopen) \
+ $(LDFLAGS.zlib) $(LDFLAGS.icu) \
+ $(LDFLAGS.rt) $(LDFLAGS.configure)
+CFLAGS.libsqlite3 = -I. $(CFLAGS.core) $(CFLAGS.icu) $(OPT_FEATURE_FLAGS)
+
+sqlite3.o: $(TOP)/sqlite3.h $(TOP)/sqlite3.c
+ $(CC) -c $(TOP)/sqlite3.c -o $@ $(CFLAGS) $(CFLAGS.libsqlite3)
+
+libsqlite3.LIB = libsqlite3$(T.lib)
+libsqlite3.DLL.basename = @SQLITE_DLL_BASENAME@
+libsqlite3.out.implib = @SQLITE_OUT_IMPLIB@
+libsqlite3.DLL = $(libsqlite3.DLL.basename)$(T.dll)
+libsqlite3.DLL.install-rules = @SQLITE_DLL_INSTALL_RULES@
+
+$(libsqlite3.DLL): sqlite3.o
+ $(CC) -o $@ sqlite3.o $(LDFLAGS.shlib) \
+ $(LDFLAGS) $(LDFLAGS.libsqlite3) \
+ $(LDFLAGS.libsqlite3.os-specific) $(LDFLAGS.libsqlite3.soname)
+$(libsqlite3.DLL)-1: $(libsqlite3.DLL)
+$(libsqlite3.DLL)-0:
+all: $(libsqlite3.DLL)-$(ENABLE_LIB_SHARED)
+
+$(libsqlite3.LIB): sqlite3.o
+ $(AR) $(AR.flags) $@ sqlite3.o
+$(libsqlite3.LIB)-1: $(libsqlite3.LIB)
+$(libsqlite3.LIB)-0:
+all: $(libsqlite3.LIB)-$(ENABLE_LIB_STATIC)
+
+#
+# Maintenance reminder: the install-dll-... rules must be kept in sync
+# with the main copies rom /main.mk.
+#
+install-dll-out-implib: $(install-dir.lib) $(libsqlite3.DLL)
+ if [ x != "x$(libsqlite3.out.implib)" ] && [ -f "$(libsqlite3.out.implib)" ]; then \
+ $(INSTALL) $(libsqlite3.out.implib) "$(install-dir.lib)"; \
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-am
-all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(MANS) $(DATA) $(HEADERS)
-install-binPROGRAMS: install-libLTLIBRARIES
-installdirs:
- for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(pkgconfigdir)" "$(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; \
+install-dll-unix-generic: install-dll-out-implib
+ $(INSTALL) $(libsqlite3.DLL) "$(install-dir.lib)"
+ @echo "Setting up $(libsqlite3.DLL) version symlinks..."; \
+ cd "$(install-dir.lib)" || exit $$?; \
+ rm -f $(libsqlite3.DLL).0 $(libsqlite3.DLL).$(PACKAGE_VERSION) || exit $$?; \
+ mv $(libsqlite3.DLL) $(libsqlite3.DLL).$(PACKAGE_VERSION) || exit $$?; \
+ ln -s $(libsqlite3.DLL).$(PACKAGE_VERSION) $(libsqlite3.DLL) || exit $$?; \
+ ln -s $(libsqlite3.DLL).$(PACKAGE_VERSION) $(libsqlite3.DLL).0 || exit $$?; \
+ ls -la $(libsqlite3.DLL) $(libsqlite3.DLL).[a03]*; \
+ if [ -e $(libsqlite3.DLL).0.8.6 ]; then \
+ echo "ACHTUNG: legacy libtool-compatible install found. Re-linking it..."; \
+ rm -f libsqlite3.la $(libsqlite3.DLL).0.8.6 || exit $$?; \
+ ln -s $(libsqlite3.DLL).$(PACKAGE_VERSION) $(libsqlite3.DLL).0.8.6 || exit $$?; \
+ ls -la $(libsqlite3.DLL).0.8.6; \
+ elif [ x1 = "x$(INSTALL_SO_086_LINK)" ]; then \
+ echo "ACHTUNG: installing legacy libtool-style links because INSTALL_SO_086_LINK=1"; \
+ rm -f libsqlite3.la $(libsqlite3.DLL).0.8.6 || exit $$?; \
+ ln -s $(libsqlite3.DLL).$(PACKAGE_VERSION) $(libsqlite3.DLL).0.8.6 || exit $$?; \
+ ls -la $(libsqlite3.DLL).0.8.6; \
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-libLTLIBRARIES \
- clean-libtool mostlyclean-am
-
-distclean: distclean-am
- -rm -f $(am__CONFIG_DISTCLEAN_FILES)
- -rm -f ./$(DEPDIR)/sqlite3-shell.Po
- -rm -f ./$(DEPDIR)/sqlite3-sqlite3.Po
- -rm -f ./$(DEPDIR)/sqlite3.Plo
- -rm -f Makefile
-distclean-am: clean-am distclean-compile distclean-generic \
- distclean-libtool distclean-tags
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am: install-includeHEADERS install-man \
- install-pkgconfigDATA
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man: install-man1
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
- -rm -f $(am__CONFIG_DISTCLEAN_FILES)
- -rm -rf $(top_srcdir)/autom4te.cache
- -rm -f ./$(DEPDIR)/sqlite3-shell.Po
- -rm -f ./$(DEPDIR)/sqlite3-sqlite3.Po
- -rm -f ./$(DEPDIR)/sqlite3.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-binPROGRAMS uninstall-includeHEADERS \
- uninstall-libLTLIBRARIES uninstall-man uninstall-pkgconfigDATA
-
-uninstall-man: uninstall-man1
-
-.MAKE: install-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles am--refresh check \
- check-am clean clean-binPROGRAMS clean-cscope clean-generic \
- clean-libLTLIBRARIES 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-compile distclean-generic \
- distclean-libtool distclean-tags distcleancheck distdir \
- distuninstallcheck dvi dvi-am html html-am info info-am \
- install install-am install-binPROGRAMS install-data \
- install-data-am install-dvi install-dvi-am install-exec \
- install-exec-am install-html install-html-am \
- install-includeHEADERS install-info install-info-am \
- install-libLTLIBRARIES install-man install-man1 install-pdf \
- install-pdf-am install-pkgconfigDATA install-ps install-ps-am \
- install-strip installcheck installcheck-am installdirs \
- maintainer-clean maintainer-clean-generic mostlyclean \
- mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
- pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
- uninstall-binPROGRAMS uninstall-includeHEADERS \
- uninstall-libLTLIBRARIES uninstall-man uninstall-man1 \
- uninstall-pkgconfigDATA
-
-.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:
+install-dll-msys: install-dll-out-implib $(install-dir.bin)
+ $(INSTALL) $(libsqlite3.DLL) "$(install-dir.bin)"
+# ----------------------------------------------^^^ yes, bin
+# Each of {msys,mingw,cygwin} uses a different name for the DLL, but
+# that is already accounted for via $(libsqlite3.DLL).
+install-dll-mingw: install-dll-msys
+install-dll-cygwin: install-dll-msys
+
+install-dll-darwin: $(install-dir.lib) $(libsqlite3.DLL)
+ $(INSTALL) $(libsqlite3.DLL) "$(install-dir.lib)"
+ @echo "Setting up $(libsqlite3.DLL) version symlinks..."; \
+ cd "$(install-dir.lib)" || exit $$?; \
+ rm -f libsqlite3.0$(T.dll) libsqlite3.$(PACKAGE_VERSION)$(T.dll) || exit $$?; \
+ dllname=libsqlite3.$(PACKAGE_VERSION)$(T.dll); \
+ mv $(libsqlite3.DLL) $$dllname || exit $$?; \
+ ln -s $$dllname $(libsqlite3.DLL) || exit $$?; \
+ ln -s $$dllname libsqlite3.0$(T.dll) || exit $$?; \
+ ls -la $$dllname $(libsqlite3.DLL) libsqlite3.0$(T.dll)
+
+install-dll-1: install-dll-$(libsqlite3.DLL.install-rules)
+install-dll-0 install-dll-:
+install-dll: install-dll-$(ENABLE_LIB_SHARED)
+install: install-dll
+
+install-lib-1: $(install-dir.lib) $(libsqlite3.LIB)
+ $(INSTALL.noexec) $(libsqlite3.LIB) "$(install-dir.lib)"
+install-lib-0 install-lib-:
+install-lib: install-lib-$(ENABLE_LIB_STATIC)
+install: install-lib
+
+#
+# Flags to link the shell app either directly against sqlite3.c
+# (ENABLE_STATIC_SHELL==1) or libsqlite3.so (ENABLE_STATIC_SHELL==0).
+#
+ENABLE_STATIC_SHELL = @ENABLE_STATIC_SHELL@
+sqlite3-shell-link-flags.1 = $(TOP)/sqlite3.c $(LDFLAGS.libsqlite3)
+sqlite3-shell-link-flags.0 = -L. -lsqlite3 $(LDFLAGS.zlib) $(LDFLAGS.math)
+sqlite3-shell-deps.1 = $(TOP)/sqlite3.c
+sqlite3-shell-deps.0 = $(libsqlite3.DLL)
+#
+# STATIC_CLI_SHELL = 1 to statically link sqlite3$(T.exe), else
+# 0. Requires static versions of all requisite libraries. Primarily
+# intended for use with static-friendly environments like Alpine
+# Linux.
+#
+STATIC_CLI_SHELL = @STATIC_CLI_SHELL@
+#
+# sqlite3-shell-static.flags.N = N is $(STATIC_CLI_SHELL)
+#
+sqlite3-shell-static.flags.1 = -static
+sqlite3-shell-static.flags.0 =
+sqlite3$(T.exe): $(TOP)/shell.c $(sqlite3-shell-deps.$(ENABLE_STATIC_SHELL))
+ $(CC) -o $@ \
+ $(TOP)/shell.c $(sqlite3-shell-link-flags.$(ENABLE_STATIC_SHELL)) \
+ $(sqlite3-shell-static.flags.$(STATIC_CLI_SHELL)) \
+ -I. $(OPT_FEATURE_FLAGS) $(SHELL_OPT) \
+ $(CFLAGS) $(CFLAGS.readline) $(CFLAGS.icu) \
+ $(LDFLAGS) $(LDFLAGS.readline)
+
+sqlite3$(T.exe)-1:
+sqlite3$(T.exe)-0: sqlite3$(T.exe)
+all: sqlite3$(T.exe)-$(HAVE_WASI_SDK)
+
+install-shell-0: sqlite3$(T.exe) $(install-dir.bin)
+ $(INSTALL) sqlite3$(T.exe) "$(install-dir.bin)"
+install-shell-1:
+install: install-shell-$(HAVE_WASI_SDK)
+
+install-headers: $(TOP)/sqlite3.h $(install-dir.include)
+ $(INSTALL.noexec) $(TOP)/sqlite3.h $(TOP)/sqlite3ext.h "$(install-dir.include)"
+install: install-headers
+
+install-pc: sqlite3.pc $(install-dir.pkgconfig)
+ $(INSTALL.noexec) sqlite3.pc "$(install-dir.pkgconfig)"
+install: install-pc
+
+install-man1: $(TOP)/sqlite3.1 $(install-dir.man1)
+ $(INSTALL.noexec) $(TOP)/sqlite3.1 "$(install-dir.man1)"
+install: install-man1
+
+clean:
+ rm -f *.o sqlite3$(T.exe)
+ rm -f $(libsqlite3.LIB) $(libsqlite3.DLL) libsqlite3$(T.dll).a
+
+distclean: clean
+ rm -f jimsh0$(T.exe) config.* sqlite3.pc sqlite_cfg.h Makefile
+
+DIST_FILES := \
+ README.txt VERSION \
+ auto.def autosetup configure tea \
+ sqlite3.h sqlite3.c shell.c sqlite3ext.h \
+ Makefile.in Makefile.msc Makefile.fallback \
+ sqlite3.rc sqlite3rc.h Replace.cs \
+ sqlite3.pc.in sqlite3.1
+
+#
+# Maintenance note: dist_name must be sqlite-$(PACKAGE_VERSION) so
+# that tool/mkautoconfamal.sh knows how to find it.
+#
+dist_name = sqlite-$(PACKAGE_VERSION)
+dist_tarball = $(dist_name).tar.gz
+dist:
+ rm -fr $(dist_name)
+ mkdir -p $(dist_name)
+ cp -rp $(DIST_FILES) $(dist_name)/.
+ tar czf $(dist_tarball) $(dist_name)
+ rm -fr $(dist_name)
+ ls -l $(dist_tarball)
diff --git a/contrib/sqlite3/Makefile.msc b/contrib/sqlite3/Makefile.msc
index a4270fb2ae71..dfa2dcfd5bdc 100644
--- a/contrib/sqlite3/Makefile.msc
+++ b/contrib/sqlite3/Makefile.msc
@@ -19,7 +19,9 @@ TOP = .
# Optionally set EXTRA_SRC to a list of C files to append to
-# the generated sqlite3.c.
+# the generated sqlite3.c. Any sqlite3 extensions added this
+# way may require manual editing, as described in
+# https://sqlite.org/forum/forumpost/903f721f3e7c0d25
#
!IFNDEF EXTRA_SRC
EXTRA_SRC =
@@ -66,6 +68,14 @@ USE_STDCALL = 0
USE_SEH = 1
!ENDIF
+# Use STATICALLY_LINK_TCL=1 to statically link against TCL
+#
+!IFNDEF STATICALLY_LINK_TCL
+STATICALLY_LINK_TCL = 0
+!ELSEIF $(STATICALLY_LINK_TCL)!=0
+CCOPTS = $(CCOPTS) -DSTATIC_BUILD
+!ENDIF
+
# Set this non-0 to have the shell executable link against the core dynamic
# link library.
#
@@ -237,6 +247,12 @@ SESSION = 0
RBU = 0
!ENDIF
+# Set this to non-0 to enable support for blocking locks.
+#
+!IFNDEF SETLK_TIMEOUT
+SETLK_TIMEOUT = 0
+!ENDIF
+
# Set the source code file to be used by executables and libraries when
# they need the amalgamation.
#
@@ -301,6 +317,7 @@ SQLITE3EXEPDB = /pdb:sqlite3sh.pdb
# the Windows platform.
#
!IFNDEF OPT_FEATURE_FLAGS
+OPT_FEATURE_FLAGS = $(OPT_XTRA)
!IF $(MINIMAL_AMALGAMATION)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5=1
@@ -314,6 +331,14 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
!ENDIF
+# Additional feature-options above and beyond what are normally used can be
+# be added using OPTIONS=.... on the command-line. These values are
+# appended to the OPT_FEATURE_FLAGS variable.
+#
+!IFDEF OPTIONS
+OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) $(OPTIONS)
+!ENDIF
+
# Should the session extension be enabled? If so, add compilation options
# to enable it.
#
@@ -353,6 +378,10 @@ EXT_FEATURE_FLAGS =
!ENDIF
!ENDIF
+!IF $(SETLK_TIMEOUT)!=0
+OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SETLK_TIMEOUT
+!ENDIF
+
###############################################################################
############################### END OF OPTIONS ################################
###############################################################################
@@ -695,7 +724,7 @@ RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
!ENDIF
!IF $(DEBUG)>2
-TCC = $(TCC) -DSQLITE_DEBUG=1
+TCC = $(TCC) -DSQLITE_DEBUG=1 -DSQLITE_USE_W32_FOR_CONSOLE_IO
RCC = $(RCC) -DSQLITE_DEBUG=1
!IF $(DYNAMIC_SHELL)==0
TCC = $(TCC) -DSQLITE_ENABLE_WHERETRACE -DSQLITE_ENABLE_SELECTTRACE
@@ -782,15 +811,6 @@ RCC = $(RCC) -DSQLITE_THREAD_OVERRIDE_LOCK=-1
TLIBS =
!ENDIF
-# Flags controlling use of the in memory btree implementation
-#
-# SQLITE_TEMP_STORE is 0 to force temporary tables to be in a file, 1 to
-# default to file, 2 to default to memory, and 3 to force temporary
-# tables to always be in memory.
-#
-TCC = $(TCC) -DSQLITE_TEMP_STORE=1
-RCC = $(RCC) -DSQLITE_TEMP_STORE=1
-
# Enable/disable loadable extensions, and other optional features
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
# The same set of OMIT and ENABLE flags should be passed to the
@@ -1022,6 +1042,11 @@ dll: $(SQLITE3DLL)
#
shell: $(SQLITE3EXE)
+# jimsh0 - replacement for tclsh
+#
+jimsh0.exe: $(TOP)\autosetup\jimsh0.c
+ cl -DHAVE__FULLPATH=1 $(TOP)\autosetup\jimsh0.c
+
$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
@@ -1072,5 +1097,6 @@ $(LIBRESOBJS): $(TOP)\sqlite3.rc rcver.vc $(SQLITE3H)
clean:
del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
- del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q sqlite3.def tclsqlite3.def ctime.c pragma.h 2>NUL
del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
diff --git a/contrib/sqlite3/README.txt b/contrib/sqlite3/README.txt
index ccf5e235ac93..ca0ed20fd4a3 100644
--- a/contrib/sqlite3/README.txt
+++ b/contrib/sqlite3/README.txt
@@ -4,13 +4,44 @@ This package contains:
* the sqlite3.h and sqlite3ext.h header files that define the C-language
interface to the sqlite3.c library file
* the shell.c file used to build the sqlite3 command-line shell program
- * autoconf/automake installation infrastucture for building on POSIX
+ * autoconf-like installation infrastucture for building on POSIX
compliant systems
* a Makefile.msc, sqlite3.rc, and Replace.cs for building with Microsoft
Visual C++ on Windows
-SUMMARY OF HOW TO BUILD
-=======================
+WHY USE THIS PACKAGE?
+=====================
+
+The canonical make system for SQLite requires TCL as part of the build
+process. Various TCL scripts are used to generate parts of the code and
+TCL is used to run tests. But some people would prefer to build SQLite
+using only generic tools and without having to install TCL. The purpose
+of this package is to provide that capability.
+
+This package contains a pre-build SQLite amalgamation file "sqlite3.c"
+(and its associated header file "sqlite3.h"). Because the
+amalgamation has been pre-built, no TCL is required for the code
+generate (the configure script itself is written in TCL but it can use
+the embedded copy of JimTCL).
+
+REASONS TO USE THE CANONICAL BUILD SYSTEM RATHER THAN THIS PACKAGE
+==================================================================
+
+ * the canonical build system allows you to run tests to verify that
+ the build worked
+ * the canonical build system supports more compile-time options
+ * the canonical build system works for any arbitrary check-in to
+ the SQLite source tree
+
+Step-by-step instructions on how to build using the canonical make
+system for SQLite can be found at:
+
+ https://sqlite.org/src/doc/trunk/doc/compile-for-unix.md
+ https://sqlite.org/src/doc/trunk/doc/compile-for-windows.md
+
+
+SUMMARY OF HOW TO BUILD USING THIS PACKAGE
+==========================================
Unix: ./configure; make
Windows: nmake /f Makefile.msc
@@ -18,14 +49,12 @@ SUMMARY OF HOW TO BUILD
BUILDING ON POSIX
=================
-The generic installation instructions for autoconf/automake are found
-in the INSTALL file.
-
-The following SQLite specific boolean options are supported:
+The configure script follows common conventions, making it easy
+to use for anyone who has configured a software tree before.
+It supports a number of build-time flags, the full list of which
+can be seen by running:
- --enable-readline use readline in shell tool [default=yes]
- --enable-threadsafe build a thread-safe library [default=yes]
- --enable-dynamic-extensions support loadable extensions [default=yes]
+ ./configure --help
The default value for the CFLAGS variable (options passed to the C
compiler) includes debugging symbols in the build, resulting in larger
@@ -36,10 +65,11 @@ line like this:
to produce a smaller installation footprint.
-Other SQLite compilation parameters can also be set using CFLAGS. For
+Many SQLite compilation parameters can be defined by passing flags
+to the configure script. Others may be passed on in the CFLAGS. For
example:
- $ CFLAGS="-Os -DSQLITE_THREADSAFE=0" ./configure
+ $ CFLAGS="-Os -DSQLITE_OMIT_DEPRECATED" ./configure
BUILDING WITH MICROSOFT VISUAL C++
@@ -53,48 +83,6 @@ Using Microsoft Visual C++ 2005 (or later) is recommended. Several Windows
platform variants may be built by adding additional macros to the NMAKE
command line.
-Building for WinRT 8.0
-----------------------
-
- FOR_WINRT=1
-
-Using Microsoft Visual C++ 2012 (or later) is required. When using the
-above, something like the following macro will need to be added to the
-NMAKE command line as well:
-
- "NSDKLIBPATH=%WindowsSdkDir%\..\8.0\lib\win8\um\x86"
-
-Building for WinRT 8.1
-----------------------
-
- FOR_WINRT=1
-
-Using Microsoft Visual C++ 2013 (or later) is required. When using the
-above, something like the following macro will need to be added to the
-NMAKE command line as well:
-
- "NSDKLIBPATH=%WindowsSdkDir%\..\8.1\lib\winv6.3\um\x86"
-
-Building for UWP 10.0
----------------------
-
- FOR_WINRT=1 FOR_UWP=1
-
-Using Microsoft Visual C++ 2015 (or later) is required. When using the
-above, something like the following macros will need to be added to the
-NMAKE command line as well:
-
- "NSDKLIBPATH=%WindowsSdkDir%\..\10\lib\10.0.10586.0\um\x86"
- "PSDKLIBPATH=%WindowsSdkDir%\..\10\lib\10.0.10586.0\um\x86"
- "NUCRTLIBPATH=%UniversalCRTSdkDir%\..\10\lib\10.0.10586.0\ucrt\x86"
-
-Building for the Windows 10 SDK
--------------------------------
-
- FOR_WIN10=1
-
-Using Microsoft Visual C++ 2015 (or later) is required. When using the
-above, no other macros should be needed on the NMAKE command line.
Other preprocessor defines
--------------------------
@@ -102,7 +90,7 @@ Other preprocessor defines
Additionally, preprocessor defines may be specified by using the OPTS macro
on the NMAKE command line. However, not all possible preprocessor defines
may be specified in this manner as some require the amalgamation to be built
-with them enabled (see http://www.sqlite.org/compile.html). For example, the
+with them enabled (see http://sqlite.org/compile.html). For example, the
following will work:
"OPTS=-DSQLITE_ENABLE_STAT4=1 -DSQLITE_OMIT_JSON=1"
diff --git a/contrib/sqlite3/VERSION b/contrib/sqlite3/VERSION
new file mode 100644
index 000000000000..18d0478a0414
--- /dev/null
+++ b/contrib/sqlite3/VERSION
@@ -0,0 +1 @@
+3.50.2
diff --git a/contrib/sqlite3/aclocal.m4 b/contrib/sqlite3/aclocal.m4
deleted file mode 100644
index f1bd33678932..000000000000
--- a/contrib/sqlite3/aclocal.m4
+++ /dev/null
@@ -1,10204 +0,0 @@
-# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
-
-# Copyright (C) 1996-2021 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 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.
-
-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.71],,
-[m4_warning([this file was generated for autoconf 2.71.
-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'.])])
-
-# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
-#
-# 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
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-m4_define([_LT_COPYING], [dnl
-# 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.
-#
-# 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 this program. If not, see <http://www.gnu.org/licenses/>.
-])
-
-# serial 58 LT_INIT
-
-
-# LT_PREREQ(VERSION)
-# ------------------
-# Complain and exit if this libtool version is less that VERSION.
-m4_defun([LT_PREREQ],
-[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
- [m4_default([$3],
- [m4_fatal([Libtool version $1 or higher is required],
- 63)])],
- [$2])])
-
-
-# _LT_CHECK_BUILDDIR
-# ------------------
-# Complain if the absolute build directory name contains unusual characters
-m4_defun([_LT_CHECK_BUILDDIR],
-[case `pwd` in
- *\ * | *\ *)
- AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
-esac
-])
-
-
-# LT_INIT([OPTIONS])
-# ------------------
-AC_DEFUN([LT_INIT],
-[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
-AC_BEFORE([$0], [LTDL_INIT])dnl
-m4_require([_LT_CHECK_BUILDDIR])dnl
-
-dnl Autoconf doesn't catch unexpanded LT_ macros by default:
-m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
-m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
-dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
-dnl unless we require an AC_DEFUNed macro:
-AC_REQUIRE([LTOPTIONS_VERSION])dnl
-AC_REQUIRE([LTSUGAR_VERSION])dnl
-AC_REQUIRE([LTVERSION_VERSION])dnl
-AC_REQUIRE([LTOBSOLETE_VERSION])dnl
-m4_require([_LT_PROG_LTMAIN])dnl
-
-_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
-
-dnl Parse OPTIONS
-_LT_SET_OPTIONS([$0], [$1])
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS=$ltmain
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-AC_SUBST(LIBTOOL)dnl
-
-_LT_SETUP
-
-# Only expand once:
-m4_define([LT_INIT])
-])# LT_INIT
-
-# Old names:
-AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
-AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
-dnl aclocal-1.4 backwards compatibility:
-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)
-# -------------------
-# 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],
-[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])'.
-m4_defun([_LT_FILEUTILS_DEFAULTS],
-[: ${CP="cp -f"}
-: ${MV="mv -f"}
-: ${RM="rm -f"}
-])# _LT_FILEUTILS_DEFAULTS
-
-
-# _LT_SETUP
-# ---------
-m4_defun([_LT_SETUP],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
-
-_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
-dnl
-_LT_DECL([], [host_alias], [0], [The host system])dnl
-_LT_DECL([], [host], [0])dnl
-_LT_DECL([], [host_os], [0])dnl
-dnl
-_LT_DECL([], [build_alias], [0], [The build system])dnl
-_LT_DECL([], [build], [0])dnl
-_LT_DECL([], [build_os], [0])dnl
-dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-dnl
-AC_REQUIRE([AC_PROG_LN_S])dnl
-test -z "$LN_S" && LN_S="ln -s"
-_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
-dnl
-AC_REQUIRE([LT_CMD_MAX_LEN])dnl
-_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
-_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
-dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_CHECK_SHELL_FEATURES])dnl
-m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
-m4_require([_LT_CMD_RELOAD])dnl
-m4_require([_LT_CHECK_MAGIC_METHOD])dnl
-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 that allow our
-# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
-fi
-])
-if test -n "${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
-fi
-
-_LT_CHECK_OBJDIR
-
-m4_require([_LT_TAG_COMPILER])dnl
-
-case $host_os in
-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 set != "${COLLECT_NAMES+set}"; then
- COLLECT_NAMES=
- export COLLECT_NAMES
- fi
- ;;
-esac
-
-# Global variables:
-ofile=libtool
-can_build_shared=yes
-
-# 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
-
-old_CC=$CC
-old_CFLAGS=$CFLAGS
-
-# Set sane defaults for various variables
-test -z "$CC" && CC=cc
-test -z "$LTCC" && LTCC=$CC
-test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
-test -z "$LD" && LD=ld
-test -z "$ac_objext" && ac_objext=o
-
-_LT_CC_BASENAME([$compiler])
-
-# Only perform the check for file, if the check method requires it
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-case $deplibs_check_method in
-file_magic*)
- if test "$file_magic_cmd" = '$MAGIC_CMD'; then
- _LT_PATH_MAGIC
- fi
- ;;
-esac
-
-# Use C for the default configuration in the libtool script
-LT_SUPPORTED_TAG([CC])
-_LT_LANG_C_CONFIG
-_LT_LANG_DEFAULT_CONFIG
-_LT_CONFIG_COMMANDS
-])# _LT_SETUP
-
-
-# _LT_PREPARE_SED_QUOTE_VARS
-# --------------------------
-# Define a few sed substitution that help us do robust quoting.
-m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
-[# 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'
-])
-
-# _LT_PROG_LTMAIN
-# ---------------
-# 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,
-# 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
-])# _LT_PROG_LTMAIN
-
-
-
-# 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'
-# label.
-
-
-# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
-# ----------------------------------------
-# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL_INIT],
-[m4_ifval([$1],
- [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
- [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_INIT])
-
-
-# _LT_CONFIG_LIBTOOL([COMMANDS])
-# ------------------------------
-# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL],
-[m4_ifval([$1],
- [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
- [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
-
-
-# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
-# -----------------------------------------------------
-m4_defun([_LT_CONFIG_SAVE_COMMANDS],
-[_LT_CONFIG_LIBTOOL([$1])
-_LT_CONFIG_LIBTOOL_INIT([$2])
-])
-
-
-# _LT_FORMAT_COMMENT([COMMENT])
-# -----------------------------
-# Add leading comment marks to the start of each line, and a trailing
-# full-stop to the whole comment if one is not present already.
-m4_define([_LT_FORMAT_COMMENT],
-[m4_ifval([$1], [
-m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
- [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
-)])
-
-
-
-
-
-# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
-# -------------------------------------------------------------------
-# CONFIGNAME is the name given to the value in the libtool script.
-# VARNAME is the (base) name used in the configure script.
-# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
-# VARNAME. Any other value will be used directly.
-m4_define([_LT_DECL],
-[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
- [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
- [m4_ifval([$1], [$1], [$2])])
- lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
- m4_ifval([$4],
- [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
- lt_dict_add_subkey([lt_decl_dict], [$2],
- [tagged?], [m4_ifval([$5], [yes], [no])])])
-])
-
-
-# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
-# --------------------------------------------------------
-m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
-
-
-# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_tag_varnames],
-[_lt_decl_filter([tagged?], [yes], $@)])
-
-
-# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
-# ---------------------------------------------------------
-m4_define([_lt_decl_filter],
-[m4_case([$#],
- [0], [m4_fatal([$0: too few arguments: $#])],
- [1], [m4_fatal([$0: too few arguments: $#: $1])],
- [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
- [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
- [lt_dict_filter([lt_decl_dict], $@)])[]dnl
-])
-
-
-# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
-# --------------------------------------------------
-m4_define([lt_decl_quote_varnames],
-[_lt_decl_filter([value], [1], $@)])
-
-
-# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_dquote_varnames],
-[_lt_decl_filter([value], [2], $@)])
-
-
-# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_varnames_tagged],
-[m4_assert([$# <= 2])dnl
-_$0(m4_quote(m4_default([$1], [[, ]])),
- m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
- m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
-m4_define([_lt_decl_varnames_tagged],
-[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
-
-
-# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_all_varnames],
-[_$0(m4_quote(m4_default([$1], [[, ]])),
- m4_if([$2], [],
- m4_quote(lt_decl_varnames),
- m4_quote(m4_shift($@))))[]dnl
-])
-m4_define([_lt_decl_all_varnames],
-[lt_join($@, lt_decl_varnames_tagged([$1],
- lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
-])
-
-
-# _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
-# 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"`'])
-
-
-# _LT_CONFIG_STATUS_DECLARATIONS
-# ------------------------------
-# We delimit libtool config variables with single quotes, so when
-# we write them to config.status, we have to be sure to quote all
-# embedded single quotes properly. In configure, this macro expands
-# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
-#
-# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
-m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
- [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAGS
-# ----------------
-# 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
-])
-
-
-# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
-# -----------------------------------
-# Extract the dictionary values for VARNAME (optionally with TAG) and
-# expand to a commented shell variable setting:
-#
-# # Some comment about what VAR is for.
-# visible_name=$lt_internal_name
-m4_define([_LT_LIBTOOL_DECLARE],
-[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
- [description])))[]dnl
-m4_pushdef([_libtool_name],
- m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
-m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
- [0], [_libtool_name=[$]$1],
- [1], [_libtool_name=$lt_[]$1],
- [2], [_libtool_name=$lt_[]$1],
- [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
-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'
-# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
-# section) are produced by _LT_LIBTOOL_TAG_VARS.
-m4_defun([_LT_LIBTOOL_CONFIG_VARS],
-[m4_foreach([_lt_var],
- m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
- [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAG_VARS(TAG)
-# -------------------------
-m4_define([_LT_LIBTOOL_TAG_VARS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
- [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
-
-
-# _LT_TAGVAR(VARNAME, [TAGNAME])
-# ------------------------------
-m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
-
-
-# _LT_CONFIG_COMMANDS
-# -------------------
-# 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
-# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
-m4_defun([_LT_CONFIG_COMMANDS],
-[AC_PROVIDE_IFELSE([LT_OUTPUT],
- dnl If the libtool generation code has been placed in $CONFIG_LT,
- dnl instead of duplicating it all over again into config.status,
- dnl then we will have config.status run $CONFIG_LT later, so it
- dnl needs to know what name is stored there:
- [AC_CONFIG_COMMANDS([libtool],
- [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
- dnl If the libtool generation code is destined for config.status,
- dnl expand the accumulated commands and init code now:
- [AC_CONFIG_COMMANDS([libtool],
- [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
-])#_LT_CONFIG_COMMANDS
-
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
-[
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-sed_quote_subst='$sed_quote_subst'
-double_quote_subst='$double_quote_subst'
-delay_variable_subst='$delay_variable_subst'
-_LT_CONFIG_STATUS_DECLARATIONS
-LTCC='$LTCC'
-LTCFLAGS='$LTCFLAGS'
-compiler='$compiler_DEFAULT'
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
- eval 'cat <<_LTECHO_EOF
-\$[]1
-_LTECHO_EOF'
-}
-
-# Quote evaled strings.
-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\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
- ;;
- *)
- eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
- ;;
- esac
-done
-
-# Double-quote double-evaled strings.
-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\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
- ;;
- *)
- eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
- ;;
- esac
-done
-
-_LT_OUTPUT_LIBTOOL_INIT
-])
-
-# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
-# ------------------------------------
-# 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
-# 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).
-m4_ifdef([AS_INIT_GENERATED],
-[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
-[m4_defun([_LT_GENERATED_FILE_INIT],
-[m4_require([AS_PREPARE])]dnl
-[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
-[lt_write_fail=0
-cat >$1 <<_ASEOF || lt_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-$2
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$1 <<\_ASEOF || lt_write_fail=1
-AS_SHELL_SANITIZE
-_AS_PREPARE
-exec AS_MESSAGE_FD>&1
-_ASEOF
-test 0 = "$lt_write_fail" && chmod +x $1[]dnl
-m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
-
-# LT_OUTPUT
-# ---------
-# This macro allows early generation of the libtool script (before
-# AC_OUTPUT is called), incase it is used in configure for compilation
-# tests.
-AC_DEFUN([LT_OUTPUT],
-[: ${CONFIG_LT=./config.lt}
-AC_MSG_NOTICE([creating $CONFIG_LT])
-_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
-[# Run this file to recreate a libtool stub with the current configuration.])
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-lt_cl_silent=false
-exec AS_MESSAGE_LOG_FD>>config.log
-{
- echo
- AS_BOX([Running $as_me.])
-} >&AS_MESSAGE_LOG_FD
-
-lt_cl_help="\
-'$as_me' creates a local libtool stub from the current configuration,
-for use in further configure time tests before the real libtool is
-generated.
-
-Usage: $[0] [[OPTIONS]]
-
- -h, --help print this help, then exit
- -V, --version print version number, then exit
- -q, --quiet do not print progress messages
- -d, --debug don't remove temporary files
-
-Report bugs to <bug-libtool@gnu.org>."
-
-lt_cl_version="\
-m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
-m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
-configured by $[0], generated by m4_PACKAGE_STRING.
-
-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 != $[#]
-do
- case $[1] in
- --version | --v* | -V )
- echo "$lt_cl_version"; exit 0 ;;
- --help | --h* | -h )
- echo "$lt_cl_help"; exit 0 ;;
- --debug | --d* | -d )
- debug=: ;;
- --quiet | --q* | --silent | --s* | -q )
- lt_cl_silent=: ;;
-
- -*) AC_MSG_ERROR([unrecognized option: $[1]
-Try '$[0] --help' for more information.]) ;;
-
- *) AC_MSG_ERROR([unrecognized argument: $[1]
-Try '$[0] --help' for more information.]) ;;
- esac
- shift
-done
-
-if $lt_cl_silent; then
- exec AS_MESSAGE_FD>/dev/null
-fi
-_LTEOF
-
-cat >>"$CONFIG_LT" <<_LTEOF
-_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
-_LTEOF
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-AC_MSG_NOTICE([creating $ofile])
-_LT_OUTPUT_LIBTOOL_COMMANDS
-AS_EXIT(0)
-_LTEOF
-chmod +x "$CONFIG_LT"
-
-# configure is writing to config.log, but config.lt does its own redirection,
-# appending to config.log, which fails on DOS, as config.log is still kept
-# 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 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
-exec AS_MESSAGE_LOG_FD>>config.log
-$lt_cl_success || AS_EXIT(1)
-])# LT_OUTPUT
-
-
-# _LT_CONFIG(TAG)
-# ---------------
-# If TAG is the built-in tag, create an initial libtool script with a
-# default configuration from the untagged config vars. Otherwise add code
-# to config.status for appending the configuration named by TAG from the
-# matching tagged config vars.
-m4_defun([_LT_CONFIG],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_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 that allow our
- # commands through without removal of \ escapes.
- if test -n "${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
- fi
-
- cfgfile=${ofile}T
- trap "$RM \"$cfgfile\"; exit 1" 1 2 15
- $RM "$cfgfile"
-
- cat <<_LT_EOF >> "$cfgfile"
-#! $SHELL
-# Generated automatically by $as_me ($PACKAGE) $VERSION
-# 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
-# ### END LIBTOOL CONFIG
-
-_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 set != "${COLLECT_NAMES+set}"; then
- COLLECT_NAMES=
- export COLLECT_NAMES
-fi
-_LT_EOF
- ;;
- esac
-
- _LT_PROG_LTMAIN
-
- # We use sed instead of cat because bash on DJGPP gets confused if
- # if finds mixed CR/LF and LF-only lines. Since sed operates in
- # text mode, it properly converts lines to CR/LF. This bash problem
- # is reportedly fixed, but why not run on old versions too?
- sed '$q' "$ltmain" >> "$cfgfile" \
- || (rm -f "$cfgfile"; exit 1)
-
- mv -f "$cfgfile" "$ofile" ||
- (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
- chmod +x "$ofile"
-],
-[cat <<_LT_EOF >> "$ofile"
-
-dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
-dnl in a comment (ie after a #).
-# ### BEGIN LIBTOOL TAG CONFIG: $1
-_LT_LIBTOOL_TAG_VARS(_LT_TAG)
-# ### END LIBTOOL TAG CONFIG: $1
-_LT_EOF
-])dnl /m4_if
-],
-[m4_if([$1], [], [
- PACKAGE='$PACKAGE'
- VERSION='$VERSION'
- RM='$RM'
- ofile='$ofile'], [])
-])dnl /_LT_CONFIG_SAVE_COMMANDS
-])# _LT_CONFIG
-
-
-# LT_SUPPORTED_TAG(TAG)
-# ---------------------
-# Trace this macro to discover what tags are supported by the libtool
-# --tag option, using:
-# autoconf --trace 'LT_SUPPORTED_TAG:$1'
-AC_DEFUN([LT_SUPPORTED_TAG], [])
-
-
-# C support is built-in for now
-m4_define([_LT_LANG_C_enabled], [])
-m4_define([_LT_TAGS], [])
-
-
-# LT_LANG(LANG)
-# -------------
-# Enable libtool support for the given language if not already enabled.
-AC_DEFUN([LT_LANG],
-[AC_BEFORE([$0], [LT_OUTPUT])dnl
-m4_case([$1],
- [C], [_LT_LANG(C)],
- [C++], [_LT_LANG(CXX)],
- [Go], [_LT_LANG(GO)],
- [Java], [_LT_LANG(GCJ)],
- [Fortran 77], [_LT_LANG(F77)],
- [Fortran], [_LT_LANG(FC)],
- [Windows Resource], [_LT_LANG(RC)],
- [m4_ifdef([_LT_LANG_]$1[_CONFIG],
- [_LT_LANG($1)],
- [m4_fatal([$0: unsupported language: "$1"])])])dnl
-])# LT_LANG
-
-
-# _LT_LANG(LANGNAME)
-# ------------------
-m4_defun([_LT_LANG],
-[m4_ifdef([_LT_LANG_]$1[_enabled], [],
- [LT_SUPPORTED_TAG([$1])dnl
- m4_append([_LT_TAGS], [$1 ])dnl
- m4_define([_LT_LANG_]$1[_enabled], [])dnl
- _LT_LANG_$1_CONFIG($1)])dnl
-])# _LT_LANG
-
-
-m4_ifndef([AC_PROG_GO], [
-# NOTE: This macro has been submitted for inclusion into #
-# GNU Autoconf as AC_PROG_GO. When it is available in #
-# a released version of Autoconf we should remove this #
-# macro and use it instead. #
-m4_defun([AC_PROG_GO],
-[AC_LANG_PUSH(Go)dnl
-AC_ARG_VAR([GOC], [Go compiler command])dnl
-AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
-_AC_ARG_VAR_LDFLAGS()dnl
-AC_CHECK_TOOL(GOC, gccgo)
-if test -z "$GOC"; then
- if test -n "$ac_tool_prefix"; then
- AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
- fi
-fi
-if test -z "$GOC"; then
- AC_CHECK_PROG(GOC, gccgo, gccgo, false)
-fi
-])#m4_defun
-])#m4_ifndef
-
-
-# _LT_LANG_DEFAULT_CONFIG
-# -----------------------
-m4_defun([_LT_LANG_DEFAULT_CONFIG],
-[AC_PROVIDE_IFELSE([AC_PROG_CXX],
- [LT_LANG(CXX)],
- [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_F77],
- [LT_LANG(F77)],
- [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_FC],
- [LT_LANG(FC)],
- [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
-
-dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
-dnl pulling things in needlessly.
-AC_PROVIDE_IFELSE([AC_PROG_GCJ],
- [LT_LANG(GCJ)],
- [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
- [LT_LANG(GCJ)],
- [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
- [LT_LANG(GCJ)],
- [m4_ifdef([AC_PROG_GCJ],
- [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
- m4_ifdef([A][M_PROG_GCJ],
- [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
- m4_ifdef([LT_PROG_GCJ],
- [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
-
-AC_PROVIDE_IFELSE([AC_PROG_GO],
- [LT_LANG(GO)],
- [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
-
-AC_PROVIDE_IFELSE([LT_PROG_RC],
- [LT_LANG(RC)],
- [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
-])# _LT_LANG_DEFAULT_CONFIG
-
-# Obsolete macros:
-AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
-AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
-AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
-AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
-AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
-dnl AC_DEFUN([AC_LIBTOOL_F77], [])
-dnl AC_DEFUN([AC_LIBTOOL_FC], [])
-dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
-dnl AC_DEFUN([AC_LIBTOOL_RC], [])
-
-
-# _LT_TAG_COMPILER
-# ----------------
-m4_defun([_LT_TAG_COMPILER],
-[AC_REQUIRE([AC_PROG_CC])dnl
-
-_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
-_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
-_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
-_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-])# _LT_TAG_COMPILER
-
-
-# _LT_COMPILER_BOILERPLATE
-# ------------------------
-# Check for compiler boilerplate output or warnings with
-# the simple compiler test code.
-m4_defun([_LT_COMPILER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_compile_test_code" >conftest.$ac_ext
-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_compiler_boilerplate=`cat conftest.err`
-$RM conftest*
-])# _LT_COMPILER_BOILERPLATE
-
-
-# _LT_LINKER_BOILERPLATE
-# ----------------------
-# Check for linker boilerplate output or warnings with
-# the simple link test code.
-m4_defun([_LT_LINKER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_link_test_code" >conftest.$ac_ext
-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_linker_boilerplate=`cat conftest.err`
-$RM -r conftest*
-])# _LT_LINKER_BOILERPLATE
-
-# _LT_REQUIRED_DARWIN_CHECKS
-# -------------------------
-m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
- case $host_os in
- rhapsody* | darwin*)
- AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
- AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
- AC_CHECK_TOOL([LIPO], [lipo], [:])
- AC_CHECK_TOOL([OTOOL], [otool], [:])
- AC_CHECK_TOOL([OTOOL64], [otool64], [:])
- _LT_DECL([], [DSYMUTIL], [1],
- [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
- _LT_DECL([], [NMEDIT], [1],
- [Tool to change global to local symbols on Mac OS X])
- _LT_DECL([], [LIPO], [1],
- [Tool to manipulate fat objects and archives on Mac OS X])
- _LT_DECL([], [OTOOL], [1],
- [ldd/readelf like tool for Mach-O binaries on Mac OS X])
- _LT_DECL([], [OTOOL64], [1],
- [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
-
- 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
- # 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
- # link flags.
- rm -rf libconftest.dylib*
- echo "int foo(void){return 1;}" > conftest.c
- echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
--dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
- $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
- -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
- _lt_result=$?
- # If there is a non-empty error log, and "single_module"
- # appears in it, assume the flag caused a linker warning
- if test -s conftest.err && $GREP single_module conftest.err; then
- 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 0 = "$_lt_result"; then
- lt_cv_apple_cc_single_mod=yes
- else
- cat conftest.err >&AS_MESSAGE_LOG_FD
- fi
- rm -rf libconftest.dylib*
- rm -f conftest.*
- fi])
-
- AC_CACHE_CHECK([for -exported_symbols_list linker flag],
- [lt_cv_ld_exported_symbols_list],
- [lt_cv_ld_exported_symbols_list=no
- save_LDFLAGS=$LDFLAGS
- echo "_main" > conftest.sym
- LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
- [lt_cv_ld_exported_symbols_list=yes],
- [lt_cv_ld_exported_symbols_list=no])
- LDFLAGS=$save_LDFLAGS
- ])
-
- AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
- [lt_cv_ld_force_load=no
- cat > conftest.c << _LT_EOF
-int forced_loaded() { return 2;}
-_LT_EOF
- echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
- $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
- echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
- $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
- echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
- $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
- cat > conftest.c << _LT_EOF
-int main() { return 0;}
-_LT_EOF
- echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
- $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
- _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 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
- fi
- rm -f conftest.err libconftest.a conftest conftest.c
- rm -rf conftest.dSYM
- ])
- case $host_os in
- rhapsody* | darwin1.[[012]])
- _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
- darwin1.*)
- _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[[912]]*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- 10.[[012]][[,.]]*)
- _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- 10.*|11.*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- esac
- ;;
- esac
- if test yes = "$lt_cv_apple_cc_single_mod"; then
- _lt_dar_single_mod='$single_module'
- fi
- 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'
- fi
- if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
- _lt_dsymutil='~$DSYMUTIL $lib || :'
- else
- _lt_dsymutil=
- fi
- ;;
- esac
-])
-
-
-# _LT_DARWIN_LINKER_FEATURES([TAG])
-# ---------------------------------
-# Checks for linker and compiler features on darwin
-m4_defun([_LT_DARWIN_LINKER_FEATURES],
-[
- m4_require([_LT_REQUIRED_DARWIN_CHECKS])
- _LT_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_automatic, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
- 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
- case $cc_basename in
- ifort*|nagfor*) _lt_dar_can_shared=yes ;;
- *) _lt_dar_can_shared=$GCC ;;
- esac
- 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"
- m4_if([$1], [CXX],
-[ 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
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
-])
-
-# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
-# ----------------------------------
-# Links a minimal program and checks the executable
-# for the system default hardcoded library path. In most cases,
-# this is /usr/lib:/lib, but when the MPI compilers are used
-# the location of the communication and MPI libs are included too.
-# If we don't find anything, use the default library path according
-# to the aix ld manual.
-# Store the results from the different compilers for each TAGNAME.
-# 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 set = "${lt_cv_aix_libpath+set}"; then
- aix_libpath=$lt_cv_aix_libpath
-else
- AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
- [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
- lt_aix_libpath_sed='[
- /Import File Strings/,/^$/ {
- /^0/ {
- s/^0 *\([^ ]*\) *$/\1/
- p
- }
- }]'
- _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- # Check for a 64-bit object if we didn't find anything.
- if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
- _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
- fi
- ])
- aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
-fi
-])# _LT_SYS_MODULE_PATH_AIX
-
-
-# _LT_SHELL_INIT(ARG)
-# -------------------
-m4_define([_LT_SHELL_INIT],
-[m4_divert_text([M4SH-INIT], [$1
-])])# _LT_SHELL_INIT
-
-
-
-# _LT_PROG_ECHO_BACKSLASH
-# -----------------------
-# 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 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
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-
-AC_MSG_CHECKING([how to print strings])
-# 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*) AC_MSG_RESULT([printf]) ;;
- print*) AC_MSG_RESULT([print -r]) ;;
- *) AC_MSG_RESULT([cat]) ;;
-esac
-
-m4_ifdef([_AS_DETECT_SUGGESTED],
-[_AS_DETECT_SUGGESTED([
- test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
- ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
- ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
- ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
- PATH=/empty FPATH=/empty; export PATH FPATH
- test "X`printf %s $ECHO`" = "X$ECHO" \
- || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
-
-_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
-_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
-])# _LT_PROG_ECHO_BACKSLASH
-
-
-# _LT_WITH_SYSROOT
-# ----------------
-AC_DEFUN([_LT_WITH_SYSROOT],
-[AC_MSG_CHECKING([for sysroot])
-AC_ARG_WITH([sysroot],
-[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 #(
- yes)
- if test yes = "$GCC"; then
- lt_sysroot=`$CC --print-sysroot 2>/dev/null`
- fi
- ;; #(
- /*)
- lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
- ;; #(
- no|'')
- ;; #(
- *)
- 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 where our libraries should be installed.])])
-
-# _LT_ENABLE_LOCK
-# ---------------
-m4_defun([_LT_ENABLE_LOCK],
-[AC_ARG_ENABLE([libtool-lock],
- [AS_HELP_STRING([--disable-libtool-lock],
- [avoid locking (might break parallel builds)])])
-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 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
- ;;
- *ELF-64*)
- HPUX_IA64_MODE=64
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-*-*-irix6*)
- # 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 yes = "$lt_cv_prog_gnu_ld"; then
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -melf32bsmip"
- ;;
- *N32*)
- LD="${LD-ld} -melf32bmipn32"
- ;;
- *64-bit*)
- LD="${LD-ld} -melf64bmip"
- ;;
- esac
- else
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -32"
- ;;
- *N32*)
- LD="${LD-ld} -n32"
- ;;
- *64-bit*)
- LD="${LD-ld} -64"
- ;;
- esac
- fi
- fi
- 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 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
- *32-bit*)
- case $host in
- x86_64-*kfreebsd*-gnu)
- LD="${LD-ld} -m elf_i386_fbsd"
- ;;
- x86_64-*linux*)
- case `/usr/bin/file conftest.o` in
- *x86-64*)
- LD="${LD-ld} -m elf32_x86_64"
- ;;
- *)
- LD="${LD-ld} -m elf_i386"
- ;;
- esac
- ;;
- powerpc64le-*linux*)
- LD="${LD-ld} -m elf32lppclinux"
- ;;
- powerpc64-*linux*)
- LD="${LD-ld} -m elf32ppclinux"
- ;;
- s390x-*linux*)
- LD="${LD-ld} -m elf_s390"
- ;;
- sparc64-*linux*)
- LD="${LD-ld} -m elf32_sparc"
- ;;
- esac
- ;;
- *64-bit*)
- case $host in
- x86_64-*kfreebsd*-gnu)
- LD="${LD-ld} -m elf_x86_64_fbsd"
- ;;
- x86_64-*linux*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- powerpcle-*linux*)
- LD="${LD-ld} -m elf64lppc"
- ;;
- powerpc-*linux*)
- LD="${LD-ld} -m elf64ppc"
- ;;
- s390*-*linux*|s390*-*tpf*)
- LD="${LD-ld} -m elf64_s390"
- ;;
- sparc*-*linux*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- esac
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-
-*-*-sco3.2v5*)
- # On SCO OpenServer 5, we need -belf to get full-featured binaries.
- 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 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
- fi
- ;;
-*-*solaris*)
- # 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
- *64-bit*)
- case $lt_cv_prog_gnu_ld in
- yes*)
- case $host in
- i?86-*-solaris*|x86_64-*-solaris*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- sparc*-*-solaris*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- 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
- fi
- ;;
- *)
- if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
- LD="${LD-ld} -64"
- fi
- ;;
- esac
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-esac
-
-need_locks=$enable_libtool_lock
-])# _LT_ENABLE_LOCK
-
-
-# _LT_PROG_AR
-# -----------
-m4_defun([_LT_PROG_AR],
-[AC_CHECK_TOOLS(AR, [ar], false)
-: ${AR=ar}
-: ${AR_FLAGS=cr}
-_LT_DECL([], [AR], [1], [The archiver])
-_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
-
-AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
- [lt_cv_ar_at_file=no
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
- [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 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 0 -ne "$ac_status"; then
- lt_cv_ar_at_file=@
- fi
- fi
- rm -f conftest.* libconftest.a
- ])
- ])
-
-if test no = "$lt_cv_ar_at_file"; then
- archiver_list_spec=
-else
- archiver_list_spec=$lt_cv_ar_at_file
-fi
-_LT_DECL([], [archiver_list_spec], [1],
- [How to feed a file listing to the archiver])
-])# _LT_PROG_AR
-
-
-# _LT_CMD_OLD_ARCHIVE
-# -------------------
-m4_defun([_LT_CMD_OLD_ARCHIVE],
-[_LT_PROG_AR
-
-AC_CHECK_TOOL(STRIP, strip, :)
-test -z "$STRIP" && STRIP=:
-_LT_DECL([], [STRIP], [1], [A symbol stripping program])
-
-AC_CHECK_TOOL(RANLIB, ranlib, :)
-test -z "$RANLIB" && RANLIB=:
-_LT_DECL([], [RANLIB], [1],
- [Commands used to install an old-style archive])
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
- case $host_os in
- bitrig* | openbsd*)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
- ;;
- *)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
- ;;
- esac
- old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
-fi
-
-case $host_os in
- darwin*)
- lock_old_archive_extraction=yes ;;
- *)
- lock_old_archive_extraction=no ;;
-esac
-_LT_DECL([], [old_postinstall_cmds], [2])
-_LT_DECL([], [old_postuninstall_cmds], [2])
-_LT_TAGDECL([], [old_archive_cmds], [2],
- [Commands used to build an old-style archive])
-_LT_DECL([], [lock_old_archive_extraction], [0],
- [Whether to use a lock for old archive extraction])
-])# _LT_CMD_OLD_ARCHIVE
-
-
-# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------------------
-# Check whether the given compiler option works
-AC_DEFUN([_LT_COMPILER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-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" ## 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
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- # The option is referenced via a variable to avoid confusing sed.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
- (eval "$lt_compile" 2>conftest.err)
- ac_status=$?
- cat conftest.err >&AS_MESSAGE_LOG_FD
- echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
- if (exit $ac_status) && test -s "$ac_outfile"; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings other than the usual output.
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
- $2=yes
- fi
- fi
- $RM conftest*
-])
-
-if test yes = "[$]$2"; then
- m4_if([$5], , :, [$5])
-else
- m4_if([$6], , :, [$6])
-fi
-])# _LT_COMPILER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
-
-
-# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-# [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------
-# Check whether the given linker option works
-AC_DEFUN([_LT_LINKER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-AC_CACHE_CHECK([$1], [$2],
- [$2=no
- 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
- # The linker can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- # Append any errors to the config.log.
- cat conftest.err 1>&AS_MESSAGE_LOG_FD
- $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if diff conftest.exp conftest.er2 >/dev/null; then
- $2=yes
- fi
- else
- $2=yes
- fi
- fi
- $RM -r conftest*
- LDFLAGS=$save_LDFLAGS
-])
-
-if test yes = "[$]$2"; then
- m4_if([$4], , :, [$4])
-else
- m4_if([$5], , :, [$5])
-fi
-])# _LT_LINKER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
-
-
-# LT_CMD_MAX_LEN
-#---------------
-AC_DEFUN([LT_CMD_MAX_LEN],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-# find the maximum length of command line arguments
-AC_MSG_CHECKING([the maximum length of command line arguments])
-AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
- i=0
- teststring=ABCD
-
- case $build_os in
- msdosdjgpp*)
- # On DJGPP, this test can blow up pretty badly due to problems in libc
- # (any single argument exceeding 2000 bytes causes a buffer overrun
- # during glob expansion). Even if it were fixed, the result of this
- # check would be larger than it should be.
- lt_cv_sys_max_cmd_len=12288; # 12K is about right
- ;;
-
- gnu*)
- # Under GNU Hurd, this test is not required because there is
- # no limit to the length of command line arguments.
- # Libtool will interpret -1 as no limit whatsoever
- lt_cv_sys_max_cmd_len=-1;
- ;;
-
- cygwin* | mingw* | cegcc*)
- # On Win9x/ME, this test blows up -- it succeeds, but takes
- # about 5 minutes as the teststring grows exponentially.
- # Worse, since 9x/ME are not pre-emptively multitasking,
- # you end up with a "frozen" computer, even though with patience
- # the test eventually succeeds (with a max line length of 256k).
- # Instead, let's just punt: use the minimum linelength reported by
- # all of the supported platforms: 8192 (on NT/2K/XP).
- 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;
- ;;
-
- 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`
- elif test -x /usr/sbin/sysctl; then
- lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
- else
- lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
- fi
- # And add a safety zone
- 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`
- ;;
-
- interix*)
- # We know the value 262144 and hardcode it with a safety zone (like BSD)
- lt_cv_sys_max_cmd_len=196608
- ;;
-
- os2*)
- # The test takes a long time on OS/2.
- lt_cv_sys_max_cmd_len=8192
- ;;
-
- osf*)
- # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
- # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
- # nice to cause kernel panics so lets avoid the loop below.
- # First set a reasonable default.
- lt_cv_sys_max_cmd_len=16384
- #
- if test -x /sbin/sysconfig; then
- case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
- *1*) lt_cv_sys_max_cmd_len=-1 ;;
- esac
- fi
- ;;
- sco3.2v5*)
- lt_cv_sys_max_cmd_len=102400
- ;;
- sysv5* | sco5v6* | sysv4.2uw2*)
- kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
- if test -n "$kargmax"; then
- lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
- else
- lt_cv_sys_max_cmd_len=32768
- fi
- ;;
- *)
- 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
- 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
- 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` \
- = "X$teststring$teststring"; } >/dev/null 2>&1 &&
- test 17 != "$i" # 1/2 MB should be enough
- do
- i=`expr $i + 1`
- teststring=$teststring$teststring
- done
- # Only check the string length outside the loop.
- lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
- teststring=
- # Add a significant safety factor because C++ compilers can tack on
- # massive amounts of additional arguments before passing them to the
- # linker. It appears as though 1/2 is a usable value.
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
- fi
- ;;
- esac
-])
-if test -n "$lt_cv_sys_max_cmd_len"; then
- AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
-else
- AC_MSG_RESULT(none)
-fi
-max_cmd_len=$lt_cv_sys_max_cmd_len
-_LT_DECL([], [max_cmd_len], [0],
- [What is the maximum length of a command?])
-])# LT_CMD_MAX_LEN
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
-
-
-# _LT_HEADER_DLFCN
-# ----------------
-m4_defun([_LT_HEADER_DLFCN],
-[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
-])# _LT_HEADER_DLFCN
-
-
-# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
-# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
-# ----------------------------------------------------------------
-m4_defun([_LT_TRY_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test yes = "$cross_compiling"; then :
- [$4]
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<_LT_EOF
-[#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-/* 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))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else
- {
- if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- else puts (dlerror ());
- }
- /* dlclose (self); */
- }
- else
- puts (dlerror ());
-
- return status;
-}]
-_LT_EOF
- 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
- x$lt_dlno_uscore) $1 ;;
- x$lt_dlneed_uscore) $2 ;;
- x$lt_dlunknown|x*) $3 ;;
- esac
- else :
- # compilation failed
- $3
- fi
-fi
-rm -fr conftest*
-])# _LT_TRY_DLOPEN_SELF
-
-
-# LT_SYS_DLOPEN_SELF
-# ------------------
-AC_DEFUN([LT_SYS_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test yes != "$enable_dlopen"; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
- lt_cv_dlopen=no
- lt_cv_dlopen_libs=
-
- case $host_os in
- beos*)
- 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_libs=
- ;;
-
- cygwin*)
- lt_cv_dlopen=dlopen
- lt_cv_dlopen_libs=
- ;;
-
- darwin*)
- # 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_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],
- [AC_CHECK_LIB([dld], [shl_load],
- [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
- [AC_CHECK_FUNC([dlopen],
- [lt_cv_dlopen=dlopen],
- [AC_CHECK_LIB([dl], [dlopen],
- [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
- [AC_CHECK_LIB([svld], [dlopen],
- [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])
- ])
- ])
- ])
- ])
- ])
- ;;
- esac
-
- 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 yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
- save_LDFLAGS=$LDFLAGS
- wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
- save_LIBS=$LIBS
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- AC_CACHE_CHECK([whether a program can dlopen itself],
- lt_cv_dlopen_self, [dnl
- _LT_TRY_DLOPEN_SELF(
- lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
- lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
- ])
-
- 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
- _LT_TRY_DLOPEN_SELF(
- lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
- lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
- ])
- fi
-
- CPPFLAGS=$save_CPPFLAGS
- LDFLAGS=$save_LDFLAGS
- LIBS=$save_LIBS
- ;;
- esac
-
- case $lt_cv_dlopen_self in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case $lt_cv_dlopen_self_static in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-_LT_DECL([dlopen_support], [enable_dlopen], [0],
- [Whether dlopen is supported])
-_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
- [Whether dlopen of programs is supported])
-_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
- [Whether dlopen of statically linked programs is supported])
-])# LT_SYS_DLOPEN_SELF
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
-
-
-# _LT_COMPILER_C_O([TAGNAME])
-# ---------------------------
-# Check to see if options -c and -o are simultaneously supported by compiler.
-# This macro does not hard code the compiler like AC_PROG_CC_C_O.
-m4_defun([_LT_COMPILER_C_O],
-[m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
- [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
- [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
- $RM -r conftest 2>/dev/null
- mkdir conftest
- cd conftest
- mkdir out
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- lt_compiler_flag="-o out/conftest2.$ac_objext"
- # 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
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
- (eval "$lt_compile" 2>out/conftest.err)
- ac_status=$?
- cat out/conftest.err >&AS_MESSAGE_LOG_FD
- echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
- if (exit $ac_status) && test -s out/conftest2.$ac_objext
- then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
- $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
- if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
- _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
- fi
- fi
- chmod u+w . 2>&AS_MESSAGE_LOG_FD
- $RM conftest*
- # SGI C++ compiler will create directory out/ii_files/ for
- # template instantiation
- test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
- $RM out/* && rmdir out
- cd ..
- $RM -r conftest
- $RM conftest*
-])
-_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
- [Does compiler simultaneously support -c and -o options?])
-])# _LT_COMPILER_C_O
-
-
-# _LT_COMPILER_FILE_LOCKS([TAGNAME])
-# ----------------------------------
-# Check to see if we can do hard links to lock some files if needed
-m4_defun([_LT_COMPILER_FILE_LOCKS],
-[m4_require([_LT_ENABLE_LOCK])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_LT_COMPILER_C_O([$1])
-
-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
- $RM conftest*
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- touch conftest.a
- 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 no = "$hard_links"; then
- AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
- need_locks=warn
- fi
-else
- need_locks=no
-fi
-_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
-])# _LT_COMPILER_FILE_LOCKS
-
-
-# _LT_CHECK_OBJDIR
-# ----------------
-m4_defun([_LT_CHECK_OBJDIR],
-[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
-[rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
- lt_cv_objdir=.libs
-else
- # MS-DOS does not allow filenames that begin with a dot.
- lt_cv_objdir=_libs
-fi
-rmdir .libs 2>/dev/null])
-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 where libtool stores uninstalled libraries.])
-])# _LT_CHECK_OBJDIR
-
-
-# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
-# --------------------------------------
-# Check hardcoding attributes.
-m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
-[AC_MSG_CHECKING([how to hardcode library paths into programs])
-_LT_TAGVAR(hardcode_action, $1)=
-if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
- test -n "$_LT_TAGVAR(runpath_var, $1)" ||
- test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
-
- # We can hardcode non-existent directories.
- 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 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
- # We can link without hardcoding, and we can hardcode nonexisting dirs.
- _LT_TAGVAR(hardcode_action, $1)=immediate
- fi
-else
- # We cannot hardcode anything, or else we can only hardcode existing
- # directories.
- _LT_TAGVAR(hardcode_action, $1)=unsupported
-fi
-AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
-
-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 yes = "$shlibpath_overrides_runpath" ||
- test no = "$enable_shared"; then
- # Fast installation is not necessary
- enable_fast_install=needless
-fi
-_LT_TAGDECL([], [hardcode_action], [0],
- [How to hardcode a shared library path into an executable])
-])# _LT_LINKER_HARDCODE_LIBPATH
-
-
-# _LT_CMD_STRIPLIB
-# ----------------
-m4_defun([_LT_CMD_STRIPLIB],
-[m4_require([_LT_DECL_EGREP])
-striplib=
-old_striplib=
-AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- AC_MSG_RESULT([yes])
-else
-# FIXME - insert some real tests, host_os isn't really good enough
- case $host_os in
- darwin*)
- if test -n "$STRIP"; then
- striplib="$STRIP -x"
- old_striplib="$STRIP -S"
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- ;;
- *)
- AC_MSG_RESULT([no])
- ;;
- esac
-fi
-_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
-_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
-m4_defun([_LT_SYS_DYNAMIC_LINKER],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-m4_require([_LT_DECL_EGREP])dnl
-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 yes = "$GCC"; then
- case $host_os in
- 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' ;;
- 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
- *\;*)
- # if the path contains ";" then we assume it to be the separator
- # otherwise default to the standard path separator (i.e. ":") - it is
- # assumed that no part of a normal pathname contains ";" but that should
- # okay in the real world where ";" in dirpaths is itself problematic.
- lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
- ;;
- *)
- lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
- ;;
- esac
- # Ok, now we have the path, separated by spaces, we can step through it
- # 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`
- # ...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"
- 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;
- 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;
- } else {
- lt_count--;
- }
- }
- }
- }
- if (lt_foo != "") { lt_freq[[lt_foo]]++; }
- if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
-}'`
- # AWK program above erroneously prepends '/' to C:/dos/paths
- # 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'` ;;
- esac
- sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
-else
- sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-fi])
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-shrext_cmds=.so
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-need_lib_prefix=unknown
-hardcode_into_libs=no
-
-# when you set need_version to no, make sure it does not cause -set_version
-# 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'
- 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'
- ;;
-
-aix[[4-9]]*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- hardcode_into_libs=yes
- 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'
- 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
- # 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
- :
- else
- can_build_shared=no
- fi
- ;;
- esac
- # 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.
- 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'
- ;;
- 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'
- ;;
- 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
- ;;
-
-amigaos*)
- case $host_cpu in
- 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'
- ;;
- 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%'\''`; $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'
- dynamic_linker="$host_os ld.so"
- shlibpath_var=LIBRARY_PATH
- ;;
-
-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'
- 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"
- sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
- # the default ld.so.conf also contains /usr/contrib/lib and
- # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
- # libtool to hard-code these into programs
- ;;
-
-cygwin* | mingw* | pw32* | cegcc*)
- version_type=windows
- shrext_cmds=.dll
- need_version=no
- need_lib_prefix=no
-
- case $GCC,$cc_basename in
- yes,*)
- # 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'\''`~
- 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'
- shlibpath_overrides_runpath=yes
-
- 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'
-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'
- ;;
- 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'
- ;;
- esac
- dynamic_linker='Win32 ld.exe'
- ;;
-
- *,cl*)
- # Native MSVC
- libname_spec='$name'
- soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
- library_names_spec='$libname.dll.lib'
-
- case $build_os in
- mingw*)
- sys_lib_search_path_spec=
- lt_save_ifs=$IFS
- IFS=';'
- for lt_path in $LIB
- do
- IFS=$lt_save_ifs
- # Let DOS variable expansion print the short 8.3 style file name.
- lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
- sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
- done
- IFS=$lt_save_ifs
- # Convert to MSYS style.
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
- ;;
- cygwin*)
- # Convert to unix form, then to dos form, then back to unix form
- # but this time dos style (no spaces!) so that the unix form looks
- # like /cygdrive/c/PROGRA~1:/cygdr...
- sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
- sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
- 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
- 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'`
- else
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
- fi
- # FIXME: find the short name or the path components, as spaces are
- # common. (e.g. "Program Files" -> "PROGRA~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'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname'
- postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $RM \$dlpath'
- shlibpath_overrides_runpath=yes
- dynamic_linker='Win32 link.exe'
- ;;
-
- *)
- # Assume MSVC wrapper
- library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
- dynamic_linker='Win32 ld.exe'
- ;;
- esac
- # FIXME: first we should search . and the directory the executable is in
- shlibpath_var=PATH
- ;;
-
-darwin* | rhapsody*)
- dynamic_linker="$host_os dyld"
- 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'
- shlibpath_overrides_runpath=yes
- shlibpath_var=DYLD_LIBRARY_PATH
- shrext_cmds='`test .$module = .yes && echo .so || 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'
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-freebsd* | dragonfly*)
- # DragonFly does not have aout. When/if they implement a new
- # versioning mechanism, adjust this.
- if test -x /usr/bin/objformat; then
- objformat=`/usr/bin/objformat`
- else
- case $host_os in
- freebsd[[23]].*) objformat=aout ;;
- *) objformat=elf ;;
- esac
- fi
- version_type=freebsd-$objformat
- case $version_type in
- freebsd-elf*)
- 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'
- need_version=yes
- ;;
- esac
- shlibpath_var=LD_LIBRARY_PATH
- case $host_os in
- freebsd2.*)
- shlibpath_overrides_runpath=yes
- ;;
- freebsd3.[[01]]* | freebsdelf3.[[01]]*)
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
- freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
- freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
- *) # from 4.6 on, and DragonFly
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
- esac
- ;;
-
-haiku*)
- version_type=linux # correct to gnu/linux during the next big refactor
- 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'
- shlibpath_var=LIBRARY_PATH
- shlibpath_overrides_runpath=no
- sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
- hardcode_into_libs=yes
- ;;
-
-hpux9* | hpux10* | hpux11*)
- # Give a soname corresponding to the major version so that dld.sl refuses to
- # link against other versions.
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- case $host_cpu in
- ia64*)
- shrext_cmds='.so'
- hardcode_into_libs=yes
- 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 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
- ;;
- hppa*64*)
- shrext_cmds='.sl'
- hardcode_into_libs=yes
- 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'
- sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
- ;;
- *)
- shrext_cmds='.sl'
- 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'
- ;;
- esac
- # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
- postinstall_cmds='chmod 555 $lib'
- # or fails outright, so override atomically:
- install_override_mode=555
- ;;
-
-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'
- dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
-
-irix5* | irix6* | nonstopux*)
- case $host_os in
- nonstopux*) version_type=nonstopux ;;
- *)
- 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
- fi ;;
- 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'
- case $host_os in
- irix5* | nonstopux*)
- libsuff= shlibsuff=
- ;;
- *)
- case $LD in # libtool.m4 will add one of these switches to LD
- *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
- libsuff= shlibsuff= libmagic=32-bit;;
- *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
- libsuff=32 shlibsuff=N32 libmagic=N32;;
- *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
- libsuff=64 shlibsuff=64 libmagic=64-bit;;
- *) libsuff= shlibsuff= libmagic=never-match;;
- esac
- ;;
- 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"
- hardcode_into_libs=yes
- ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-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'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
-
- # Some binutils ld are patched to set DT_RUNPATH
- AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
- [lt_cv_shlibpath_overrides_runpath=no
- save_LDFLAGS=$LDFLAGS
- save_libdir=$libdir
- eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
- LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
- AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
- [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
- [lt_cv_shlibpath_overrides_runpath=yes])])
- LDFLAGS=$save_LDFLAGS
- libdir=$save_libdir
- ])
- shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
-
- # 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
-
- # 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"
- fi
-
- # We used to test for /lib/ld.so.1 and disable shared libraries on
- # powerpc, because MkLinux only supported shared libraries with the
- # GNU dynamic linker. Since this was broken with cross compilers,
- # most powerpc-linux boxes support dynamic linking these days and
- # people can always --disable-shared, the test was removed, and we
- # assume the GNU/Linux dynamic linker is in use.
- 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'
- 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'
- dynamic_linker='NetBSD ld.elf_so'
- fi
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- ;;
-
-*nto* | *qnx*)
- 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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- dynamic_linker='ldqnx.so'
- ;;
-
-openbsd* | bitrig*)
- version_type=sunos
- sys_lib_dlsearch_path_spec=/usr/lib
- need_lib_prefix=no
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
- need_version=no
- else
- 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'
- version_type=windows
- shrext_cmds=.dll
- need_version=no
- need_lib_prefix=no
- # 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=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'
- 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
- ;;
-
-rdos*)
- dynamic_linker=no
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- # ldd complains unless libraries are executable
- postinstall_cmds='chmod +x $lib'
- ;;
-
-sunos4*)
- version_type=sunos
- 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 yes = "$with_gnu_ld"; then
- need_lib_prefix=no
- fi
- need_version=yes
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- case $host_vendor in
- sni)
- shlibpath_overrides_runpath=no
- need_lib_prefix=no
- runpath_var=LD_RUN_PATH
- ;;
- siemens)
- need_lib_prefix=no
- ;;
- motorola)
- need_lib_prefix=no
- need_version=no
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
- ;;
- esac
- ;;
-
-sysv4*MP*)
- 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'
- shlibpath_var=LD_LIBRARY_PATH
- fi
- ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- 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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- 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'
- case $host_os in
- sco3.2v5*)
- sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
- ;;
- esac
- fi
- sys_lib_dlsearch_path_spec='/usr/lib'
- ;;
-
-tpf*)
- # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
- 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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-*)
- dynamic_linker=no
- ;;
-esac
-AC_MSG_RESULT([$dynamic_linker])
-test no = "$dynamic_linker" && can_build_shared=no
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test yes = "$GCC"; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-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 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])
-_LT_DECL([], [need_lib_prefix], [0],
- [Do we need the "lib" prefix for modules?])
-_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
-_LT_DECL([], [version_type], [0], [Library versioning type])
-_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
-_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
-_LT_DECL([], [shlibpath_overrides_runpath], [0],
- [Is shlibpath searched before the hard-coded library search path?])
-_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
-_LT_DECL([], [library_names_spec], [1],
- [[List of archive names. First name is the real one, the rest are links.
- The last name is the one that the linker finds with -lNAME]])
-_LT_DECL([], [soname_spec], [1],
- [[The coded name of the library, if different from the real name]])
-_LT_DECL([], [install_override_mode], [1],
- [Permission mode override for installation of shared libraries])
-_LT_DECL([], [postinstall_cmds], [2],
- [Command to use after installation of a shared archive])
-_LT_DECL([], [postuninstall_cmds], [2],
- [Command to use after uninstallation of a shared archive])
-_LT_DECL([], [finish_cmds], [2],
- [Commands used to finish a libtool library installation in a directory])
-_LT_DECL([], [finish_eval], [1],
- [[As "finish_cmds", except a single script fragment to be evaled but
- not shown]])
-_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], [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 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_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
- test -z "$ac_dir" && ac_dir=.
- 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
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- $EGREP "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS=$lt_save_ifs
- MAGIC_CMD=$lt_save_MAGIC_CMD
- ;;
-esac])
-MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-if test -n "$MAGIC_CMD"; then
- AC_MSG_RESULT($MAGIC_CMD)
-else
- AC_MSG_RESULT(no)
-fi
-_LT_DECL([], [MAGIC_CMD], [0],
- [Used to examine libraries when file_magic_cmd begins with "file"])dnl
-])# _LT_PATH_TOOL_PREFIX
-
-# Old name:
-AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
-
-
-# _LT_PATH_MAGIC
-# --------------
-# 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
- if test -n "$ac_tool_prefix"; then
- _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
- else
- MAGIC_CMD=:
- fi
-fi
-])# _LT_PATH_MAGIC
-
-
-# LT_PATH_LD
-# ----------
-# find the pathname to the GNU or non-GNU linker
-AC_DEFUN([LT_PATH_LD],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-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 no = "$withval" || with_gnu_ld=yes],
- [with_gnu_ld=no])dnl
-
-ac_prog=ld
-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
- ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
- *)
- ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
- esac
- case $ac_prog in
- # Accept absolute paths.
- [[\\/]]* | ?:[[\\/]]*)
- re_direlt='/[[^/]][[^/]]*/\.\./'
- # Canonicalize the pathname of ld
- ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
- 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
- ;;
- "")
- # If it fails, then pretend we aren't using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
-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
- for ac_dir in $PATH; do
- 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
- # 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 no != "$with_gnu_ld" && break
- ;;
- *)
- test yes != "$with_gnu_ld" && break
- ;;
- esac
- fi
- done
- IFS=$lt_save_ifs
-else
- lt_cv_path_LD=$LD # Let the user override the test with a path.
-fi])
-LD=$lt_cv_path_LD
-if test -n "$LD"; then
- AC_MSG_RESULT($LD)
-else
- AC_MSG_RESULT(no)
-fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
-_LT_PATH_LD_GNU
-AC_SUBST([LD])
-
-_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
-])# LT_PATH_LD
-
-# Old names:
-AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
-AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_PROG_LD], [])
-dnl AC_DEFUN([AC_PROG_LD], [])
-
-
-# _LT_PATH_LD_GNU
-#- --------------
-m4_defun([_LT_PATH_LD_GNU],
-[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
-[# I'd rather use --version here, but apparently some GNU lds only accept -v.
-case `$LD -v 2>&1 </dev/null` in
-*GNU* | *'with BFD'*)
- lt_cv_prog_gnu_ld=yes
- ;;
-*)
- lt_cv_prog_gnu_ld=no
- ;;
-esac])
-with_gnu_ld=$lt_cv_prog_gnu_ld
-])# _LT_PATH_LD_GNU
-
-
-# _LT_CMD_RELOAD
-# --------------
-# find reload flag for linker
-# -- PORTME Some linkers may need a different reload flag.
-m4_defun([_LT_CMD_RELOAD],
-[AC_CACHE_CHECK([for $LD option to reload object files],
- lt_cv_ld_reload_flag,
- [lt_cv_ld_reload_flag='-r'])
-reload_flag=$lt_cv_ld_reload_flag
-case $reload_flag in
-"" | " "*) ;;
-*) reload_flag=" $reload_flag" ;;
-esac
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
- if test yes != "$GCC"; then
- reload_cmds=false
- fi
- ;;
- darwin*)
- 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
- ;;
-esac
-_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
-_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
-# -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_MAGIC_METHOD],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-AC_CACHE_CHECK([how to recognize dependent libraries],
-lt_cv_deplibs_check_method,
-[lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-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.
-# '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
-# 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]]*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-beos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-bsdi[[45]]*)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- lt_cv_file_magic_test_file=/shlib/libc.so
- ;;
-
-cygwin*)
- # func_win32_libid is a shell function defined in ltmain.sh
- lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
- lt_cv_file_magic_cmd='func_win32_libid'
- ;;
-
-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.
- 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
- # Keep this pattern in sync with the one in func_win32_libid.
- lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- fi
- ;;
-
-cegcc*)
- # use the weaker test based on 'objdump'. See mingw*.
- lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- ;;
-
-darwin* | rhapsody*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-freebsd* | dragonfly*)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
- case $host_cpu in
- i*86 )
- # Not sure whether the presence of OpenBSD here was a mistake.
- # Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- ;;
- esac
- else
- lt_cv_deplibs_check_method=pass_all
- fi
- ;;
-
-haiku*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-hpux10.20* | hpux11*)
- lt_cv_file_magic_cmd=/usr/bin/file
- case $host_cpu in
- ia64*)
- lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
- lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
- ;;
- hppa*64*)
- [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
- lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
- ;;
- *)
- lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
- lt_cv_file_magic_test_file=/usr/lib/libc.sl
- ;;
- esac
- ;;
-
-interix[[3-9]]*)
- # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
- lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
- ;;
-
-irix5* | irix6* | nonstopux*)
- case $LD in
- *-32|*"-32 ") libmagic=32-bit;;
- *-n32|*"-n32 ") libmagic=N32;;
- *-64|*"-64 ") libmagic=64-bit;;
- *) libmagic=never-match;;
- esac
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-netbsd* | netbsdelf*-gnu)
- 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
- lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
- fi
- ;;
-
-newos6*)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libnls.so
- ;;
-
-*nto* | *qnx*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-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)$'
- fi
- ;;
-
-osf3* | osf4* | osf5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-rdos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-solaris*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv4 | sysv4.3*)
- case $host_vendor in
- motorola)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
- ;;
- ncr)
- lt_cv_deplibs_check_method=pass_all
- ;;
- sequent)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
- ;;
- sni)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
- siemens)
- lt_cv_deplibs_check_method=pass_all
- ;;
- pc)
- lt_cv_deplibs_check_method=pass_all
- ;;
- esac
- ;;
-
-tpf*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-os2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-esac
-])
-
-file_magic_glob=
-want_nocaseglob=no
-if test "$build" = "$host"; then
- case $host_os in
- mingw* | pw32*)
- if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
- want_nocaseglob=yes
- else
- file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
- fi
- ;;
- esac
-fi
-
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-_LT_DECL([], [deplibs_check_method], [1],
- [Method to check whether dependent libraries are shared objects])
-_LT_DECL([], [file_magic_cmd], [1],
- [Command to use when deplibs_check_method = "file_magic"])
-_LT_DECL([], [file_magic_glob], [1],
- [How to find potential files when deplibs_check_method = "file_magic"])
-_LT_DECL([], [want_nocaseglob], [1],
- [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
-])# _LT_CHECK_MAGIC_METHOD
-
-
-# LT_PATH_NM
-# ----------
-# find the pathname to a BSD- or MS-compatible name lister
-AC_DEFUN([LT_PATH_NM],
-[AC_REQUIRE([AC_PROG_CC])dnl
-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
-else
- 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
- for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
- 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
- # Check to see if the nm accepts a BSD-compat flag.
- # 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
- # 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 2
- ;;
- *)
- case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
- */dev/null*)
- lt_cv_path_NM="$tmp_nm -p"
- break 2
- ;;
- *)
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
- ;;
- esac
- ;;
- esac
- fi
- done
- IFS=$lt_save_ifs
- done
- : ${lt_cv_path_NM=no}
-fi])
-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 -headers /dev/null 2>&1 | sed '1q'` in
- *COFF*)
- DUMPBIN="$DUMPBIN -symbols -headers"
- ;;
- *)
- DUMPBIN=:
- ;;
- esac
- fi
- AC_SUBST([DUMPBIN])
- if test : != "$DUMPBIN"; then
- NM=$DUMPBIN
- fi
-fi
-test -z "$NM" && NM=nm
-AC_SUBST([NM])
-_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
-
-AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
- [lt_cv_nm_interface="BSD nm"
- echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
- (eval "$ac_compile" 2>conftest.err)
- cat conftest.err >&AS_MESSAGE_LOG_FD
- (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
- (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
- cat conftest.err >&AS_MESSAGE_LOG_FD
- (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
- cat conftest.out >&AS_MESSAGE_LOG_FD
- if $GREP 'External.*some_variable' conftest.out > /dev/null; then
- lt_cv_nm_interface="MS dumpbin"
- fi
- rm -f conftest*])
-])# LT_PATH_NM
-
-# Old names:
-AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
-AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_PROG_NM], [])
-dnl AC_DEFUN([AC_PROG_NM], [])
-
-# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-# --------------------------------
-# how to determine the name of the shared library
-# associated with a specific link library.
-# -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-m4_require([_LT_DECL_DLLTOOL])
-AC_CACHE_CHECK([how to associate runtime and link libraries],
-lt_cv_sharedlib_from_linklib_cmd,
-[lt_cv_sharedlib_from_linklib_cmd='unknown'
-
-case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
- # 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
- ;;
- *)
- lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
- ;;
- esac
- ;;
-*)
- # fallback: assume linklib IS sharedlib
- lt_cv_sharedlib_from_linklib_cmd=$ECHO
- ;;
-esac
-])
-sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
-test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
-
-_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
- [Command to associate shared and link libraries])
-])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-
-
-# _LT_PATH_MANIFEST_TOOL
-# ----------------------
-# locate the manifest tool
-m4_defun([_LT_PATH_MANIFEST_TOOL],
-[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
-test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
- [lt_cv_path_mainfest_tool=no
- echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
- $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
- cat conftest.err >&AS_MESSAGE_LOG_FD
- if $GREP 'Manifest Tool' conftest.out > /dev/null; then
- lt_cv_path_mainfest_tool=yes
- fi
- rm -f conftest*])
-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
-AC_DEFUN([LT_LIB_M],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-LIBM=
-case $host in
-*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
- # These system don't have libm, or don't need it
- ;;
-*-ncr-sysv4.3*)
- AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
- AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
- ;;
-*)
- AC_CHECK_LIB(m, cos, LIBM=-lm)
- ;;
-esac
-AC_SUBST([LIBM])
-])# LT_LIB_M
-
-# Old name:
-AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_CHECK_LIBM], [])
-
-
-# _LT_COMPILER_NO_RTTI([TAGNAME])
-# -------------------------------
-m4_defun([_LT_COMPILER_NO_RTTI],
-[m4_require([_LT_TAG_COMPILER])dnl
-
-_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-
-if test yes = "$GCC"; then
- case $cc_basename in
- nvcc*)
- _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
- esac
-
- _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
- lt_cv_prog_compiler_rtti_exceptions,
- [-fno-rtti -fno-exceptions], [],
- [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
-fi
-_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
- [Compiler flag to turn off builtin functions])
-])# _LT_COMPILER_NO_RTTI
-
-
-# _LT_CMD_GLOBAL_SYMBOLS
-# ----------------------
-m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_PROG_AWK])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-AC_MSG_CHECKING([command to parse $NM output from $compiler object])
-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
-[
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix. What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[[BCDEGRST]]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
-
-# Define system-specific variables.
-case $host_os in
-aix*)
- symcode='[[BCDT]]'
- ;;
-cygwin* | mingw* | pw32* | cegcc*)
- symcode='[[ABCDGISTW]]'
- ;;
-hpux*)
- if test ia64 = "$host_cpu"; then
- symcode='[[ABCDEGRST]]'
- fi
- ;;
-irix* | nonstopux*)
- symcode='[[BCDEGRST]]'
- ;;
-osf*)
- symcode='[[BCDEGQRST]]'
- ;;
-solaris*)
- symcode='[[BDRT]]'
- ;;
-sco3.2v5*)
- symcode='[[DT]]'
- ;;
-sysv4.2uw2*)
- symcode='[[DT]]'
- ;;
-sysv5* | sco5v6* | unixware* | OpenUNIX*)
- symcode='[[ABDT]]'
- ;;
-sysv4)
- symcode='[[DFNSTU]]'
- ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-case `$NM -V 2>&1` in
-*GNU* | *'with BFD'*)
- 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"\
-$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"\
-$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=
-case $build_os in
-mingw*)
- opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
- ;;
-esac
-
-# Try without a prefix underscore, then with it.
-for ac_symprfx in "" "_"; do
-
- # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
- symxfrm="\\1 $ac_symprfx\\2 \\2"
-
- # 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,
- # 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=\"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'"
- fi
- lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
-
- # Check to see that the pipe works correctly.
- pipe_works=no
-
- rm -f conftest*
- cat > conftest.$ac_ext <<_LT_EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(void);
-void nm_test_func(void){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-_LT_EOF
-
- if AC_TRY_EVAL(ac_compile); then
- # Now try to grab the symbols.
- nlist=conftest.nm
- $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD
- if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then
- # Try sorting and uniquifying the output.
- if sort "$nlist" | uniq > "$nlist"T; then
- mv -f "$nlist"T "$nlist"
- else
- rm -f "$nlist"T
- fi
-
- # Make sure that we snagged all the symbols we need.
- if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
- 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 can't be const, because runtime
- relocations are performed -- see ld's documentation on pseudo-relocs. */
-# define LT@&t@_DLSYM_CONST
-#elif defined __osf__
-/* This system does not cope well with relocations in const data. */
-# define LT@&t@_DLSYM_CONST
-#else
-# define LT@&t@_DLSYM_CONST const
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-_LT_EOF
- # Now generate the symbol file.
- eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
-
- cat <<_LT_EOF >> conftest.$ac_ext
-
-/* The mapping between symbol names and symbols. */
-LT@&t@_DLSYM_CONST struct {
- const char *name;
- void *address;
-}
-lt__PROGRAM__LTX_preloaded_symbols[[]] =
-{
- { "@PROGRAM@", (void *) 0 },
-_LT_EOF
- $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
- cat <<\_LT_EOF >> conftest.$ac_ext
- {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
- return lt__PROGRAM__LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-_LT_EOF
- # Now try linking the two files.
- mv conftest.$ac_objext conftstm.$ac_objext
- lt_globsym_save_LIBS=$LIBS
- lt_globsym_save_CFLAGS=$CFLAGS
- 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
- pipe_works=yes
- fi
- LIBS=$lt_globsym_save_LIBS
- CFLAGS=$lt_globsym_save_CFLAGS
- else
- echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
- fi
- else
- echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
- fi
- else
- echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
- fi
- else
- echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
- cat conftest.$ac_ext >&5
- fi
- rm -rf conftest* conftst*
-
- # Do not use the global_symbol_pipe unless it works.
- if test yes = "$pipe_works"; then
- break
- else
- lt_cv_sys_global_symbol_pipe=
- fi
-done
-])
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
- lt_cv_sys_global_symbol_to_cdecl=
-fi
-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
- AC_MSG_RESULT(failed)
-else
- AC_MSG_RESULT(ok)
-fi
-
-# Response file support.
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- nm_file_list_spec='@'
-elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
- nm_file_list_spec='@'
-fi
-
-_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
-
-
-# _LT_COMPILER_PIC([TAGNAME])
-# ---------------------------
-m4_defun([_LT_COMPILER_PIC],
-[m4_require([_LT_TAG_COMPILER])dnl
-_LT_TAGVAR(lt_prog_compiler_wl, $1)=
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=
-_LT_TAGVAR(lt_prog_compiler_static, $1)=
-
-m4_if([$1], [CXX], [
- # C++ specific cases for pic, static, wl, etc.
- 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 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*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- 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'.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
- ;;
- esac
- ;;
-
- beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
- # PIC is the default for these OSes.
- ;;
- mingw* | cygwin* | os2* | pw32* | 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).
- # Although the cygwin gcc ignores -fPIC, still need this for old-style
- # (--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
- # Common symbols not allowed in MH_DYLIB files
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
- ;;
- *djgpp*)
- # DJGPP does not support shared libraries at all
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=
- ;;
- haiku*)
- # PIC is the default for Haiku.
- # The "-static" flag exists, but is broken.
- _LT_TAGVAR(lt_prog_compiler_static, $1)=
- ;;
- interix[[3-9]]*)
- # Interix 3.x gcc -fpic/-fPIC options generate broken code.
- # Instead, we relocate shared libraries at runtime.
- ;;
- sysv4*MP*)
- if test -d /usr/nec; then
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
- fi
- ;;
- hpux*)
- # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
- # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
- # sets the default TLS model and affects inlining.
- case $host_cpu in
- hppa*64*)
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- esac
- ;;
- *qnx* | *nto*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- esac
- else
- case $host_os in
- aix[[4-9]]*)
- # All AIX code is PIC.
- if test ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- else
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
- fi
- ;;
- chorus*)
- case $cc_basename in
- cxch68*)
- # Green Hills C++ Compiler
- # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
- ;;
- esac
- ;;
- mingw* | cygwin* | os2* | pw32* | 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'])
- ;;
- dgux*)
- case $cc_basename in
- ec++*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- ;;
- ghcx*)
- # Green Hills C++ Compiler
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- ;;
- *)
- ;;
- esac
- ;;
- freebsd* | dragonfly*)
- # FreeBSD uses GNU C++
- ;;
- hpux9* | hpux10* | hpux11*)
- 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 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'
- case $host_cpu in
- hppa*64*|ia64*)
- # +Z the default
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
- ;;
- esac
- ;;
- *)
- ;;
- esac
- ;;
- interix*)
- # This is c89, which is MS Visual C++ (no shared libs)
- # Anyone wants to do a port?
- ;;
- irix5* | irix6* | nonstopux*)
- case $cc_basename in
- CC*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- # CC pic flag -KPIC is the default.
- ;;
- *)
- ;;
- esac
- ;;
- linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- case $cc_basename in
- KCC*)
- # KAI C++ Compiler
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- ecpc* )
- # 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'
- ;;
- icpc* )
- # Intel C++, used to be incompatible with GCC.
- # ICC 10 doesn't accept -KPIC any more.
- _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* | pgcpp*)
- # Portland Group 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)='-Bstatic'
- ;;
- cxx*)
- # Compaq C++
- # Make sure the PIC flag is empty. It appears that all Alpha
- # Linux and Compaq Tru64 Unix objects are PIC.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
- xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
- # IBM XL 8.0, 9.0 on PPC and BlueGene
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
- ;;
- *)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ C*)
- # Sun C++ 5.9
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
- ;;
- esac
- ;;
- esac
- ;;
- lynxos*)
- ;;
- m88k*)
- ;;
- mvs*)
- case $cc_basename in
- cxx*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
- ;;
- *)
- ;;
- esac
- ;;
- netbsd* | netbsdelf*-gnu)
- ;;
- *qnx* | *nto*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
- ;;
- osf3* | osf4* | osf5*)
- case $cc_basename in
- KCC*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
- ;;
- RCC*)
- # Rational C++ 2.4.1
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- ;;
- cxx*)
- # Digital/Compaq C++
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # Make sure the PIC flag is empty. It appears that all Alpha
- # Linux and Compaq Tru64 Unix objects are PIC.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
- *)
- ;;
- esac
- ;;
- psos*)
- ;;
- solaris*)
- case $cc_basename in
- CC* | sunCC*)
- # Sun C++ 4.2, 5.x and Centerline C++
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
- ;;
- gcx*)
- # Green Hills C++ Compiler
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
- ;;
- *)
- ;;
- esac
- ;;
- sunos4*)
- case $cc_basename in
- CC*)
- # Sun C++ 4.x
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- lcc*)
- # Lucid
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- ;;
- *)
- ;;
- esac
- ;;
- sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
- case $cc_basename in
- CC*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- esac
- ;;
- tandem*)
- case $cc_basename in
- NCC*)
- # NonStop-UX NCC 3.20
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- ;;
- *)
- ;;
- esac
- ;;
- vxworks*)
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
- ;;
- esac
- fi
-],
-[
- 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 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*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- 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'.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
- ;;
- esac
- ;;
-
- beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
- # PIC is the default for these OSes.
- ;;
-
- 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).
- # Although the cygwin gcc ignores -fPIC, still need this for old-style
- # (--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
- # Common symbols not allowed in MH_DYLIB files
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
- ;;
-
- haiku*)
- # PIC is the default for Haiku.
- # The "-static" flag exists, but is broken.
- _LT_TAGVAR(lt_prog_compiler_static, $1)=
- ;;
-
- hpux*)
- # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
- # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
- # sets the default TLS model and affects inlining.
- case $host_cpu in
- hppa*64*)
- # +Z the default
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- esac
- ;;
-
- interix[[3-9]]*)
- # Interix 3.x gcc -fpic/-fPIC options generate broken code.
- # Instead, we relocate shared libraries at runtime.
- ;;
-
- msdosdjgpp*)
- # Just because we use GCC doesn't mean we suddenly get shared libraries
- # on systems that don't support them.
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
- enable_shared=no
- ;;
-
- *nto* | *qnx*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
- fi
- ;;
-
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- esac
-
- case $cc_basename in
- nvcc*) # Cuda Compiler Driver 2.2
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
- if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
- _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
- fi
- ;;
- esac
- else
- # PORTME Check for flag to pass linker flags through the system compiler.
- case $host_os in
- aix*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- if test ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- else
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
- 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*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
- # not for PA HP-UX.
- case $host_cpu in
- hppa*64*|ia64*)
- # +Z the default
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
- ;;
- 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'
- ;;
-
- irix5* | irix6* | nonstopux*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # PIC (with -KPIC) is the default.
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
-
- linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- case $cc_basename in
- # 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'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- # flang / f18. f95 an alias for gfortran or flang on Debian
- flang* | f18* | f95*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- # icc used to be incompatible with GCC.
- # ICC 10 doesn't accept -KPIC any more.
- icc* | ifort*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- # Lahey Fortran 8.1.
- lf95*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
- ;;
- 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'
- ;;
- 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)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- ccc*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # All Alpha code is PIC.
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
- xl* | bgxl* | bgf* | mpixl*)
- # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
- ;;
- *)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
- # Sun Fortran 8.3 passes all unrecognized flags to the linker
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
- ;;
- *Sun\ F* | *Sun*Fortran*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
- ;;
- *Sun\ C*)
- # Sun C 5.9
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- ;;
- *Intel*\ [[CF]]*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'
- ;;
- *Portland\ Group*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- esac
- ;;
- esac
- ;;
-
- newsos6)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- *nto* | *qnx*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
- ;;
-
- osf3* | osf4* | osf5*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # All OSF/1 code is PIC.
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
-
- rdos*)
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
-
- solaris*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- case $cc_basename in
- f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
- *)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
- esac
- ;;
-
- sunos4*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- sysv4 | sysv4.2uw2* | sysv4.3*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- fi
- ;;
-
- sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- unicos*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
- ;;
-
- uts4*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- *)
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
- ;;
- esac
- fi
-])
-case $host_os in
- # For platforms that do not support PIC, -DPIC is meaningless:
- *djgpp*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
- ;;
-esac
-
-AC_CACHE_CHECK([for $compiler option to produce PIC],
- [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
- [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
-
-#
-# Check to make sure the PIC flag actually works.
-#
-if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
- _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
- [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
- [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
- [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
- "" | " "*) ;;
- *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
- esac],
- [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
-fi
-_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
- [Additional compiler flags for building library objects])
-
-_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
- [How to pass a linker flag through the compiler])
-#
-# Check to make sure the static flag actually works.
-#
-wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
-_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
- _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
- $lt_tmp_static_flag,
- [],
- [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
-_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
- [Compiler flag to prevent dynamic linking])
-])# _LT_COMPILER_PIC
-
-
-# _LT_LINKER_SHLIBS([TAGNAME])
-# ----------------------------
-# See if the linker supports building shared libraries.
-m4_defun([_LT_LINKER_SHLIBS],
-[AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
-m4_if([$1], [CXX], [
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
- _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
- 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 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) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
- else
- _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
- ;;
- cygwin* | mingw* | cegcc*)
- case $cc_basename in
- cl*)
- _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
- ;;
- *)
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
- _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
- ;;
- 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'
- ;;
- esac
-], [
- runpath_var=
- _LT_TAGVAR(allow_undefined_flag, $1)=
- _LT_TAGVAR(always_export_symbols, $1)=no
- _LT_TAGVAR(archive_cmds, $1)=
- _LT_TAGVAR(archive_expsym_cmds, $1)=
- _LT_TAGVAR(compiler_needs_object, $1)=no
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
- _LT_TAGVAR(export_dynamic_flag_spec, $1)=
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
- _LT_TAGVAR(hardcode_automatic, $1)=no
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_direct_absolute, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
- _LT_TAGVAR(hardcode_libdir_separator, $1)=
- _LT_TAGVAR(hardcode_minus_L, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
- _LT_TAGVAR(inherit_rpath, $1)=no
- _LT_TAGVAR(link_all_deplibs, $1)=unknown
- _LT_TAGVAR(module_cmds, $1)=
- _LT_TAGVAR(module_expsym_cmds, $1)=
- _LT_TAGVAR(old_archive_from_new_cmds, $1)=
- _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
- _LT_TAGVAR(thread_safe_flag_spec, $1)=
- _LT_TAGVAR(whole_archive_flag_spec, $1)=
- # include_expsyms should be a list of space-separated symbols to be *always*
- # 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'.
- _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
- # the symbol is explicitly referenced. Since portable code cannot
- # rely on this symbol name, it's probably fine to never include it in
- # preloaded symbol tables.
- # Exclude shared library initialization/finalization symbols.
-dnl Note also adjust exclude_expsyms for C++ above.
- extract_expsyms_cmds=
-
- case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
- # 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 yes != "$GCC"; then
- with_gnu_ld=no
- fi
- ;;
- interix*)
- # we just hope/assume this is gcc and not c89 (= MSVC++)
- with_gnu_ld=yes
- ;;
- 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
-
- # 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 yes = "$with_gnu_ld"; then
- case $host_os in
- aix*)
- # The AIX port of GNU ld has always aspired to compatibility
- # with the native linker. However, as the warning in the GNU ld
- # block says, versions before 2.19.5* couldn't really create working
- # shared libraries, regardless of the interface used.
- case `$LD -v 2>&1` in
- *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
- *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
- *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
- *)
- lt_use_gnu_ld_interface=yes
- ;;
- esac
- ;;
- *)
- lt_use_gnu_ld_interface=yes
- ;;
- esac
- fi
-
- if test yes = "$lt_use_gnu_ld_interface"; then
- # If archive_cmds runs LD, not CC, wlarc should be empty
- 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'
- # 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'
- else
- _LT_TAGVAR(whole_archive_flag_spec, $1)=
- fi
- supports_anon_versioning=no
- 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 ...
- *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
- *\ 2.11.*) ;; # other 2.11 versions
- *) supports_anon_versioning=yes ;;
- esac
-
- # See if GNU ld supports shared libraries.
- case $host_os in
- aix[[3-9]]*)
- # On AIX/PPC, the GNU linker is very broken
- if test ia64 != "$host_cpu"; then
- _LT_TAGVAR(ld_shlibs, $1)=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.19, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support. If you
-*** really care for shared libraries, you may want to install binutils
-*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
-*** You will then need to restart the configuration process.
-
-_LT_EOF
- fi
- ;;
-
- amigaos*)
- 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_expsym_cmds, $1)=''
- ;;
- m68k)
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- ;;
- esac
- ;;
-
- beos*)
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; 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'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- # _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(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(always_export_symbols, $1)=no
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
- _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, 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(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'
- # 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'
- ;;
-
- gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
- tmp_diet=no
- 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 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'
- 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'
- tmp_addflag=' $pic_flag -Mnomain' ;;
- ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
- tmp_addflag=' -i_dynamic' ;;
- efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
- tmp_addflag=' -i_dynamic -nofor_main' ;;
- ifc* | ifort*) # Intel Fortran compiler
- tmp_addflag=' -nofor_main' ;;
- 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(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(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'
-
- 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'
- 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(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $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~
- $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
- fi
- ;;
- esac
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- netbsd* | netbsdelf*-gnu)
- 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'
- fi
- ;;
-
- solaris*)
- if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
- _LT_TAGVAR(ld_shlibs, $1)=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_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'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
- case `$LD -v 2>&1` in
- *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
- _LT_TAGVAR(ld_shlibs, $1)=no
- cat <<_LT_EOF 1>&2
-
-*** 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
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
- ;;
- *)
- # For security reasons, it is highly recommended that you always
- # use absolute paths for naming shared libraries, and exclude the
- # 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'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
- ;;
-
- sunos4*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- wlarc=
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- *)
- 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'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
-
- 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)=
- _LT_TAGVAR(whole_archive_flag_spec, $1)=
- fi
- else
- # PORTME fill in a description of your system's linker (not GNU ld)
- case $host_os in
- aix3*)
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(always_export_symbols, $1)=yes
- _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
- # 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 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
- fi
- ;;
-
- aix[[4-9]]*)
- 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=
- else
- # If we're using GNU nm, then we don't want the "-C" option.
- # -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) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
- else
- _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
- # 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 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
-
- exp_sym_flag='-bexport'
- no_entry_flag='-bnoentry'
- fi
-
- # When large executables or shared objects are built, AIX ld can
- # have problems creating the table of contents. If linking a library
- # or program results in "error TOC overflow" add -mminimal-toc to
- # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
- # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
- _LT_TAGVAR(archive_cmds, $1)=''
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _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,'
- 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 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`
- if test -f "$collect2name" &&
- strings "$collect2name" | $GREP resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- :
- else
- # We have old collect2
- _LT_TAGVAR(hardcode_direct, $1)=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=
- fi
- ;;
- esac
- shared_flag='-shared'
- 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 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 yes = "$aix_use_runtimelinking"; then
- shared_flag='$wl-G'
- else
- 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'
- # 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,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 -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 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"
- 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"
- # 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 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'
- 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
- _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
- ;;
-
- amigaos*)
- 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_expsym_cmds, $1)=''
- ;;
- m68k)
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- ;;
- esac
- ;;
-
- bsdi[[45]]*)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- case $cc_basename in
- cl*)
- # Native MSVC
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(always_export_symbols, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='@'
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- 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,-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
- _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
- # 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'
- ;;
- *)
- # Assume MSVC wrapper
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- 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.
- _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
- # FIXME: Should let the user specify the lib program.
- _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- ;;
- esac
- ;;
-
- darwin* | rhapsody*)
- _LT_DARWIN_LINKER_FEATURES($1)
- ;;
-
- dgux*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
- # support. Future versions do this automatically, but an explicit c++rt0.o
- # does not break anything, and helps significantly (at the cost of a little
- # extra space).
- freebsd2.2*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- # Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2.*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | dragonfly*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- hpux9*)
- 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 "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_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'
- ;;
-
- hpux10*)
- 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 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'
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- fi
- ;;
-
- hpux11*)
- 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'
- ;;
- 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+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'
- ;;
- ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- *)
- m4_if($1, [], [
- # Older versions of the 11.00 compiler do not understand -b yet
- # (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)='$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'])
- ;;
- esac
- fi
- 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(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
- *)
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _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
- ;;
- esac
- fi
- ;;
-
- irix5* | irix6* | nonstopux*)
- 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"
- AC_LINK_IFELSE(
- [AC_LANG_SOURCE(
- [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
- [C++], [[int foo (void) { return 0; }]],
- [Fortran 77], [[
- subroutine foo
- end]],
- [Fortran], [[
- subroutine foo
- end]])])],
- [lt_cv_irix_exported_symbol=yes],
- [lt_cv_irix_exported_symbol=no])
- 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
- _LT_TAGVAR(link_all_deplibs, $1)=no
- 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'
- fi
- _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _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
- ;;
-
- 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* | netbsdelf*-gnu)
- 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
- _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
- fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- 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_separator, $1)=:
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- *nto* | *qnx*)
- ;;
-
- 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__`"; 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'
- else
- _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
- fi
- ;;
-
- 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
- ;;
-
- osf3*)
- 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'
- fi
- _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _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 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_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'
-
- # Both c and cxx compiler support -rpath directly
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
- fi
- _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
- ;;
-
- solaris*)
- _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
- 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'
- 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_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'
- ;;
- *)
- 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'
- ;;
- esac
- fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- case $host_os in
- 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 is careful enough not to reorder.
- # Supported since Solaris 2.6 (maybe 2.5.1?)
- 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
- ;;
- esac
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- ;;
-
- sunos4*)
- 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'
- else
- _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
- fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- sysv4)
- case $host_vendor in
- sni)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
- ;;
- siemens)
- ## LD is ld it makes a PLAMLIB
- ## CC just makes a GrossModule.
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
- _LT_TAGVAR(hardcode_direct, $1)=no
- ;;
- motorola)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
- ;;
- esac
- runpath_var='LD_RUN_PATH'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- sysv4.3*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- _LT_TAGVAR(ld_shlibs, $1)=yes
- fi
- ;;
-
- sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
- _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 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'
- fi
- ;;
-
- sysv5* | sco3.2v5* | sco5v6*)
- # 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(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_separator, $1)=':'
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
- runpath_var='LD_RUN_PATH'
-
- 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'
- fi
- ;;
-
- uts4*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- *)
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
-
- if test sni = "$host_vendor"; then
- case $host in
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
- ;;
- esac
- fi
- fi
-])
-AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
-
-_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
-
-_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
-_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
-_LT_DECL([], [extract_expsyms_cmds], [2],
- [The commands to extract the exported symbol list from a shared archive])
-
-#
-# Do we need to explicitly link libc?
-#
-case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
-x|xyes)
- # Assume -lc should be added
- _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-
- 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.
- ;;
- '$CC '*)
- # Test whether the compiler implicitly links with -lc since on some
- # systems, -lgcc has to come before -lc. If gcc already passes -lc
- # to ld, don't add -lc before -lgcc.
- AC_CACHE_CHECK([whether -lc should be explicitly linked in],
- [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
- [$RM conftest*
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
- soname=conftest
- lib=conftest
- libobjs=conftest.$ac_objext
- deplibs=
- wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
- pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
- compiler_flags=-v
- linker_flags=-v
- verstring=
- output_objdir=.
- libname=conftest
- lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
- _LT_TAGVAR(allow_undefined_flag, $1)=
- if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
- then
- lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
- else
- lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- fi
- _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
- else
- cat conftest.err 1>&5
- fi
- $RM conftest*
- ])
- _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
- ;;
- esac
- fi
- ;;
-esac
-
-_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
- [Whether or not to add -lc for building shared libraries])
-_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
- [enable_shared_with_static_runtimes], [0],
- [Whether or not to disallow shared libs when runtime libs are static])
-_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
- [Compiler flag to allow reflexive dlopens])
-_LT_TAGDECL([], [whole_archive_flag_spec], [1],
- [Compiler flag to generate shared objects directly from archives])
-_LT_TAGDECL([], [compiler_needs_object], [1],
- [Whether the compiler copes with passing no objects directly])
-_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
- [Create an old-style archive from a shared archive])
-_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
- [Create a temporary old-style archive to link instead of a shared archive])
-_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
-_LT_TAGDECL([], [archive_expsym_cmds], [2])
-_LT_TAGDECL([], [module_cmds], [2],
- [Commands used to build a loadable module if different from building
- a shared archive.])
-_LT_TAGDECL([], [module_expsym_cmds], [2])
-_LT_TAGDECL([], [with_gnu_ld], [1],
- [Whether we are building with GNU ld or not])
-_LT_TAGDECL([], [allow_undefined_flag], [1],
- [Flag that allows shared libraries with undefined symbols to be built])
-_LT_TAGDECL([], [no_undefined_flag], [1],
- [Flag that enforces no undefined symbols])
-_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
- [Flag to hardcode $libdir into a binary during linking.
- This must work even if $libdir does not exist])
-_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
- DIR into the resulting binary])
-_LT_TAGDECL([], [hardcode_direct_absolute], [0],
- [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
- library is relocated])
-_LT_TAGDECL([], [hardcode_minus_L], [0],
- [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
- into the resulting binary])
-_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
- [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
- into the resulting binary])
-_LT_TAGDECL([], [hardcode_automatic], [0],
- [Set to "yes" if building a shared library automatically hardcodes DIR
- into the library and all subsequent libraries and executables linked
- against it])
-_LT_TAGDECL([], [inherit_rpath], [0],
- [Set to yes if linker adds runtime paths of dependent libraries
- to runtime path list])
-_LT_TAGDECL([], [link_all_deplibs], [0],
- [Whether libtool must link a program against all its dependency libraries])
-_LT_TAGDECL([], [always_export_symbols], [0],
- [Set to "yes" if exported symbols are required])
-_LT_TAGDECL([], [export_symbols_cmds], [2],
- [The commands to list exported symbols])
-_LT_TAGDECL([], [exclude_expsyms], [1],
- [Symbols that should not be listed in the preloaded symbols])
-_LT_TAGDECL([], [include_expsyms], [1],
- [Symbols that must always be exported])
-_LT_TAGDECL([], [prelink_cmds], [2],
- [Commands necessary for linking programs (against libraries) with templates])
-_LT_TAGDECL([], [postlink_cmds], [2],
- [Commands necessary for finishing linking programs])
-_LT_TAGDECL([], [file_list_spec], [1],
- [Specify filename containing input files])
-dnl FIXME: Not yet implemented
-dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
-dnl [Compiler flag to generate thread safe objects])
-])# _LT_LINKER_SHLIBS
-
-
-# _LT_LANG_C_CONFIG([TAG])
-# ------------------------
-# 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'.
-m4_defun([_LT_LANG_C_CONFIG],
-[m4_require([_LT_DECL_EGREP])dnl
-lt_save_CC=$CC
-AC_LANG_PUSH(C)
-
-# Source file extension for C test sources.
-ac_ext=c
-
-# Object file extension for compiled C test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="int some_variable = 0;"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='int main(){return(0);}'
-
-_LT_TAG_COMPILER
-# Save the default compiler, since it gets overwritten when the other
-# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
-compiler_DEFAULT=$CC
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-if test -n "$compiler"; then
- _LT_COMPILER_NO_RTTI($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_SYS_DYNAMIC_LINKER($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
- LT_SYS_DLOPEN_SELF
- _LT_CMD_STRIPLIB
-
- # 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 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 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 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
- AC_MSG_RESULT([$enable_shared])
-
- AC_MSG_CHECKING([whether to build static libraries])
- # Make sure either enable_shared or enable_static is yes.
- test yes = "$enable_shared" || enable_static=yes
- AC_MSG_RESULT([$enable_static])
-
- _LT_CONFIG($1)
-fi
-AC_LANG_POP
-CC=$lt_save_CC
-])# _LT_LANG_C_CONFIG
-
-
-# _LT_LANG_CXX_CONFIG([TAG])
-# --------------------------
-# 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'.
-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 no != "$CXX" &&
- ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
- (test g++ != "$CXX"))); then
- AC_PROG_CXXCPP
-else
- _lt_caught_CXX_error=yes
-fi
-
-AC_LANG_PUSH(C++)
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(compiler_needs_object, $1)=no
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for C++ test sources.
-ac_ext=cpp
-
-# Object file extension for compiled C++ test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# 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 yes != "$_lt_caught_CXX_error"; then
- # Code to be used in simple compile tests
- lt_simple_compile_test_code="int some_variable = 0;"
-
- # Code to be used in simple link tests
- lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
-
- # ltmain only uses $CC for tagged configurations so make sure $CC is set.
- _LT_TAG_COMPILER
-
- # save warnings/boilerplate of simple test code
- _LT_COMPILER_BOILERPLATE
- _LT_LINKER_BOILERPLATE
-
- # Allow CC to be a program name with arguments.
- lt_save_CC=$CC
- lt_save_CFLAGS=$CFLAGS
- lt_save_LD=$LD
- lt_save_GCC=$GCC
- GCC=$GXX
- lt_save_with_gnu_ld=$with_gnu_ld
- lt_save_path_LD=$lt_cv_path_LD
- if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
- lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
- else
- $as_unset lt_cv_prog_gnu_ld
- fi
- if test -n "${lt_cv_path_LDCXX+set}"; then
- lt_cv_path_LD=$lt_cv_path_LDCXX
- else
- $as_unset lt_cv_path_LD
- fi
- test -z "${LDCXX+set}" || LD=$LDCXX
- CC=${CXX-"c++"}
- CFLAGS=$CXXFLAGS
- compiler=$CC
- _LT_TAGVAR(compiler, $1)=$CC
- _LT_CC_BASENAME([$compiler])
-
- if test -n "$compiler"; then
- # We don't want -fno-exception when compiling C++ code, so set the
- # no_builtin_flag separately
- 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 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 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'
-
- # 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'
-
- # 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'
- else
- _LT_TAGVAR(whole_archive_flag_spec, $1)=
- fi
- else
- with_gnu_ld=no
- wlarc=
-
- # A generic and very simple default shared library creation
- # command for GNU C++ for the case where it uses the native
- # linker, instead of GNU ld. If possible, this setting should
- # overridden to take advantage of the native linker features on
- # the platform it is being used on.
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
- fi
-
- # 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
- GXX=no
- with_gnu_ld=no
- wlarc=
- fi
-
- # PORTME: fill in a description of your system's C++ link characteristics
- AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
- _LT_TAGVAR(ld_shlibs, $1)=yes
- case $host_os in
- aix3*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- aix[[4-9]]*)
- 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=
- 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
- # 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
- *-brtl*)
- aix_use_runtimelinking=yes
- break
- ;;
- 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
-
- exp_sym_flag='-bexport'
- no_entry_flag='-bnoentry'
- fi
-
- # When large executables or shared objects are built, AIX ld can
- # have problems creating the table of contents. If linking a library
- # or program results in "error TOC overflow" add -mminimal-toc to
- # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
- # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
- _LT_TAGVAR(archive_cmds, $1)=''
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _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,'
- 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 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`
- if test -f "$collect2name" &&
- strings "$collect2name" | $GREP resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- :
- else
- # We have old collect2
- _LT_TAGVAR(hardcode_direct, $1)=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=
- fi
- esac
- shared_flag='-shared'
- 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 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 yes = "$aix_use_runtimelinking"; then
- shared_flag='$wl-G'
- else
- 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'
- # 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,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.
- # 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(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 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"
- 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"
- # 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 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'
- 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
- _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
- ;;
-
- beos*)
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; 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'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- chorus*)
- case $cc_basename in
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- case $GXX,$cc_basename in
- ,cl* | no,cl*)
- # Native MSVC
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(always_export_symbols, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='@'
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- 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,-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'
- ;;
- *)
- # 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(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, 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
- ;;
- esac
- ;;
- darwin* | rhapsody*)
- _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++*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- ghcx*)
- # Green Hills C++ Compiler
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- freebsd2.*)
- # C++ shared libraries reported to be fairly broken before
- # switch to ELF
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- freebsd-elf*)
- _LT_TAGVAR(archive_cmds_need_lc, $1)=no
- ;;
-
- freebsd* | dragonfly*)
- # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
- # conventions
- _LT_TAGVAR(ld_shlibs, $1)=yes
- ;;
-
- haiku*)
- _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_separator, $1)=:
- _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
- # location of the library.
-
- case $cc_basename in
- CC*)
- # FIXME: insert proper C++ library support
- _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 "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.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # 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"'
- ;;
- *)
- 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
- fi
- ;;
- esac
- ;;
-
- hpux10*|hpux11*)
- 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'
- ;;
- esac
- fi
- case $host_cpu in
- hppa*64*|ia64*)
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
- *)
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
- # but as the default
- # location of the library.
- ;;
- esac
-
- case $cc_basename in
- CC*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- 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'
- ;;
- 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+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- ;;
- esac
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # 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"'
- ;;
- *)
- 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'
- ;;
- 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+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- ;;
- esac
- fi
- else
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
- ;;
-
- 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'
- # 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'
- ;;
- 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'
-
- # Archives containing C++ object files must be created using
- # "CC -ar", where "CC" is the IRIX C++ compiler. This is
- # necessary to make sure instantiated templates are included
- # in the archive.
- _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
- ;;
- *)
- 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'
- 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_separator, $1)=:
- _LT_TAGVAR(inherit_rpath, $1)=yes
- ;;
-
- linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- case $cc_basename in
- KCC*)
- # Kuck and Associates, Inc. (KAI) C++ Compiler
-
- # 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'
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # 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"'
-
- _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.
- _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
- ;;
- icpc* | ecpc* )
- # Intel C++
- with_gnu_ld=yes
- # version 8.0 and above of icpc choke on multiply defined symbols
- # if we add $predep_objects and $postdep_objects, however 7.1 and
- # 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'
- ;;
- *) # 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'
- ;;
- 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'
- ;;
- 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`"'
- _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'
- _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'
- _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'
- ;;
- *) # 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'
- ;;
- 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'
- ;;
- 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'
-
- runpath_var=LD_RUN_PATH
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # 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'
- ;;
- 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 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'
- fi
- ;;
- *)
- case `$CC -V 2>&1 | sed 5q` in
- *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(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(compiler_needs_object, $1)=yes
-
- # Not sure whether something based on
- # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
- # would be better.
- output_verbose_link_cmd='func_echo_all'
-
- # Archives containing C++ object files must be created using
- # "CC -xar", where "CC" is the Sun C++ compiler. This is
- # necessary to make sure instantiated templates are included
- # in the archive.
- _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
- ;;
- esac
- ;;
- esac
- ;;
-
- lynxos*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- m88k*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- mvs*)
- case $cc_basename in
- cxx*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- netbsd*)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
- wlarc=
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- fi
- # Workaround some broken pre-1.5 toolchains
- output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
- ;;
-
- *nto* | *qnx*)
- _LT_TAGVAR(ld_shlibs, $1)=yes
- ;;
-
- 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__`"; 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
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- osf3* | osf4* | osf5*)
- case $cc_basename in
- KCC*)
- # Kuck and Associates, Inc. (KAI) C++ Compiler
-
- # 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(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
- # Archives containing C++ object files must be created using
- # the KAI C++ compiler.
- case $host in
- osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
- *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
- esac
- ;;
- RCC*)
- # Rational C++ 2.4.1
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- 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)=' -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_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'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
- ;;
- esac
-
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # 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"'
- ;;
- *)
- 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 $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_separator, $1)=:
-
- # 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
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
- ;;
-
- psos*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- sunos4*)
- case $cc_basename in
- CC*)
- # Sun C++ 4.x
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- lcc*)
- # Lucid
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- solaris*)
- case $cc_basename in
- CC* | sunCC*)
- # 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_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'
-
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- case $host_os in
- solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
- *)
- # The compiler driver will combine and reorder linker options,
- # 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'
- ;;
- esac
- _LT_TAGVAR(link_all_deplibs, $1)=yes
-
- output_verbose_link_cmd='func_echo_all'
-
- # Archives containing C++ object files must be created using
- # "CC -xar", where "CC" is the Sun C++ compiler. This is
- # necessary to make sure instantiated templates are included
- # in the archive.
- _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
- ;;
- 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'
-
- # 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 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 $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 $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
- # platform.
- _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 $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 -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'
- 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'
- ;;
- esac
- fi
- ;;
- esac
- ;;
-
- sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
- _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 -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 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(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_separator, $1)=':'
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- _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(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
- '"$_LT_TAGVAR(old_archive_cmds, $1)"
- _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
- '"$_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'
- ;;
- esac
- ;;
-
- tandem*)
- case $cc_basename in
- NCC*)
- # NonStop-UX NCC 3.20
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- vxworks*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
-
- AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
- test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
-
- _LT_TAGVAR(GCC, $1)=$GXX
- _LT_TAGVAR(LD, $1)=$LD
-
- ## CAVEAT EMPTOR:
- ## There is no encapsulation within the following macros, do not change
- ## the running order or otherwise move them around unless you know exactly
- ## what you are doing...
- _LT_SYS_HIDDEN_LIBDEPS($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_SYS_DYNAMIC_LINKER($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
- fi # test -n "$compiler"
-
- CC=$lt_save_CC
- CFLAGS=$lt_save_CFLAGS
- LDCXX=$LD
- LD=$lt_save_LD
- GCC=$lt_save_GCC
- with_gnu_ld=$lt_save_with_gnu_ld
- lt_cv_path_LDCXX=$lt_cv_path_LD
- 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 yes != "$_lt_caught_CXX_error"
-
-AC_LANG_POP
-])# _LT_LANG_CXX_CONFIG
-
-
-# _LT_FUNC_STRIPNAME_CNF
-# ----------------------
-# func_stripname_cnf 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).
-#
-# This function is identical to the (non-XSI) version of func_stripname,
-# except this one can be used by m4 code that may be executed by configure,
-# rather than the libtool script.
-m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
-AC_REQUIRE([_LT_DECL_SED])
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
-func_stripname_cnf ()
-{
- 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
-# compiler output when linking a shared library.
-# Parse the compiler output and extract the necessary
-# objects, libraries and library flags.
-m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
-# Dependencies to place before and after the object being linked:
-_LT_TAGVAR(predep_objects, $1)=
-_LT_TAGVAR(postdep_objects, $1)=
-_LT_TAGVAR(predeps, $1)=
-_LT_TAGVAR(postdeps, $1)=
-_LT_TAGVAR(compiler_lib_search_path, $1)=
-
-dnl we can't use the lt_simple_compile_test_code here,
-dnl because it contains code intended for an executable,
-dnl not a library. It's possible we should let each
-dnl tag define a new lt_????_link_test_code variable,
-dnl but it's only used here...
-m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
-int a;
-void foo (void) { a = 0; }
-_LT_EOF
-], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
-class Foo
-{
-public:
- Foo (void) { a = 0; }
-private:
- int a;
-};
-_LT_EOF
-], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
- subroutine foo
- implicit none
- integer*4 a
- a=0
- return
- end
-_LT_EOF
-], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
- subroutine foo
- implicit none
- integer a
- a=0
- return
- end
-_LT_EOF
-], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
-public class foo {
- private int a;
- public void bar (void) {
- a = 0;
- }
-};
-_LT_EOF
-], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
-package foo
-func foo() {
-}
-_LT_EOF
-])
-
-_lt_libdeps_save_CFLAGS=$CFLAGS
-case "$CC $CFLAGS " in #(
-*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
-*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
-*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
-esac
-
-dnl Parse the compiler output and extract the necessary
-dnl objects, libraries and library flags.
-if AC_TRY_EVAL(ac_compile); then
- # Parse the compiler output and extract the necessary
- # objects, libraries and library flags.
-
- # Sentinel used to keep track of whether or not we are before
- # the conftest object file.
- pre_test_object_deps_done=no
-
- for p in `eval "$output_verbose_link_cmd"`; do
- case $prev$p in
-
- -L* | -R* | -l*)
- # Some compilers place space between "-{L,R}" and the path.
- # Remove the space.
- if test x-L = "$p" ||
- test x-R = "$p"; then
- prev=$p
- continue
- fi
-
- # Expand the sysroot to ease extracting the directories later.
- if test -z "$prev"; then
- case $p in
- -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
- -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
- -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
- esac
- fi
- case $p in
- =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
- esac
- 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
- else
- _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
- # linked, so don't bother handling this case.
- esac
- else
- if test -z "$_LT_TAGVAR(postdeps, $1)"; then
- _LT_TAGVAR(postdeps, $1)=$prev$p
- else
- _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
- fi
- fi
- prev=
- ;;
-
- *.lto.$objext) ;; # Ignore GCC LTO objects
- *.$objext)
- # This assumes that the test object file only shows up
- # once in the compiler output.
- if test "$p" = "conftest.$objext"; then
- pre_test_object_deps_done=yes
- continue
- fi
-
- if test no = "$pre_test_object_deps_done"; then
- if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
- _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
- else
- _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
- fi
- fi
- ;;
-
- *) ;; # Ignore the rest.
-
- esac
- done
-
- # Clean up.
- rm -f a.out a.exe
-else
- echo "libtool.m4: error: problem compiling $1 test program"
-fi
-
-$RM -f confest.$objext
-CFLAGS=$_lt_libdeps_save_CFLAGS
-
-# PORTME: override above test on systems where it is broken
-m4_if([$1], [CXX],
-[case $host_os in
-interix[[3-9]]*)
- # Interix 3.5 installs completely hosed .la files for C++, so rather than
- # hack all around it, let's just trust "g++" to DTRT.
- _LT_TAGVAR(predep_objects,$1)=
- _LT_TAGVAR(postdep_objects,$1)=
- _LT_TAGVAR(postdeps,$1)=
- ;;
-esac
-])
-
-case " $_LT_TAGVAR(postdeps, $1) " in
-*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
-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!^ !!'`
-fi
-_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
- [The directories searched by this compiler when creating a shared library])
-_LT_TAGDECL([], [predep_objects], [1],
- [Dependencies to place before and after the objects being linked to
- create a shared library])
-_LT_TAGDECL([], [postdep_objects], [1])
-_LT_TAGDECL([], [predeps], [1])
-_LT_TAGDECL([], [postdeps], [1])
-_LT_TAGDECL([], [compiler_lib_search_path], [1],
- [The library search path used internally by the compiler when linking
- a shared library])
-])# _LT_SYS_HIDDEN_LIBDEPS
-
-
-# _LT_LANG_F77_CONFIG([TAG])
-# --------------------------
-# 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'.
-m4_defun([_LT_LANG_F77_CONFIG],
-[AC_LANG_PUSH(Fortran 77)
-if test -z "$F77" || test no = "$F77"; then
- _lt_disable_F77=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for f77 test sources.
-ac_ext=f
-
-# Object file extension for compiled f77 test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# 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 yes != "$_lt_disable_F77"; then
- # Code to be used in simple compile tests
- lt_simple_compile_test_code="\
- subroutine t
- return
- end
-"
-
- # Code to be used in simple link tests
- lt_simple_link_test_code="\
- program t
- end
-"
-
- # ltmain only uses $CC for tagged configurations so make sure $CC is set.
- _LT_TAG_COMPILER
-
- # save warnings/boilerplate of simple test code
- _LT_COMPILER_BOILERPLATE
- _LT_LINKER_BOILERPLATE
-
- # Allow CC to be a program name with arguments.
- lt_save_CC=$CC
- lt_save_GCC=$GCC
- lt_save_CFLAGS=$CFLAGS
- CC=${F77-"f77"}
- CFLAGS=$FFLAGS
- compiler=$CC
- _LT_TAGVAR(compiler, $1)=$CC
- _LT_CC_BASENAME([$compiler])
- GCC=$G77
- if test -n "$compiler"; then
- AC_MSG_CHECKING([if libtool supports shared libraries])
- AC_MSG_RESULT([$can_build_shared])
-
- AC_MSG_CHECKING([whether to build shared libraries])
- 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 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 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
- AC_MSG_RESULT([$enable_shared])
-
- AC_MSG_CHECKING([whether to build static libraries])
- # Make sure either enable_shared or enable_static is yes.
- test yes = "$enable_shared" || enable_static=yes
- AC_MSG_RESULT([$enable_static])
-
- _LT_TAGVAR(GCC, $1)=$G77
- _LT_TAGVAR(LD, $1)=$LD
-
- ## CAVEAT EMPTOR:
- ## There is no encapsulation within the following macros, do not change
- ## the running order or otherwise move them around unless you know exactly
- ## what you are doing...
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_SYS_DYNAMIC_LINKER($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
- fi # test -n "$compiler"
-
- GCC=$lt_save_GCC
- CC=$lt_save_CC
- CFLAGS=$lt_save_CFLAGS
-fi # test yes != "$_lt_disable_F77"
-
-AC_LANG_POP
-])# _LT_LANG_F77_CONFIG
-
-
-# _LT_LANG_FC_CONFIG([TAG])
-# -------------------------
-# 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'.
-m4_defun([_LT_LANG_FC_CONFIG],
-[AC_LANG_PUSH(Fortran)
-
-if test -z "$FC" || test no = "$FC"; then
- _lt_disable_FC=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for fc test sources.
-ac_ext=${ac_fc_srcext-f}
-
-# Object file extension for compiled fc test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# 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 yes != "$_lt_disable_FC"; then
- # Code to be used in simple compile tests
- lt_simple_compile_test_code="\
- subroutine t
- return
- end
-"
-
- # Code to be used in simple link tests
- lt_simple_link_test_code="\
- program t
- end
-"
-
- # ltmain only uses $CC for tagged configurations so make sure $CC is set.
- _LT_TAG_COMPILER
-
- # save warnings/boilerplate of simple test code
- _LT_COMPILER_BOILERPLATE
- _LT_LINKER_BOILERPLATE
-
- # Allow CC to be a program name with arguments.
- lt_save_CC=$CC
- lt_save_GCC=$GCC
- lt_save_CFLAGS=$CFLAGS
- CC=${FC-"f95"}
- CFLAGS=$FCFLAGS
- compiler=$CC
- GCC=$ac_cv_fc_compiler_gnu
-
- _LT_TAGVAR(compiler, $1)=$CC
- _LT_CC_BASENAME([$compiler])
-
- if test -n "$compiler"; then
- AC_MSG_CHECKING([if libtool supports shared libraries])
- AC_MSG_RESULT([$can_build_shared])
-
- AC_MSG_CHECKING([whether to build shared libraries])
- 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 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 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
- AC_MSG_RESULT([$enable_shared])
-
- AC_MSG_CHECKING([whether to build static libraries])
- # Make sure either enable_shared or enable_static is 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
-
- ## CAVEAT EMPTOR:
- ## There is no encapsulation within the following macros, do not change
- ## the running order or otherwise move them around unless you know exactly
- ## what you are doing...
- _LT_SYS_HIDDEN_LIBDEPS($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_SYS_DYNAMIC_LINKER($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
- fi # test -n "$compiler"
-
- GCC=$lt_save_GCC
- CC=$lt_save_CC
- CFLAGS=$lt_save_CFLAGS
-fi # test yes != "$_lt_disable_FC"
-
-AC_LANG_POP
-])# _LT_LANG_FC_CONFIG
-
-
-# _LT_LANG_GCJ_CONFIG([TAG])
-# --------------------------
-# 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'.
-m4_defun([_LT_LANG_GCJ_CONFIG],
-[AC_REQUIRE([LT_PROG_GCJ])dnl
-AC_LANG_SAVE
-
-# Source file extension for Java test sources.
-ac_ext=java
-
-# Object file extension for compiled Java test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="class foo {}"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=yes
-CC=${GCJ-"gcj"}
-CFLAGS=$GCJFLAGS
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)=$LD
-_LT_CC_BASENAME([$compiler])
-
-# GCJ did not exist at the time GCC didn't implicitly link libc in.
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-
-if test -n "$compiler"; then
- _LT_COMPILER_NO_RTTI($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
-fi
-
-AC_LANG_RESTORE
-
-GCC=$lt_save_GCC
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_GCJ_CONFIG
-
-
-# _LT_LANG_GO_CONFIG([TAG])
-# --------------------------
-# 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'.
-m4_defun([_LT_LANG_GO_CONFIG],
-[AC_REQUIRE([LT_PROG_GO])dnl
-AC_LANG_SAVE
-
-# Source file extension for Go test sources.
-ac_ext=go
-
-# Object file extension for compiled Go test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="package main; func main() { }"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='package main; func main() { }'
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=yes
-CC=${GOC-"gccgo"}
-CFLAGS=$GOFLAGS
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)=$LD
-_LT_CC_BASENAME([$compiler])
-
-# Go did not exist at the time GCC didn't implicitly link libc in.
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-
-if test -n "$compiler"; then
- _LT_COMPILER_NO_RTTI($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
-fi
-
-AC_LANG_RESTORE
-
-GCC=$lt_save_GCC
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_GO_CONFIG
-
-
-# _LT_LANG_RC_CONFIG([TAG])
-# -------------------------
-# 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'.
-m4_defun([_LT_LANG_RC_CONFIG],
-[AC_REQUIRE([LT_PROG_RC])dnl
-AC_LANG_SAVE
-
-# Source file extension for RC test sources.
-ac_ext=rc
-
-# Object file extension for compiled RC test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-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
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=
-CC=${RC-"windres"}
-CFLAGS=
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_CC_BASENAME([$compiler])
-_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
-
-if test -n "$compiler"; then
- :
- _LT_CONFIG($1)
-fi
-
-GCC=$lt_save_GCC
-AC_LANG_RESTORE
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_RC_CONFIG
-
-
-# LT_PROG_GCJ
-# -----------
-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 set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
- AC_SUBST(GCJFLAGS)])])[]dnl
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
-
-
-# LT_PROG_GO
-# ----------
-AC_DEFUN([LT_PROG_GO],
-[AC_CHECK_TOOL(GOC, gccgo,)
-])
-
-
-# LT_PROG_RC
-# ----------
-AC_DEFUN([LT_PROG_RC],
-[AC_CHECK_TOOL(RC, windres,)
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_RC], [])
-
-
-# _LT_DECL_EGREP
-# --------------
-# If we don't have a new enough Autoconf to choose the best grep
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_EGREP],
-[AC_REQUIRE([AC_PROG_EGREP])dnl
-AC_REQUIRE([AC_PROG_FGREP])dnl
-test -z "$GREP" && GREP=grep
-_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
-_LT_DECL([], [EGREP], [1], [An ERE matcher])
-_LT_DECL([], [FGREP], [1], [A literal string matcher])
-dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
-AC_SUBST([GREP])
-])
-
-
-# _LT_DECL_OBJDUMP
-# --------------
-# If we don't have a new enough Autoconf to choose the best objdump
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_OBJDUMP],
-[AC_CHECK_TOOL(OBJDUMP, objdump, false)
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
-AC_SUBST([OBJDUMP])
-])
-
-# _LT_DECL_DLLTOOL
-# ----------------
-# Ensure DLLTOOL variable is set.
-m4_defun([_LT_DECL_DLLTOOL],
-[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
-AC_SUBST([DLLTOOL])
-])
-
-# _LT_DECL_SED
-# ------------
-# Check for a fully-functional sed program, that truncates
-# as few characters as possible. Prefer GNU sed if found.
-m4_defun([_LT_DECL_SED],
-[AC_PROG_SED
-test -z "$SED" && SED=sed
-Xsed="$SED -e 1s/^X//"
-_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
-_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
- [Sed that helps us avoid accidentally triggering echo(1) options like -n])
-])# _LT_DECL_SED
-
-m4_ifndef([AC_PROG_SED], [
-# NOTE: This macro has been submitted for inclusion into #
-# GNU Autoconf as AC_PROG_SED. When it is available in #
-# a released version of Autoconf we should remove this #
-# macro and use it instead. #
-
-m4_defun([AC_PROG_SED],
-[AC_MSG_CHECKING([for a sed that does not truncate output])
-AC_CACHE_VAL(lt_cv_path_SED,
-[# Loop through the user's path and test for sed and gsed.
-# Then use that list of sed's as ones to test for truncation.
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for lt_ac_prog in sed gsed; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
- lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
- fi
- done
- done
-done
-IFS=$as_save_IFS
-lt_ac_max=0
-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
- cat /dev/null > conftest.in
- lt_ac_count=0
- echo $ECHO_N "0123456789$ECHO_C" >conftest.in
- # Check for GNU sed and select it if it is found.
- if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
- lt_cv_path_SED=$lt_ac_sed
- break
- fi
- while true; do
- cat conftest.in conftest.in >conftest.tmp
- mv conftest.tmp conftest.in
- cp conftest.in conftest.nl
- echo >>conftest.nl
- $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 10 -lt "$lt_ac_count" && break
- lt_ac_count=`expr $lt_ac_count + 1`
- if test "$lt_ac_count" -gt "$lt_ac_max"; then
- lt_ac_max=$lt_ac_count
- lt_cv_path_SED=$lt_ac_sed
- fi
- done
-done
-])
-SED=$lt_cv_path_SED
-AC_SUBST([SED])
-AC_MSG_RESULT([$SED])
-])#AC_PROG_SED
-])#m4_ifndef
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_SED], [])
-
-
-# _LT_CHECK_SHELL_FEATURES
-# ------------------------
-# Find out whether the shell is Bourne or XSI compatible,
-# or has some other useful features.
-m4_defun([_LT_CHECK_SHELL_FEATURES],
-[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
- lt_unset=unset
-else
- lt_unset=false
-fi
-_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
-
-# test EBCDIC or ASCII
-case `echo X|tr X '\101'` in
- A) # ASCII based system
- # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
- lt_SP2NL='tr \040 \012'
- lt_NL2SP='tr \015\012 \040\040'
- ;;
- *) # EBCDIC based system
- lt_SP2NL='tr \100 \n'
- lt_NL2SP='tr \r\n \100\100'
- ;;
-esac
-_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
-_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
-])# _LT_CHECK_SHELL_FEATURES
-
-
-# _LT_PATH_CONVERSION_FUNCTIONS
-# -----------------------------
-# 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],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_MSG_CHECKING([how to convert $build file names to $host format])
-AC_CACHE_VAL(lt_cv_to_host_file_cmd,
-[case $host in
- *-*-mingw* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
- ;;
- *-*-cygwin* )
- lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
- ;;
- * ) # otherwise, assume *nix
- lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
- ;;
- esac
- ;;
- *-*-cygwin* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
- ;;
- *-*-cygwin* )
- lt_cv_to_host_file_cmd=func_convert_file_noop
- ;;
- * ) # otherwise, assume *nix
- lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
- ;;
- esac
- ;;
- * ) # unhandled hosts (and "normal" native builds)
- lt_cv_to_host_file_cmd=func_convert_file_noop
- ;;
-esac
-])
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
-_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
- [0], [convert $build file names to $host format])dnl
-
-AC_MSG_CHECKING([how to convert $build file names to toolchain format])
-AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
-[#assume ordinary cross tools, or native build.
-lt_cv_to_tool_file_cmd=func_convert_file_noop
-case $host in
- *-*-mingw* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
- ;;
- esac
- ;;
-esac
-])
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
-_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
- [0], [convert $build files to toolchain format])dnl
-])# _LT_PATH_CONVERSION_FUNCTIONS
-
-# Helper functions for option handling. -*- Autoconf -*-
-#
-# 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 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])])
-
-
-# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
-# ------------------------------------------
-m4_define([_LT_MANGLE_OPTION],
-[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
-
-
-# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
-# ---------------------------------------
-# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
-# matching handler defined, dispatch to it. Other OPTION-NAMEs are
-# saved as a flag.
-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
-])
-
-
-# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
-# ------------------------------------------------------------
-# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
-m4_define([_LT_IF_OPTION],
-[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
-
-
-# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
-# -------------------------------------------------------
-# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
-# are set.
-m4_define([_LT_UNLESS_OPTIONS],
-[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
- [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
- [m4_define([$0_found])])])[]dnl
-m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
-])[]dnl
-])
-
-
-# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
-# ----------------------------------------
-# OPTION-LIST is a space-separated list of Libtool options associated
-# with MACRO-NAME. If any OPTION has a matching handler declared with
-# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
-# the unknown option and exit.
-m4_defun([_LT_SET_OPTIONS],
-[# Set options
-m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
- [_LT_SET_OPTION([$1], _LT_Option)])
-
-m4_if([$1],[LT_INIT],[
- dnl
- dnl Simply set some default values (i.e off) if boolean options were not
- dnl specified:
- _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
- ])
- _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
- ])
- 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 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_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
- [_LT_WITH_AIX_SONAME([aix])])
- ])
-])# _LT_SET_OPTIONS
-
-
-
-# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
-# -----------------------------------------
-m4_define([_LT_MANGLE_DEFUN],
-[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
-
-
-# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
-# -----------------------------------------------
-m4_define([LT_OPTION_DEFINE],
-[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
-])# LT_OPTION_DEFINE
-
-
-# dlopen
-# ------
-LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
-])
-
-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.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
-
-
-# win32-dll
-# ---------
-# Declare package support for building win32 dll's.
-LT_OPTION_DEFINE([LT_INIT], [win32-dll],
-[enable_win32_dll=yes
-
-case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
- AC_CHECK_TOOL(AS, as, false)
- AC_CHECK_TOOL(DLLTOOL, dlltool, false)
- AC_CHECK_TOOL(OBJDUMP, objdump, false)
- ;;
-esac
-
-test -z "$AS" && AS=as
-_LT_DECL([], [AS], [1], [Assembler program])dnl
-
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
-
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
-])# win32-dll
-
-AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-_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.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-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'.
-m4_define([_LT_ENABLE_SHARED],
-[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([shared],
- [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
- [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
- [p=${PACKAGE-default}
- case $enableval in
- yes) enable_shared=yes ;;
- no) enable_shared=no ;;
- *)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac],
- [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
-
- _LT_DECL([build_libtool_libs], [enable_shared], [0],
- [Whether or not to build shared libraries])
-])# _LT_ENABLE_SHARED
-
-LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
-])
-
-AC_DEFUN([AC_DISABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], [disable-shared])
-])
-
-AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
-AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_SHARED], [])
-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'.
-m4_define([_LT_ENABLE_STATIC],
-[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([static],
- [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
- [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
- [p=${PACKAGE-default}
- case $enableval in
- yes) enable_static=yes ;;
- no) enable_static=no ;;
- *)
- enable_static=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_static=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac],
- [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
-
- _LT_DECL([build_old_libs], [enable_static], [0],
- [Whether or not to build static libraries])
-])# _LT_ENABLE_STATIC
-
-LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
-])
-
-AC_DEFUN([AC_DISABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], [disable-static])
-])
-
-AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
-AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_STATIC], [])
-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'.
-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],
- [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
- [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
- [p=${PACKAGE-default}
- case $enableval in
- yes) enable_fast_install=yes ;;
- no) enable_fast_install=no ;;
- *)
- 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,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_fast_install=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac],
- [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
-
-_LT_DECL([fast_install], [enable_fast_install], [0],
- [Whether or not to optimize for fast installation])dnl
-])# _LT_ENABLE_FAST_INSTALL
-
-LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
-
-# Old names:
-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.])
-])
-
-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.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-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'
-# LT_INIT options.
-# 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@:>@],
- [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
- [lt_p=${PACKAGE-default}
- case $withval in
- yes|no) pic_mode=$withval ;;
- *)
- pic_mode=default
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for lt_pkg in $withval; do
- IFS=$lt_save_ifs
- if test "X$lt_pkg" = "X$lt_p"; then
- pic_mode=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac],
- [pic_mode=m4_default([$1], [default])])
-
-_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
-])# _LT_WITH_PIC
-
-LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
-
-# Old name:
-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.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
-
-
-m4_define([_LTDL_MODE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
- [m4_define([_LTDL_MODE], [nonrecursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [recursive],
- [m4_define([_LTDL_MODE], [recursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [subproject],
- [m4_define([_LTDL_MODE], [subproject])])
-
-m4_define([_LTDL_TYPE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [installable],
- [m4_define([_LTDL_TYPE], [installable])])
-LT_OPTION_DEFINE([LTDL_INIT], [convenience],
- [m4_define([_LTDL_TYPE], [convenience])])
-
-# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
-#
-# 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
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 6 ltsugar.m4
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
-
-
-# lt_join(SEP, ARG1, [ARG2...])
-# -----------------------------
-# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
-# associated separator.
-# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
-# versions in m4sugar had bugs.
-m4_define([lt_join],
-[m4_if([$#], [1], [],
- [$#], [2], [[$2]],
- [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
-m4_define([_lt_join],
-[m4_if([$#$2], [2], [],
- [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
-
-
-# lt_car(LIST)
-# lt_cdr(LIST)
-# ------------
-# Manipulate m4 lists.
-# These macros are necessary as long as will still need to support
-# 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])],
- [$#], 1, [],
- [m4_dquote(m4_shift($@))])])
-m4_define([lt_unquote], $1)
-
-
-# lt_append(MACRO-NAME, STRING, [SEPARATOR])
-# ------------------------------------------
-# 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
-# than defined and empty).
-#
-# This macro is needed until we can rely on Autoconf 2.62, since earlier
-# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
-m4_define([lt_append],
-[m4_define([$1],
- m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
-
-
-
-# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
-# ----------------------------------------------------------
-# Produce a SEP delimited list of all paired combinations of elements of
-# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
-# has the form PREFIXmINFIXSUFFIXn.
-# Needed until we can rely on m4_combine added in Autoconf 2.62.
-m4_define([lt_combine],
-[m4_if(m4_eval([$# > 3]), [1],
- [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
-[[m4_foreach([_Lt_prefix], [$2],
- [m4_foreach([_Lt_suffix],
- ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
- [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
-
-
-# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
-# -----------------------------------------------------------------------
-# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
-# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
-m4_define([lt_if_append_uniq],
-[m4_ifdef([$1],
- [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
- [lt_append([$1], [$2], [$3])$4],
- [$5])],
- [lt_append([$1], [$2], [$3])$4])])
-
-
-# lt_dict_add(DICT, KEY, VALUE)
-# -----------------------------
-m4_define([lt_dict_add],
-[m4_define([$1($2)], [$3])])
-
-
-# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
-# --------------------------------------------
-m4_define([lt_dict_add_subkey],
-[m4_define([$1($2:$3)], [$4])])
-
-
-# lt_dict_fetch(DICT, KEY, [SUBKEY])
-# ----------------------------------
-m4_define([lt_dict_fetch],
-[m4_ifval([$3],
- m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
- m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
-
-
-# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
-# -----------------------------------------------------------------
-m4_define([lt_if_dict_fetch],
-[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
- [$5],
- [$6])])
-
-
-# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
-# --------------------------------------------------------------
-m4_define([lt_dict_filter],
-[m4_if([$5], [], [],
- [lt_join(m4_quote(m4_default([$4], [[, ]])),
- lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
- [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
-])
-
-# ltversion.m4 -- version numbers -*- Autoconf -*-
-#
-# 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
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# @configure_input@
-
-# serial 4179 ltversion.m4
-# This file is part of GNU Libtool
-
-m4_define([LT_PACKAGE_VERSION], [2.4.6])
-m4_define([LT_PACKAGE_REVISION], [2.4.6])
-
-AC_DEFUN([LTVERSION_VERSION],
-[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)
-])
-
-# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
-#
-# 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
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 5 lt~obsolete.m4
-
-# These exist entirely to fool aclocal when bootstrapping libtool.
-#
-# 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.
-#
-# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
-# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
-# using a macro with the same name in our local m4/libtool.m4 it'll
-# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
-# and doesn't know about Autoconf macros at all.)
-#
-# So we provide this file, which has a silly filename so it's always
-# 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.
-#
-# 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
-# we give up compatibility with versions before 1.7, at which point
-# we need to keep only those names which we still refer to.
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
-
-m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
-m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
-m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
-m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
-m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
-m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
-m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
-m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
-m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
-m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
-m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
-m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
-m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
-m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
-m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
-m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
-m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
-m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
-m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
-m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
-m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
-m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
-m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
-m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
-m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
-m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
-m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
-m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
-m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
-m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
-m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
-m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
-m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
-m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
-m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
-m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
-m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
-m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
-m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
-m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
-m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
-m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
-m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
-m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
-m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
-m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
-m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
-m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
-m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
-m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
-m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
-
-# Copyright (C) 2002-2021 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.5], [],
- [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.5])dnl
-m4_ifndef([AC_AUTOCONF_VERSION],
- [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
-
-# AM_AUX_DIR_EXPAND -*- Autoconf -*-
-
-# Copyright (C) 2001-2021 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-2021 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-2021 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-2021 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-2021 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
-m4_ifdef([_$0_ALREADY_INIT],
- [m4_fatal([$0 expanded multiple times
-]m4_defn([_$0_ALREADY_INIT]))],
- [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])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_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([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
-])
-# Variables for tags utilities; see am/tags.am
-if test -z "$CTAGS"; then
- CTAGS=ctags
-fi
-AC_SUBST([CTAGS])
-if test -z "$ETAGS"; then
- ETAGS=etags
-fi
-AC_SUBST([ETAGS])
-if test -z "$CSCOPE"; then
- CSCOPE=cscope
-fi
-AC_SUBST([CSCOPE])
-
-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-2021 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-2021 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-2021 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-2021 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
- MISSING="\${SHELL} '$am_aux_dir/missing'"
-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-2021 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-2021 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-2021 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-2021 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-2021 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-2021 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-2021 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-2021 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
-
diff --git a/contrib/sqlite3/auto.def b/contrib/sqlite3/auto.def
new file mode 100644
index 000000000000..c61d81e506f0
--- /dev/null
+++ b/contrib/sqlite3/auto.def
@@ -0,0 +1,25 @@
+#!/do/not/tclsh
+# ^^^ help out editors which guess this file's content type.
+#
+# This is the main autosetup-compatible configure script for the
+# "autoconf" bundle of the SQLite project.
+use sqlite-config
+sqlite-configure autoconf {
+ sqlite-handle-debug
+ sqlite-check-common-bins ;# must come before [sqlite-handle-wasi-sdk]
+ sqlite-handle-wasi-sdk ;# must run relatively early, as it changes the environment
+ sqlite-check-common-system-deps
+ proj-define-for-opt static-shell ENABLE_STATIC_SHELL \
+ "Link library statically into the CLI shell?"
+ proj-define-for-opt static-cli-shell STATIC_CLI_SHELL "Statically link CLI shell?"
+ if {![opt-bool static-shell] && [opt-bool static-cli-shell]} {
+ proj-fatal "--disable-static-shell and --static-cli-shell are mutualy exclusive"
+ }
+ if {![opt-bool shared] && ![opt-bool static-shell]} {
+ proj-opt-set shared 1
+ proj-indented-notice {
+ NOTICE: ignoring --disable-shared because --disable-static-shell
+ was specified.
+ }
+ }
+}
diff --git a/contrib/sqlite3/autosetup/LICENSE b/contrib/sqlite3/autosetup/LICENSE
new file mode 100644
index 000000000000..4fe636c9d912
--- /dev/null
+++ b/contrib/sqlite3/autosetup/LICENSE
@@ -0,0 +1,35 @@
+Unless explicitly stated, all files which form part of autosetup
+are released under the following license:
+
+---------------------------------------------------------------------
+autosetup - A build environment "autoconfigurator"
+
+Copyright (c) 2010-2011, WorkWare Systems <http://workware.net.au/>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE WORKWARE SYSTEMS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WORKWARE
+SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of WorkWare Systems.
diff --git a/contrib/sqlite3/autosetup/README.autosetup b/contrib/sqlite3/autosetup/README.autosetup
new file mode 100644
index 000000000000..395298048038
--- /dev/null
+++ b/contrib/sqlite3/autosetup/README.autosetup
@@ -0,0 +1,11 @@
+README.autosetup created by autosetup v0.7.2
+
+This is the autosetup directory for a local install of autosetup.
+It contains autosetup, support files and loadable modules.
+
+*.tcl files in this directory are optional modules which
+can be loaded with the 'use' directive.
+
+*.auto files in this directory are auto-loaded.
+
+For more information, see https://msteveb.github.io/autosetup/
diff --git a/contrib/sqlite3/autosetup/README.md b/contrib/sqlite3/autosetup/README.md
new file mode 100644
index 000000000000..3301f5739599
--- /dev/null
+++ b/contrib/sqlite3/autosetup/README.md
@@ -0,0 +1,453 @@
+Maintaining Autosetup in the SQLite Tree
+========================================================================
+
+This document provides some tips and reminders for the SQLite
+developers regarding using and maintaining the [Autosetup][]-based
+build infrastructure. It is not an [Autosetup][] reference.
+
+**Table of Contents**:
+
+- [Autosetup API Reference](#apiref)
+- [API Tips](#apitips)
+- [Ensuring TCL Compatibility](#tclcompat)
+- [Design Conventions](#conventions)
+ - Symbolic Names of Feature Flags
+ - Do Not Update Global Shared State
+- [Updating Autosetup](#updating)
+ - ***[Patching Autosetup for Project-local changes](#patching)***
+- [Branch-specific Customization](#branch-customization)
+
+
+------------------------------------------------------------------------
+
+<a name="apiref"></a>
+Autosetup API Reference
+========================================================================
+
+The Autosetup API is quite extensive and can be read either in
+the [files in the `autosetup` dir](/dir/autosetup) or using:
+
+>
+```
+$ ./configure --reference | less
+```
+
+That will include any docs from any TCL files in the `./autosetup` dir
+which contain certain (simple) markup defined by autosetup.
+
+This project's own configuration-related TCL code is spread across the
+following files:
+
+- [proj.tcl][]: project-agnostic utility code for autosetup-driven
+ projects. This file is designed to be shared between this project,
+ other projects managed under the SQLite/Hwaci umbrella
+ (e.g. Fossil), and personal projects of SQLite's developers. It is
+ essentially an amalgamation of a decade's worth of autosetup-related
+ utility code.
+- [sqlite-config.tcl][]: utility code which is too project-specific
+ for `proj.tcl`. We split this out of `auto.def` so that it can be
+ used by both `auto.def` and...
+- [auto.def][]: the primary driver for the `./configure` process.
+ When we talk about "the configure script," we're technically
+ referring to this file, though it actually contains very little
+ of the TCL code.
+- [autoconf/auto.def][]: the main driver script for the "autoconf"
+ bundle's configure script. It is essentially a slightly trimmed-down
+ version of the main `auto.def` file. The `autoconf` dir was ported
+ from the Autotools to Autosetup in the 3.49.0 dev cycle but retains
+ the "autoconf" name to minimize downstream disruption.
+
+
+<a name="apitips"></a>
+Autosetup API Tips
+========================================================================
+
+This section briefly covers only APIs which are frequently useful in
+day-to-day maintenance and might not be immediately recognized as such
+from a casual perusal of the relevant TCL files. The complete docs of
+those with `proj-` prefix can be found in [proj.tcl][] and those with
+an `sqlite-` prefix are in [sqlite-config.tcl][]. The others are part
+of Autosetup's core packages and are scattered around [the TCL files
+in ./autosetup](/dir/autosetup).
+
+In (mostly) alphabetical order:
+
+- **`file-isexec filename`**\
+ Should be used in place of `[file executable]`, as it will also
+ check for `${filename}.exe` on Windows platforms. However, on such
+ platforms it also assumes that _any_ existing file is executable.
+
+- **`get-env VAR ?default?`**\
+ Will fetch an "environment variable" from the first of either: (1) a
+ KEY=VALUE passed to the configure script or (2) the system's
+ environment variables. Not to be confused with `getenv`, which only
+ does the latter and is rarely, if ever, useful in this tree.
+ - **`proj-get-env VAR ?default?`**\
+ Works like `get-env` but will, if that function finds no match,
+ look for a file named `./.env-$VAR` and, if found, return its
+ trimmed contents. This can be used, e.g., to set a developer's
+ local preferences for the default `CFLAGS`.\
+ Tip: adding `-O0` to `.env-CFLAGS` reduces rebuild times
+ considerably at the cost of performance in `make devtest` and the
+ like.
+
+- **`proj-fatal msg`**\
+ Emits `$msg` to stderr and exits with non-zero. Its differences from
+ autosetup's `user-error` are purely cosmetic.
+
+- **`proj-if-opt-truthy flag thenScript ?elseScript?`**\
+ Evals `thenScript` if the given `--flag` is truthy, else it
+ evals the optional `elseScript`.
+
+- **`proj-indented-notice ?-error? ?-notice? msg`**\
+ Breaks its `msg` argument into lines, trims them, and emits them
+ with consistent indentation. Exactly how it emits depends on the
+ flags passed to it (or not), as covered in its docs. This will stick
+ out starkly from normal output and is intended to be used only for
+ important notices.
+
+- **`proj-opt-truthy flag`**\
+ Returns 1 if `--flag`'s value is "truthy," i.e. one of (1, on,
+ enabled, yes, true).
+
+- **`proj-opt-was-provided FLAG`**\
+ Returns 1 if `--FLAG` was explicitly provided to configure,
+ else 0. This distinction can be used to determine, e.g., whether
+ `--with-readline` was provided or whether we're searching for
+ readline by default. In the former case, failure to find it should
+ be treated as fatal, where in the latter case it's not.\
+ Unlike most functions which deal with `--flags`, this one does not
+ validate that `$FLAG` is a registered flag so will not fail fatally
+ if `$FLAG` is not registered as an Autosetup option.
+
+- **`proj-val-truthy value`**\
+ Returns 1 if `$value` is "truthy," See `proj-opt-truthy` for the definition
+ of "truthy."
+
+- **`proj-warn msg`**\
+ Emits `$msg` to stderr. Closely-related is autosetup's `user-notice`
+ (described below).
+
+- **`sqlite-add-feature-flag ?-shell? FLAG...`**\
+ Adds the given feature flag to the CFLAGS which are specific to
+ building libsqlite3. It's intended to be passed one or more
+ `-DSQLITE_ENABLE_...`, or similar, flags. If the `-shell` flag is
+ used then it also passes its arguments to
+ `sqlite-add-shell-opt`. This is a no-op if `FLAG` is not provided or
+ is empty.
+
+- **`sqlite-add-shell-opt FLAG...`**\
+ The shell-specific counterpart of `sqlite-add-feature-flag` which
+ only adds the given flag(s) to the CLI-shell-specific CFLAGS.
+
+- **`sqlite-configure BUILD-NAME {script}`**\
+ This is where all configure `--flags` are defined for all known
+ build modes ("canonical" or "autoconf"). After processing all flags,
+ this function runs `$script`, which contains the build-mode-specific
+ configuration bits, and then runs any finalization bits which are
+ common to all build modes. The `auto.def` files are intended to contain
+ exactly two commands:
+ `use sqlite-config; sqlite-configure BUILD-NAME {script}`
+
+- **`user-notice msg`**\
+ Queues `$msg` to be sent to stderr, but does not emit it until
+ either `show-notices` is called or the next time autosetup would
+ output something (it internally calls `show-notices`). This can be
+ used to generate warnings between a "checking for..." message and
+ its resulting "yes/no/whatever" message in such a way as to not
+ spoil the layout of such messages.
+
+
+<a name="tclcompat"></a>
+Ensuring TCL Compatibility
+========================================================================
+
+One of the significant benefits of using Autosetup is that (A) this
+project uses many TCL scripts in the build process and (B) Autosetup
+comes with a TCL interpreter named [JimTCL][].
+
+It is important that any TCL files used by the configure process and
+makefiles remain compatible with both [JimTCL][] and the canonical
+TCL. Though JimTCL has outstanding compatibility with canonical TCL,
+it does have a few corners with incompatibilities, e.g. regular
+expressions. If a script runs in JimTCL without using any
+JimTCL-specific features, then it's a certainty that it will run in
+canonical TCL as well. The opposite, however, is not _always_ the
+case.
+
+When [`./configure`](/file/configure) is run, it goes through a
+bootstrapping process to find a suitable TCL with which to run the
+autosetup framework. The first step involves [finding or building a
+TCL shell](/file/autosetup/autosetup-find-tclsh). That will first
+search for an available `tclsh` (under several common names,
+e.g. `tclsh8.6`) before falling back to compiling the copy of
+`jimsh0.c` included in the source tree. i.e. it will prefer to use a
+system-installed TCL for running the configure script. Once it finds
+(or builds) a TCL shell, it then runs [a sanity test to ensure that
+the shell is suitable](/file/autosetup/autosetup-test-tclsh) before
+using it to run the main autosetup app.
+
+There are two simple ways to ensure that running of the configure
+process uses JimTCL instead of the canonical `tclsh`, and either
+approach provides equally high assurances about configure script
+compatibility across TCL implementations:
+
+1. Build on a system with no `tclsh` installed in the `$PATH`. In that
+ case, the configure process will fall back to building the in-tree
+ copy of JimTCL.
+
+2. Manually build `./jimsh0` in the top of the checkout with:\
+ `cc -o jimsh0 autosetup/jimsh0.c`\
+ With that in place, the configure script will prefer to use that
+ before looking for a system-level `tclsh`. Be aware, though, that
+ `make distclean` will remove that file.
+
+**Note that `./jimsh0` is distinctly different from the `./jimsh`**
+which gets built for code-generation purposes. The latter requires
+non-default build flags to enable features which are
+platform-dependent, most notably to make its `[file normalize]` work.
+This means, for example, that the configure script and its utility
+APIs must not use `[file normalize]`, but autosetup provides a
+TCL-only implementation of `[file-normalize]` (note the dash) for
+portable use in the configure script. Contrariwise, code-generation
+scripts invoked via `make` may use `[file normalize]`, as they'll use
+`./jimsh` or `tclsh` instead of `./jimsh0`.
+
+
+Known TCL Incompatibilities
+------------------------------------------------------------------------
+
+A summary of known incompatibilities in JimTCL
+
+- **CRNL line endings**: prior to 2025-02-05 `fconfigure -translation ...`
+ was a no-op in JimTCL, and it emits CRNL line endings by default on
+ Windows. Since then, it supports `-translation binary`, which is
+ close enough to `-translation lf` for our purposes. When working
+ with files using the `open` command, it is important to use mode
+ `"rb"` or `"wb"`, as appropriate, so that the output does not get
+ CRNL-mangled on Windows.
+
+- **`file copy`** does not support multiple source files. See
+ [](/info/61f18c96183867fe) for a workaround.
+
+- **Regular expressions**:
+
+ - Patterns treat `\nnn` octal values as back-references (which it
+ does not support). Those can be reformulated as demonstrated in
+ [](/info/aeac23359bb681c0).
+
+ - `regsub` does not support the `\y` flag. A workaround is demonstrated
+ in [](/info/c2e5dd791cce3ec4).
+
+
+<a name="conventions"></a>
+Design Conventions
+========================================================================
+
+This section describes the motivations for the most glaring of the
+build's design decisions, in particular how they deviate from
+historical, or even widely-conventional, practices.
+
+Symbolic Names of Feature Flags
+------------------------------------------------------------------------
+
+Historically, the project's makefile has exclusively used
+`UPPER_UNDERSCORE` form for makefile variables. This build, however,
+primarily uses `X.y` format, where `X` is often a category label,
+e.g. `CFLAGS`, and `y` is the specific instance of that category,
+e.g. `CFLAGS.readline`.
+
+When the configure script exports flags for consumption by filtered
+files, e.g. [Makefile.in][] and the generated
+`sqlite_cfg.h`, it does so in the more conventional `X_Y` form because
+those flags get exported as as C `#define`s to `sqlite_cfg.h`, where
+dots are not permitted.
+
+The `X.y` convention is used in the makefiles primarily because the
+person who did the initial port finds that considerably easier on the
+eyes and fingers. In practice, the `X_Y` form of such exports is used
+exactly once in [Makefile.in][], where it's translated from `@X_Y@`
+into into `X.y` form for consumption by [Makefile.in][] and
+[main.mk][]. For example:
+
+>
+```
+LDFLAGS.shobj = @SHOBJ_LDFLAGS@
+LDFLAGS.zlib = @LDFLAGS_ZLIB@
+LDFLAGS.math = @LDFLAGS_MATH@
+```
+
+(That first one is defined by autosetup, and thus applies "LDFLAGS" as
+the suffix rather than the prefix. Which is more legible is a matter
+of taste, for which there is no accounting.)
+
+
+Do Not Update Global Shared State
+------------------------------------------------------------------------
+
+In both the legacy Autotools-driven build and common Autosetup usage,
+feature tests performed by the configure script may amend global flags
+such as `LIBS`, `LDFLAGS`, and `CFLAGS`[^as-cflags]. That's
+appropriate for a makefile which builds a single deliverable, but less
+so for makefiles which produce multiple deliverables. Drawbacks of
+that approach include:
+
+- It's unlikely that every single deliverable will require the same
+ core set of those flags.
+- It can be difficult to determine the origin of any given change to
+ that global state because those changes are hidden behind voodoo
+ performed outside the immediate visibility of the configure script's
+ maintainer.
+- It can force the maintainers of the configure script to place tests
+ in a specific order so that the resulting flags get applied at
+ the correct time and/or in the correct order.\
+ (A real-life example: before the approach described below was taken
+ to collecting build-time flags, the test for `-rpath` had to come
+ _after_ the test for zlib because the results of the `-rpath` test
+ implicitly modified global state which broke the zlib feature
+ test. Because the feature tests no longer (intentionally) modify
+ shared global state, that is not an issue.)
+
+In this build, cases where feature tests modify global state in such a
+way that it may impact later feature tests are either (A) very
+intentionally defined to do so (e.g. the `--with-wasi-sdk` flag has
+invasive side-effects) or (B) are oversights (i.e. bugs).
+
+This tree's [configure script][auto.def], [utility APIs][proj.tcl],
+[Makefile.in][], and [main.mk][] therefore strive to separate the
+results of any given feature test into its own well-defined
+variables. For example:
+
+- The linker flags for zlib are exported from the configure script as
+ `LDFLAGS_ZLIB`, which [Makefile.in][] and [main.mk][] then expose as
+ `LDFLAGS.zlib`.
+- `CFLAGS_READLINE` (a.k.a. `CFLAGS.readline`) contains the `CFLAGS`
+ needed for including `libreadline`, `libedit`, or `linenoise`, and
+ `LDFLAGS_READLINE` (a.k.a. `LDFLAGS.readline`) is its link-time
+ counterpart.
+
+It is then up to the Makefile to apply and order the flags however is
+appropriate.
+
+At the end of the configure script, the global `CFLAGS` _ideally_
+holds only flags which are either relevant to all targets or, failing
+that, will have no unintended side-effects on any targets. That said:
+clients frequently pass custom `CFLAGS` to `./configure` or `make` to
+set library-level feature toggles, e.g. `-DSQLITE_OMIT_FOO`, in which
+case there is no practical way to avoid "polluting" the builds of
+arbitrary makefile targets with those. _C'est la vie._
+
+
+[^as-cflags]: But see this article for a detailed discussion of how
+ autosetup currently deals specifically with CFLAGS:
+ <https://msteveb.github.io/autosetup/articles/handling-cflags/>
+
+
+<a name="updating"></a>
+Updating Autosetup
+========================================================================
+
+Updating autosetup is, more often than not, painless. It requires having
+a checked-out copy of [the autosetup git repository][autosetup-git]:
+
+>
+```
+$ git clone https://github.com/msteveb/autosetup
+$ cd autosetup
+# Or, if it's already checked out:
+$ git pull
+```
+
+Then, from the top-most directory of an SQLite checkout:
+
+>
+```
+$ /path/to/autosetup-checkout/autosetup --install .
+$ fossil status # show the modified files
+```
+
+Unless the upgrade made any incompatible changes (which is exceedingly
+rare), that's all there is to it. After that's done, **apply a patch
+for the change described in the following section**, test the
+configure process, and check it in.
+
+<a name="patching"></a>
+Patching Autosetup for Project-local Changes
+------------------------------------------------------------------------
+
+Autosetup reserves the flag name **`--debug`** for its own purposes,
+and its own special handling of `--enable-...` flags makes `--debug`
+an alias for `--enable-debug`. As this project has a long history of
+using `--enable-debug`, we patch autosetup to use the name
+`--autosetup-debug` in place of `--debug`. That requires (as of this
+writing) four small edits in [](/file/autosetup/autosetup), as
+demonstrated in [check-in 3296c8d3](/info/3296c8d3).
+
+If autosetup is upgraded and this patch is _not_ applied the invoking
+`./configure` will fail loudly because of the declaration of the
+`debug` flag in `auto.def` - duplicated flags are not permitted.
+
+<a name="branch-customization"></a>
+Branch-specific Customization
+========================================================================
+
+Certain vendor-specific branches require slight configure script
+customization. Rather than editing `sqlite-config.tcl` for this,
+which frequently leads to merge conflicts, the following approach
+is recommended:
+
+In the vendor-specific branch, create a file named
+`autosetup/sqlite-custom.tcl`.
+
+That file should contain the following content...
+
+If flag customization is required, add:
+
+>
+```
+proc sqlite-custom-flags {} {
+ # If any existing --flags require different default values
+ # then call:
+ options-defaults {
+ flag-name new-default-value
+ ...
+ }
+ # ^^^ That will replace the default value but will not update
+ # the --help text, which may lead to some confusion:
+ # https://github.com/msteveb/autosetup/issues/77
+
+ return {
+ {*} {
+ new-flag-name => {Help text}
+ ...
+ }
+ }; #see below
+}
+```
+
+That function must return either an empty string or a list in the form
+used internally by `sqlite-config.tcl:sqlite-configure`.
+
+Next, define:
+
+>
+```
+proc sqlite-custom-handle-flags {} {
+ ... do any custom flag handling here ...
+}
+```
+
+That function, if defined, will be called relatively late in the
+configure process, before any filtered files are generated but after
+all other significant processing.
+
+
+[Autosetup]: https://msteveb.github.io/autosetup/
+[auto.def]: /file/auto.def
+[autoconf/auto.def]: /file/autoconf/auto.def
+[autosetup-git]: https://github.com/msteveb/autosetup
+[proj.tcl]: /file/autosetup/proj.tcl
+[sqlite-config.tcl]: /file/autosetup/sqlite-config.tcl
+[Makefile.in]: /file/Makefile.in
+[main.mk]: /file/main.mk
+[JimTCL]: https://jim.tcl.tk
diff --git a/contrib/sqlite3/autosetup/autosetup b/contrib/sqlite3/autosetup/autosetup
new file mode 100755
index 000000000000..239987554ff3
--- /dev/null
+++ b/contrib/sqlite3/autosetup/autosetup
@@ -0,0 +1,2540 @@
+#!/bin/sh
+# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+# vim:se syntax=tcl:
+# \
+dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
+
+# Note that the version has a trailing + on unreleased versions
+set autosetup(version) 0.7.2
+
+# Can be set to 1 to debug early-init problems
+set autosetup(debug) [expr {"--autosetup-debug" in $argv}]
+
+##################################################################
+#
+# Main flow of control, option handling
+#
+proc main {argv} {
+ global autosetup define
+
+ # There are 3 potential directories involved:
+ # 1. The directory containing autosetup (this script)
+ # 2. The directory containing auto.def
+ # 3. The current directory
+
+ # From this we need to determine:
+ # a. The path to this script (and related support files)
+ # b. The path to auto.def
+ # c. The build directory, where output files are created
+
+ # This is also complicated by the fact that autosetup may
+ # have been run via the configure wrapper ([getenv WRAPPER] is set)
+
+ # Here are the rules.
+ # a. This script is $::argv0
+ # => dir, prog, exe, libdir
+ # b. auto.def is in the directory containing the configure wrapper,
+ # otherwise it is in the current directory.
+ # => srcdir, autodef
+ # c. The build directory is the current directory
+ # => builddir, [pwd]
+
+ # 'misc' is needed before we can do anything, so set a temporary libdir
+ # in case this is the development version
+ set autosetup(libdir) [file dirname $::argv0]/lib
+ use misc
+
+ # (a)
+ set autosetup(dir) [realdir [file dirname [realpath $::argv0]]]
+ set autosetup(prog) [file join $autosetup(dir) [file tail $::argv0]]
+ set autosetup(exe) [getenv WRAPPER $autosetup(prog)]
+ if {$autosetup(installed)} {
+ set autosetup(libdir) $autosetup(dir)
+ } else {
+ set autosetup(libdir) [file join $autosetup(dir) lib]
+ }
+ autosetup_add_dep $autosetup(prog)
+
+ # (b)
+ if {[getenv WRAPPER ""] eq ""} {
+ # Invoked directly
+ set autosetup(srcdir) [pwd]
+ } else {
+ # Invoked via the configure wrapper
+ set autosetup(srcdir) [file-normalize [file dirname $autosetup(exe)]]
+ }
+ set autosetup(autodef) [relative-path $autosetup(srcdir)/auto.def]
+
+ # (c)
+ set autosetup(builddir) [pwd]
+
+ set autosetup(argv) $argv
+ set autosetup(cmdline) {}
+ # options is a list of known options
+ set autosetup(options) {}
+ # optset is a dictionary of option values set by the user based on getopt
+ set autosetup(optset) {}
+ # optdefault is a dictionary of default values
+ set autosetup(optdefault) {}
+ # options-defaults is a dictionary of overrides for default values for options
+ set autosetup(options-defaults) {}
+ set autosetup(optionhelp) {}
+ set autosetup(showhelp) 0
+
+ use util
+
+ # Parse options
+ use getopt
+
+ # At the is point we don't know what is a valid option
+ # We simply parse anything that looks like an option
+ set autosetup(getopt) [getopt argv]
+
+ #"=Core Options:"
+ options-add {
+ help:=all => "display help and options. Optional: module name, such as --help=system"
+ licence license => "display the autosetup license"
+ version => "display the version of autosetup"
+ ref:=text manual:=text
+ reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
+ autosetup-debug => "display debugging output as autosetup runs"
+ install:=. => "install autosetup to the current or given directory"
+ }
+ if {$autosetup(installed)} {
+ # hidden options so we can produce a nice error
+ options-add {
+ sysinstall:path
+ }
+ } else {
+ options-add {
+ sysinstall:path => "install standalone autosetup to the given directory (e.g.: /usr/local)"
+ }
+ }
+ options-add {
+ force init:=help => "create initial auto.def, etc. Use --init=help for known types"
+ # Undocumented options
+ option-checking=1
+ nopager
+ quiet
+ timing
+ conf:
+ }
+
+ if {[opt-bool version]} {
+ puts $autosetup(version)
+ exit 0
+ }
+
+ # autosetup --conf=alternate-auto.def
+ if {[opt-str conf o]} {
+ set autosetup(autodef) $o
+ }
+
+ # Debugging output (set this early)
+ incr autosetup(debug) [opt-bool autosetup-debug]
+ incr autosetup(force) [opt-bool force]
+ incr autosetup(msg-quiet) [opt-bool quiet]
+ incr autosetup(msg-timing) [opt-bool timing]
+
+ # If the local module exists, source it now to allow for
+ # project-local customisations
+ if {[file exists $autosetup(libdir)/local.tcl]} {
+ use local
+ }
+
+ # Now any auto-load modules
+ autosetup_load_auto_modules
+
+ if {[opt-str help o]} {
+ incr autosetup(showhelp)
+ use help
+ autosetup_help $o
+ }
+
+ if {[opt-bool licence license]} {
+ use help
+ autosetup_show_license
+ exit 0
+ }
+
+ if {[opt-str {manual ref reference} o]} {
+ use help
+ autosetup_reference $o
+ }
+
+ # Allow combining --install and --init
+ set earlyexit 0
+ if {[opt-str install o]} {
+ use install
+ autosetup_install $o
+ incr earlyexit
+ }
+
+ if {[opt-str init o]} {
+ use init
+ autosetup_init $o
+ incr earlyexit
+ }
+
+ if {$earlyexit} {
+ exit 0
+ }
+ if {[opt-str sysinstall o]} {
+ use install
+ autosetup_install $o 1
+ exit 0
+ }
+
+ if {![file exists $autosetup(autodef)]} {
+ # Check for invalid option first
+ options {}
+ user-error "No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)"
+ }
+
+ # Parse extra arguments into autosetup(cmdline)
+ foreach arg $argv {
+ if {[regexp {([^=]*)=(.*)} $arg -> n v]} {
+ dict set autosetup(cmdline) $n $v
+ define $n $v
+ } else {
+ user-error "Unexpected parameter: $arg"
+ }
+ }
+
+ autosetup_add_dep $autosetup(autodef)
+
+ # Add $argv to CONFIGURE_OPTS
+ define-append-argv CONFIGURE_OPTS {*}$autosetup(argv)
+ # Set up AUTOREMAKE to reconfigure with the same args
+ define-append-argv AUTOREMAKE {*}$autosetup(exe) {*}$autosetup(argv)
+
+ # Log how we were invoked
+ configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
+ configlog "Tclsh: [info nameofexecutable]"
+
+ # Load auto.def as module "auto.def"
+ autosetup_load_module auto.def source $autosetup(autodef)
+
+ # Could warn here if options {} was not specified
+
+ show-notices
+
+ if {$autosetup(debug)} {
+ msg-result "Writing all defines to config.log"
+ configlog "================ defines ======================"
+ foreach n [lsort [array names define]] {
+ configlog "define $n $define($n)"
+ }
+ }
+
+ exit 0
+}
+
+# @section Option Handling
+
+# @opt-bool ?-nodefault? option ...
+#
+# Check each of the named, boolean options and if any have been explicitly enabled
+# or disabled by the user, return 1 or 0 accordingly.
+#
+# If the option was specified more than once, the last value wins.
+# e.g. With '--enable-foo --disable-foo', '[opt-bool foo]' will return 0
+#
+# If no value was specified by the user, returns the default value for the
+# first option. If '-nodefault' is given, this behaviour changes and
+# -1 is returned instead.
+#
+proc opt-bool {args} {
+ set nodefault 0
+ if {[lindex $args 0] eq "-nodefault"} {
+ set nodefault 1
+ set args [lrange $args 1 end]
+ }
+ option-check-names {*}$args
+
+ foreach opt $args {
+ if {[dict exists $::autosetup(optset) $opt]} {
+ return [dict get $::autosetup(optset) $opt]
+ }
+ }
+
+ if {$nodefault} {
+ return -1
+ }
+ # Default value is the default for the first option
+ return [dict get $::autosetup(optdefault) [lindex $args 0]]
+}
+
+# @opt-val optionlist ?default=""?
+#
+# Returns a list containing all the values given for the non-boolean options in '$optionlist'.
+# There will be one entry in the list for each option given by the user, including if the
+# same option was used multiple times.
+#
+# If no options were set, '$default' is returned (exactly, not as a list).
+#
+# Note: For most use cases, 'opt-str' should be preferred.
+#
+proc opt-val {names {default ""}} {
+ option-check-names {*}$names
+
+ foreach opt $names {
+ if {[dict exists $::autosetup(optset) $opt]} {
+ lappend result {*}[dict get $::autosetup(optset) $opt]
+ }
+ }
+ if {[info exists result]} {
+ return $result
+ }
+ return $default
+}
+
+# @opt-str optionlist varname ?default?
+#
+# Sets '$varname' in the callers scope to the value for one of the given options.
+#
+# For the list of options given in '$optionlist', if any value is set for any option,
+# the option value is taken to be the *last* value of the last option (in the order given).
+#
+# If no option was given, and a default was specified with 'options-defaults',
+# that value is used.
+#
+# If no 'options-defaults' value was given and '$default' was given, it is used.
+#
+# If none of the above provided a value, no value is set.
+#
+# The return value depends on whether '$default' was specified.
+# If it was, the option value is returned.
+# If it was not, 1 is returns if a value was set, or 0 if not.
+#
+# Typical usage is as follows:
+#
+## if {[opt-str {myopt altname} o]} {
+## do something with $o
+## }
+#
+# Or:
+## define myname [opt-str {myopt altname} o "/usr/local"]
+#
+proc opt-str {names varname args} {
+ global autosetup
+
+ option-check-names {*}$names
+ upvar $varname value
+
+ if {[llength $args]} {
+ # A default was given, so always return the string value of the option
+ set default [lindex $args 0]
+ set retopt 1
+ } else {
+ # No default, so return 0 or 1 to indicate if a value was found
+ set retopt 0
+ }
+
+ foreach opt $names {
+ if {[dict exists $::autosetup(optset) $opt]} {
+ set result [lindex [dict get $::autosetup(optset) $opt] end]
+ }
+ }
+
+ if {![info exists result]} {
+ # No user-specified value. Has options-defaults been set?
+ foreach opt $names {
+ if {[dict exists $::autosetup(optdefault) $opt]} {
+ set result [dict get $autosetup(optdefault) $opt]
+ }
+ }
+ }
+
+ if {[info exists result]} {
+ set value $result
+ if {$retopt} {
+ return $value
+ }
+ return 1
+ }
+
+ if {$retopt} {
+ set value $default
+ return $value
+ }
+
+ return 0
+}
+
+proc option-check-names {args} {
+ foreach o $args {
+ if {$o ni $::autosetup(options)} {
+ autosetup-error "Request for undeclared option --$o"
+ }
+ }
+}
+
+# Parse the option definition in $opts and update
+# ::autosetup(setoptions) and ::autosetup(optionhelp) appropriately
+#
+proc options-add {opts} {
+ global autosetup
+
+ # First weed out comment lines
+ set realopts {}
+ foreach line [split $opts \n] {
+ if {![string match "#*" [string trimleft $line]]} {
+ append realopts $line \n
+ }
+ }
+ set opts $realopts
+
+ for {set i 0} {$i < [llength $opts]} {incr i} {
+ set opt [lindex $opts $i]
+ if {[string match =* $opt]} {
+ # This is a special heading
+ lappend autosetup(optionhelp) [list $opt $autosetup(module)]
+ continue
+ }
+ unset -nocomplain defaultvalue equal value
+
+ #puts "i=$i, opt=$opt"
+ regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
+ if {$name in $autosetup(options)} {
+ autosetup-error "Option $name already specified"
+ }
+
+ #puts "$opt => $name $colon $equal $value"
+
+ # Find the corresponding value in the user options
+ # and set the default if necessary
+ if {[string match "-*" $opt]} {
+ # This is a documentation-only option, like "-C <dir>"
+ set opthelp $opt
+ } elseif {$colon eq ""} {
+ # Boolean option
+ lappend autosetup(options) $name
+
+ # Check for override
+ if {[dict exists $autosetup(options-defaults) $name]} {
+ # A default was specified with options-defaults, so use it
+ set value [dict get $autosetup(options-defaults) $name]
+ }
+
+ if {$value eq "1"} {
+ set opthelp "--disable-$name"
+ } else {
+ set opthelp "--$name"
+ }
+
+ # Set the default
+ if {$value eq ""} {
+ set value 0
+ }
+ set defaultvalue $value
+ dict set autosetup(optdefault) $name $defaultvalue
+
+ if {[dict exists $autosetup(getopt) $name]} {
+ # The option was specified by the user. Look at the last value.
+ lassign [lindex [dict get $autosetup(getopt) $name] end] type setvalue
+ if {$type eq "str"} {
+ # Can we convert the value to a boolean?
+ if {$setvalue in {1 enabled yes}} {
+ set setvalue 1
+ } elseif {$setvalue in {0 disabled no}} {
+ set setvalue 0
+ } else {
+ user-error "Boolean option $name given as --$name=$setvalue"
+ }
+ }
+ dict set autosetup(optset) $name $setvalue
+ #puts "Found boolean option --$name=$setvalue"
+ }
+ } else {
+ # String option.
+ lappend autosetup(options) $name
+
+ if {$equal ne "="} {
+ # Was the option given as "name:value=default"?
+ # If so, set $value to the display name and $defaultvalue to the default
+ # (This is the preferred way to set a default value for a string option)
+ if {[regexp {^([^=]+)=(.*)$} $value -> value defaultvalue]} {
+ dict set autosetup(optdefault) $name $defaultvalue
+ }
+ }
+
+ # Maybe override the default value
+ if {[dict exists $autosetup(options-defaults) $name]} {
+ # A default was specified with options-defaults, so use it
+ set defaultvalue [dict get $autosetup(options-defaults) $name]
+ dict set autosetup(optdefault) $name $defaultvalue
+ } elseif {![info exists defaultvalue]} {
+ # No default value was given by value=default or options-defaults
+ # so use the value as the default when the plain option with no
+ # value is given (.e.g. just --opt instead of --opt=value)
+ set defaultvalue $value
+ }
+
+ if {$equal eq "="} {
+ # String option with optional value
+ set opthelp "--$name?=$value?"
+ } else {
+ # String option with required value
+ set opthelp "--$name=$value"
+ }
+
+ # Get the values specified by the user
+ if {[dict exists $autosetup(getopt) $name]} {
+ set listvalue {}
+
+ foreach pair [dict get $autosetup(getopt) $name] {
+ lassign $pair type setvalue
+ if {$type eq "bool" && $setvalue} {
+ if {$equal ne "="} {
+ user-error "Option --$name requires a value"
+ }
+ # If given as a boolean, use the default value
+ set setvalue $defaultvalue
+ }
+ lappend listvalue $setvalue
+ }
+
+ #puts "Found string option --$name=$listvalue"
+ dict set autosetup(optset) $name $listvalue
+ }
+ }
+
+ # Now create the help for this option if appropriate
+ if {[lindex $opts $i+1] eq "=>"} {
+ set desc [lindex $opts $i+2]
+ if {[info exists defaultvalue]} {
+ set desc [string map [list @default@ $defaultvalue] $desc]
+ }
+ # A multi-line description
+ lappend autosetup(optionhelp) [list $opthelp $autosetup(module) $desc]
+ incr i 2
+ }
+ }
+}
+
+# @module-options optionlist
+#
+# Deprecated. Simply use 'options' from within a module.
+proc module-options {opts} {
+ options $opts
+}
+
+proc max {a b} {
+ expr {$a > $b ? $a : $b}
+}
+
+proc options-wrap-desc {text length firstprefix nextprefix initial} {
+ set len $initial
+ set space $firstprefix
+ foreach word [split $text] {
+ set word [string trim $word]
+ if {$word == ""} {
+ continue
+ }
+ if {$len && [string length $space$word] + $len >= $length} {
+ puts ""
+ set len 0
+ set space $nextprefix
+ }
+ incr len [string length $space$word]
+ puts -nonewline $space$word
+ set space " "
+ }
+ if {$len} {
+ puts ""
+ }
+}
+
+# Display options (from $autosetup(optionhelp)) for modules that match
+# glob pattern $what
+proc options-show {what} {
+ set local 0
+ # Determine the max option width
+ set max 0
+ foreach help $::autosetup(optionhelp) {
+ lassign $help opt module desc
+ if {![string match $what $module]} {
+ continue
+ }
+ if {[string match =* $opt] || [string match \n* $desc]} {
+ continue
+ }
+ set max [max $max [string length $opt]]
+ }
+ set indent [string repeat " " [expr {$max+4}]]
+ set cols [getenv COLUMNS 80]
+ catch {
+ lassign [exec stty size] _ sttycols
+ if {[string is integer -strict $sttycols]} {
+ set cols $sttycols
+ }
+ }
+ incr cols -1
+ # Now output
+ foreach help $::autosetup(optionhelp) {
+ lassign $help opt module desc
+ if {![string match $what $module]} {
+ continue
+ }
+ if {$local == 0 && $module eq "auto.def"} {
+ puts "Local Options:"
+ incr local
+ }
+ if {[string match =* $opt]} {
+ # Output a special heading line"
+ puts [string range $opt 1 end]
+ continue
+ }
+ puts -nonewline " [format %-${max}s $opt]"
+ if {[string match \n* $desc]} {
+ # Output a pre-formatted help description as-is
+ puts $desc
+ } else {
+ options-wrap-desc [string trim $desc] $cols " " $indent [expr {$max+2}]
+ }
+ }
+}
+
+# @options optionspec
+#
+# Specifies configuration-time options which may be selected by the user
+# and checked with 'opt-str' and 'opt-bool'. '$optionspec' contains a series
+# of options specifications separated by newlines, as follows:
+#
+# A boolean option is of the form:
+#
+## name[=0|1] => "Description of this boolean option"
+#
+# The default is 'name=0', meaning that the option is disabled by default.
+# If 'name=1' is used to make the option enabled by default, the description should reflect
+# that with text like "Disable support for ...".
+#
+# An argument option (one which takes a parameter) is of one of the following forms:
+#
+## name:value => "Description of this option"
+## name:value=default => "Description of this option with a default value"
+## name:=value => "Description of this option with an optional value"
+#
+# If the 'name:value' form is used, the value must be provided with the option (as '--name=myvalue').
+# If the 'name:value=default' form is used, the option has the given default value even if not
+# specified by the user.
+# If the 'name:=value' form is used, the value is optional and the given value is used
+# if it is not provided.
+#
+# The description may contain '@default@', in which case it will be replaced with the default
+# value for the option (taking into account defaults specified with 'options-defaults'.
+#
+# Undocumented options are also supported by omitting the '=> description'.
+# These options are not displayed with '--help' and can be useful for internal options or as aliases.
+#
+# For example, '--disable-lfs' is an alias for '--disable=largefile':
+#
+## lfs=1 largefile=1 => "Disable large file support"
+#
+proc options {optlist} {
+ global autosetup
+
+ options-add $optlist
+
+ if {$autosetup(showhelp)} {
+ # If --help, stop now to show help
+ return -code break
+ }
+
+ if {$autosetup(module) eq "auto.def"} {
+ # Check for invalid options
+ if {[opt-bool option-checking]} {
+ foreach o [dict keys $::autosetup(getopt)] {
+ if {$o ni $::autosetup(options)} {
+ user-error "Unknown option --$o"
+ }
+ }
+ }
+ }
+}
+
+# @options-defaults dictionary
+#
+# Specifies a dictionary of options and a new default value for each of those options.
+# Use before any 'use' statements in 'auto.def' to change the defaults for
+# subsequently included modules.
+proc options-defaults {dict} {
+ foreach {n v} $dict {
+ dict set ::autosetup(options-defaults) $n $v
+ }
+}
+
+proc config_guess {} {
+ if {[file-isexec $::autosetup(dir)/autosetup-config.guess]} {
+ if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.guess} alias]} {
+ user-error $alias
+ }
+ return $alias
+ } else {
+ configlog "No autosetup-config.guess, so using uname"
+ string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
+ }
+}
+
+proc config_sub {alias} {
+ if {[file-isexec $::autosetup(dir)/autosetup-config.sub]} {
+ if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.sub $alias} alias]} {
+ user-error $alias
+ }
+ }
+ return $alias
+}
+
+# @section Variable Definitions (defines)
+
+# @define name ?value=1?
+#
+# Defines the named variable to the given value.
+# These (name, value) pairs represent the results of the configuration check
+# and are available to be subsequently checked, modified and substituted.
+#
+proc define {name {value 1}} {
+ set ::define($name) $value
+ #dputs "$name <= $value"
+}
+
+# @define-push {name ...} script
+#
+# Save the values of the given defines, evaluation the script, then restore.
+# For example, to avoid updating AS_FLAGS and AS_CXXFLAGS:
+## define-push {AS_CFLAGS AS_CXXFLAGS} {
+## cc-check-flags -Wno-error
+## }
+proc define-push {names script} {
+ array set unset {}
+ foreach name $names {
+ if {[is-defined $name]} {
+ set save($name) [get-define $name]
+ } else {
+ set unset($name) 1
+ }
+ }
+ uplevel 1 $script
+ array set ::define [array get save]
+ foreach name [array names unset] {
+ unset -nocomplain ::define($name)
+ }
+}
+
+# @undefine name
+#
+# Undefine the named variable.
+#
+proc undefine {name} {
+ unset -nocomplain ::define($name)
+ #dputs "$name <= <undef>"
+}
+
+# @define-append name value ...
+#
+# Appends the given value(s) to the given "defined" variable.
+# If the variable is not defined or empty, it is set to '$value'.
+# Otherwise the value is appended, separated by a space.
+# Any extra values are similarly appended.
+#
+# Note that define-append is not designed to add values containing spaces.
+# If values may contain spaces, consider define-append-argv instead.
+#
+proc define-append {name args} {
+ if {[get-define $name ""] ne ""} {
+ foreach arg $args {
+ if {$arg eq ""} {
+ continue
+ }
+ append ::define($name) " " $arg
+ }
+ } else {
+ set ::define($name) [join $args]
+ }
+ #dputs "$name += [join $args] => $::define($name)"
+}
+
+# @define-append-argv name value ...
+#
+# Similar to define-append except designed to construct shell command
+# lines, including correct handling of parameters with spaces.
+#
+# Each non-empty value is quoted if necessary and then appended to the given variable
+# if it does not already exist.
+#
+proc define-append-argv {name args} {
+ set seen {}
+ set new {}
+ foreach val [list {*}[get-define $name ""] {*}$args] {
+ if {$val ne {} && ![dict exists $seen $val]} {
+ lappend new [quote-if-needed $val]
+ dict set seen $val 1
+ }
+ }
+ set ::define($name) [join $new " "]
+ #dputs "$name += [join $args] => $::define($name)"
+}
+
+# @get-define name ?default=0?
+#
+# Returns the current value of the "defined" variable, or '$default'
+# if not set.
+#
+proc get-define {name {default 0}} {
+ if {[info exists ::define($name)]} {
+ #dputs "$name => $::define($name)"
+ return $::define($name)
+ }
+ #dputs "$name => $default"
+ return $default
+}
+
+# @is-defined name
+#
+# Returns 1 if the given variable is defined.
+#
+proc is-defined {name} {
+ info exists ::define($name)
+}
+
+# @is-define-set name
+#
+# Returns 1 if the given variable is defined and is set
+# to a value other than "" or 0
+#
+proc is-define-set {name} {
+ if {[get-define $name] in {0 ""}} {
+ return 0
+ }
+ return 1
+}
+
+# @all-defines
+#
+# Returns a dictionary (name, value list) of all defined variables.
+#
+# This is suitable for use with 'dict', 'array set' or 'foreach'
+# and allows for arbitrary processing of the defined variables.
+#
+proc all-defines {} {
+ array get ::define
+}
+
+# @section Environment/Helpers
+
+# @get-env name default
+#
+# If '$name' was specified on the command line, return it.
+# Otherwise if '$name' was set in the environment, return it.
+# Otherwise return '$default'.
+#
+proc get-env {name default} {
+ if {[dict exists $::autosetup(cmdline) $name]} {
+ return [dict get $::autosetup(cmdline) $name]
+ }
+ getenv $name $default
+}
+
+# @env-is-set name
+#
+# Returns 1 if '$name' was specified on the command line or in the environment.
+# Note that an empty environment variable is not considered to be set.
+#
+proc env-is-set {name} {
+ if {[dict exists $::autosetup(cmdline) $name]} {
+ return 1
+ }
+ if {[getenv $name ""] ne ""} {
+ return 1
+ }
+ return 0
+}
+
+# @readfile filename ?default=""?
+#
+# Return the contents of the file, without the trailing newline.
+# If the file doesn't exist or can't be read, returns '$default'.
+#
+proc readfile {filename {default_value ""}} {
+ set result $default_value
+ catch {
+ set f [open $filename]
+ set result [read -nonewline $f]
+ close $f
+ }
+ return $result
+}
+
+# @writefile filename value
+#
+# Creates the given file containing '$value'.
+# Does not add an extra newline.
+#
+proc writefile {filename value} {
+ set f [open $filename w]
+ puts -nonewline $f $value
+ close $f
+}
+
+proc quote-if-needed {str} {
+ if {[string match {*[\" ]*} $str]} {
+ return \"[string map [list \" \\" \\ \\\\] $str]\"
+ }
+ return $str
+}
+
+proc quote-argv {argv} {
+ set args {}
+ foreach arg $argv {
+ lappend args [quote-if-needed $arg]
+ }
+ join $args
+}
+
+# @list-non-empty list
+#
+# Returns a copy of the given list with empty elements removed
+proc list-non-empty {list} {
+ set result {}
+ foreach p $list {
+ if {$p ne ""} {
+ lappend result $p
+ }
+ }
+ return $result
+}
+
+# @section Paths, Searching
+
+# @find-executable-path name
+#
+# Searches the path for an executable with the given name.
+# Note that the name may include some parameters, e.g. 'cc -mbig-endian',
+# in which case the parameters are ignored.
+# Returns the full path to the executable if found, or "" if not found.
+#
+proc find-executable-path {name} {
+ # Ignore any parameters
+ set name [lindex $name 0]
+ # The empty string is never a valid executable
+ if {$name ne ""} {
+ foreach p [split-path] {
+ dputs "Looking for $name in $p"
+ set exec [file join $p $name]
+ if {[file-isexec $exec]} {
+ dputs "Found $name -> $exec"
+ return $exec
+ }
+ }
+ }
+ return {}
+}
+
+# @find-executable name
+#
+# Searches the path for an executable with the given name.
+# Note that the name may include some parameters, e.g. 'cc -mbig-endian',
+# in which case the parameters are ignored.
+# Returns 1 if found, or 0 if not.
+#
+proc find-executable {name} {
+ if {[find-executable-path $name] eq {}} {
+ return 0
+ }
+ return 1
+}
+
+# @find-an-executable ?-required? name ...
+#
+# Given a list of possible executable names,
+# searches for one of these on the path.
+#
+# Returns the name found, or "" if none found.
+# If the first parameter is '-required', an error is generated
+# if no executable is found.
+#
+proc find-an-executable {args} {
+ set required 0
+ if {[lindex $args 0] eq "-required"} {
+ set args [lrange $args 1 end]
+ incr required
+ }
+ foreach name $args {
+ if {[find-executable $name]} {
+ return $name
+ }
+ }
+ if {$required} {
+ if {[llength $args] == 1} {
+ user-error "failed to find: [join $args]"
+ } else {
+ user-error "failed to find one of: [join $args]"
+ }
+ }
+ return ""
+}
+
+# @section Logging, Messages and Errors
+
+# @configlog msg
+#
+# Writes the given message to the configuration log, 'config.log'.
+#
+proc configlog {msg} {
+ if {![info exists ::autosetup(logfh)]} {
+ set ::autosetup(logfh) [open config.log w]
+ }
+ puts $::autosetup(logfh) $msg
+}
+
+# @msg-checking msg
+#
+# Writes the message with no newline to stdout.
+#
+proc msg-checking {msg} {
+ if {$::autosetup(msg-quiet) == 0} {
+ maybe-show-timestamp
+ puts -nonewline $msg
+ set ::autosetup(msg-checking) 1
+ }
+}
+
+# @msg-result msg
+#
+# Writes the message to stdout.
+#
+proc msg-result {msg} {
+ if {$::autosetup(msg-quiet) == 0} {
+ maybe-show-timestamp
+ puts $msg
+ set ::autosetup(msg-checking) 0
+ show-notices
+ }
+}
+
+# @msg-quiet command ...
+#
+# 'msg-quiet' evaluates it's arguments as a command with output
+# from 'msg-checking' and 'msg-result' suppressed.
+#
+# This is useful if a check needs to run a subcheck which isn't
+# of interest to the user.
+proc msg-quiet {args} {
+ incr ::autosetup(msg-quiet)
+ set rc [uplevel 1 $args]
+ incr ::autosetup(msg-quiet) -1
+ return $rc
+}
+
+# Will be overridden by 'use misc'
+proc error-stacktrace {msg} {
+ return $msg
+}
+
+proc error-location {msg} {
+ return $msg
+}
+
+##################################################################
+#
+# Debugging output
+#
+proc dputs {msg} {
+ if {$::autosetup(debug)} {
+ puts $msg
+ }
+}
+
+##################################################################
+#
+# User and system warnings and errors
+#
+# Usage errors such as wrong command line options
+
+# @user-error msg
+#
+# Indicate incorrect usage to the user, including if required components
+# or features are not found.
+# 'autosetup' exits with a non-zero return code.
+#
+proc user-error {msg} {
+ show-notices
+ puts stderr "Error: $msg"
+ puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
+ exit 1
+}
+
+# @user-notice msg
+#
+# Output the given message to stderr.
+#
+proc user-notice {msg} {
+ lappend ::autosetup(notices) $msg
+}
+
+# Incorrect usage in the auto.def file. Identify the location.
+proc autosetup-error {msg} {
+ autosetup-full-error [error-location $msg]
+}
+
+# Like autosetup-error, except $msg is the full error message.
+proc autosetup-full-error {msg} {
+ show-notices
+ puts stderr $msg
+ exit 1
+}
+
+proc show-notices {} {
+ if {$::autosetup(msg-checking)} {
+ puts ""
+ set ::autosetup(msg-checking) 0
+ }
+ flush stdout
+ if {[info exists ::autosetup(notices)]} {
+ puts stderr [join $::autosetup(notices) \n]
+ unset ::autosetup(notices)
+ }
+}
+
+proc maybe-show-timestamp {} {
+ if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
+ puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
+ }
+}
+
+# @autosetup-require-version required
+#
+# Checks the current version of 'autosetup' against '$required'.
+# A fatal error is generated if the current version is less than that required.
+#
+proc autosetup-require-version {required} {
+ if {[compare-versions $::autosetup(version) $required] < 0} {
+ user-error "autosetup version $required is required, but this is $::autosetup(version)"
+ }
+}
+
+proc autosetup_version {} {
+ return "autosetup v$::autosetup(version)"
+}
+
+##################################################################
+#
+# Directory/path handling
+#
+
+proc realdir {dir} {
+ set oldpwd [pwd]
+ cd $dir
+ set pwd [pwd]
+ cd $oldpwd
+ return $pwd
+}
+
+# Follow symlinks until we get to something which is not a symlink
+proc realpath {path} {
+ while {1} {
+ if {[catch {
+ set path [file readlink $path]
+ }]} {
+ # Not a link
+ break
+ }
+ }
+ return $path
+}
+
+# Convert absolute path, $path into a path relative
+# to the given directory (or the current dir, if not given).
+#
+proc relative-path {path {pwd {}}} {
+ set diff 0
+ set same 0
+ set newf {}
+ set prefix {}
+ set path [file-normalize $path]
+ if {$pwd eq ""} {
+ set pwd [pwd]
+ } else {
+ set pwd [file-normalize $pwd]
+ }
+
+ if {$path eq $pwd} {
+ return .
+ }
+
+ # Try to make the filename relative to the current dir
+ foreach p [split $pwd /] f [split $path /] {
+ if {$p ne $f} {
+ incr diff
+ } elseif {!$diff} {
+ incr same
+ }
+ if {$diff} {
+ if {$p ne ""} {
+ # Add .. for sibling or parent dir
+ lappend prefix ..
+ }
+ if {$f ne ""} {
+ lappend newf $f
+ }
+ }
+ }
+ if {$same == 1 || [llength $prefix] > 3} {
+ return $path
+ }
+
+ file join [join $prefix /] [join $newf /]
+}
+
+# Add filename as a dependency to rerun autosetup
+# The name will be normalised (converted to a full path)
+#
+proc autosetup_add_dep {filename} {
+ lappend ::autosetup(deps) [file-normalize $filename]
+}
+
+# @section Modules Support
+
+##################################################################
+#
+# Library module support
+#
+
+# @use module ...
+#
+# Load the given library modules.
+# e.g. 'use cc cc-shared'
+#
+# Note that module 'X' is implemented in either 'autosetup/X.tcl'
+# or 'autosetup/X/init.tcl'
+#
+# The latter form is useful for a complex module which requires additional
+# support file. In this form, '$::usedir' is set to the module directory
+# when it is loaded.
+#
+proc use {args} {
+ global autosetup libmodule modsource
+
+ set dirs [list $autosetup(libdir)]
+ if {[info exists autosetup(srcdir)]} {
+ lappend dirs $autosetup(srcdir)/autosetup
+ }
+ foreach m $args {
+ if {[info exists libmodule($m)]} {
+ continue
+ }
+ set libmodule($m) 1
+
+ if {[info exists modsource(${m}.tcl)]} {
+ autosetup_load_module $m eval $modsource(${m}.tcl)
+ } else {
+ set locs [list ${m}.tcl ${m}/init.tcl]
+ set found 0
+ foreach dir $dirs {
+ foreach loc $locs {
+ set source $dir/$loc
+ if {[file exists $source]} {
+ incr found
+ break
+ }
+ }
+ if {$found} {
+ break
+ }
+ }
+ if {$found} {
+ # For the convenience of the "use" source, point to the directory
+ # it is being loaded from
+ set ::usedir [file dirname $source]
+ autosetup_load_module $m source $source
+ autosetup_add_dep $source
+ } else {
+ autosetup-error "use: No such module: $m"
+ }
+ }
+ }
+}
+
+proc autosetup_load_auto_modules {} {
+ global autosetup modsource
+ # First load any embedded auto modules
+ foreach mod [array names modsource *.auto] {
+ autosetup_load_module $mod eval $modsource($mod)
+ }
+ # Now any external auto modules
+ foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
+ autosetup_load_module [file tail $file] source $file
+ }
+}
+
+# Load module source in the global scope by executing the given command
+proc autosetup_load_module {module args} {
+ global autosetup
+ set prev $autosetup(module)
+ set autosetup(module) $module
+
+ if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
+ autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
+ }
+ set autosetup(module) $prev
+}
+
+# Initial settings
+set autosetup(exe) $::argv0
+set autosetup(istcl) 1
+set autosetup(start) [clock millis]
+set autosetup(installed) 0
+set autosetup(sysinstall) 0
+set autosetup(msg-checking) 0
+set autosetup(msg-quiet) 0
+set autosetup(inittypes) {}
+set autosetup(module) autosetup
+
+# Embedded modules are inserted below here
+set autosetup(installed) 1
+set autosetup(sysinstall) 0
+# ----- @module asciidoc-formatting.tcl -----
+
+set modsource(asciidoc-formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# asciidoc format
+
+use formatting
+
+proc para {text} {
+ regsub -all "\[ \t\n\]+" [string trim $text] " "
+}
+proc title {text} {
+ underline [para $text] =
+ nl
+}
+proc p {text} {
+ puts [para $text]
+ nl
+}
+proc code {text} {
+ foreach line [parse_code_block $text] {
+ puts " $line"
+ }
+ nl
+}
+proc codelines {lines} {
+ foreach line $lines {
+ puts " $line"
+ }
+ nl
+}
+proc nl {} {
+ puts ""
+}
+proc underline {text char} {
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
+ puts $text
+ puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+ underline "[para $text]" -
+ nl
+}
+proc subsection {text} {
+ underline "$text" ~
+ nl
+}
+proc bullet {text} {
+ puts "* [para $text]"
+}
+proc indent {text} {
+ puts " :: "
+ puts [para $text]
+}
+proc defn {first args} {
+ set sep ""
+ if {$first ne ""} {
+ puts "${first}::"
+ } else {
+ puts " :: "
+ }
+ set defn [string trim [join $args \n]]
+ regsub -all "\n\n" $defn "\n ::\n" defn
+ puts $defn
+}
+}
+
+# ----- @module formatting.tcl -----
+
+set modsource(formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides common text formatting
+
+# This is designed for documentation which looks like:
+# code {...}
+# or
+# code {
+# ...
+# ...
+# }
+# In the second case, we need to work out the indenting
+# and strip it from all lines but preserve the remaining indenting.
+# Note that all lines need to be indented with the same initial
+# spaces/tabs.
+#
+# Returns a list of lines with the indenting removed.
+#
+proc parse_code_block {text} {
+ # If the text begins with newline, take the following text,
+ # otherwise just return the original
+ if {![regexp "^\n(.*)" $text -> text]} {
+ return [list [string trim $text]]
+ }
+
+ # And trip spaces off the end
+ set text [string trimright $text]
+
+ set min 100
+ # Examine each line to determine the minimum indent
+ foreach line [split $text \n] {
+ if {$line eq ""} {
+ # Ignore empty lines for the indent calculation
+ continue
+ }
+ regexp "^(\[ \t\]*)" $line -> indent
+ set len [string length $indent]
+ if {$len < $min} {
+ set min $len
+ }
+ }
+
+ # Now make a list of lines with this indent removed
+ set lines {}
+ foreach line [split $text \n] {
+ lappend lines [string range $line $min end]
+ }
+
+ # Return the result
+ return $lines
+}
+}
+
+# ----- @module getopt.tcl -----
+
+set modsource(getopt.tcl) {
+# Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Simple getopt module
+
+# Parse everything out of the argv list which looks like an option
+# Everything which doesn't look like an option, or is after --, is left unchanged
+# Understands --enable-xxx as a synonym for --xxx to enable the boolean option xxx.
+# Understands --disable-xxx to disable the boolean option xxx.
+#
+# The returned value is a dictionary keyed by option name
+# Each value is a list of {type value} ... where type is "bool" or "str".
+# The value for a boolean option is 0 or 1. The value of a string option is the value given.
+proc getopt {argvname} {
+ upvar $argvname argv
+ set nargv {}
+
+ set opts {}
+
+ for {set i 0} {$i < [llength $argv]} {incr i} {
+ set arg [lindex $argv $i]
+
+ #dputs arg=$arg
+
+ if {$arg eq "--"} {
+ # End of options
+ incr i
+ lappend nargv {*}[lrange $argv $i end]
+ break
+ }
+
+ if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
+ # --name=value
+ dict lappend opts $name [list str $value]
+ } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
+ if {$prefix in {enable- ""}} {
+ set value 1
+ } else {
+ set value 0
+ }
+ dict lappend opts $name [list bool $value]
+ } else {
+ lappend nargv $arg
+ }
+ }
+
+ #puts "getopt: argv=[join $argv] => [join $nargv]"
+ #array set getopt $opts
+ #parray getopt
+
+ set argv $nargv
+
+ return $opts
+}
+}
+
+# ----- @module help.tcl -----
+
+set modsource(help.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://workware.net.au/
+# All rights reserved
+
+# Module which provides usage, help and the command reference
+
+proc autosetup_help {what} {
+ use_pager
+
+ puts "Usage: [file tail $::autosetup(exe)] \[options\] \[settings\]\n"
+ puts "This is [autosetup_version], a build environment \"autoconfigurator\""
+ puts "See the documentation online at https://msteveb.github.io/autosetup/\n"
+
+ if {$what in {all local}} {
+ # Need to load auto.def now
+ if {[file exists $::autosetup(autodef)]} {
+ # Load auto.def as module "auto.def"
+ autosetup_load_module auto.def source $::autosetup(autodef)
+ }
+ if {$what eq "all"} {
+ set what *
+ } else {
+ set what auto.def
+ }
+ } else {
+ use $what
+ puts "Options for module $what:"
+ }
+ options-show $what
+ exit 0
+}
+
+proc autosetup_show_license {} {
+ global modsource autosetup
+ use_pager
+
+ if {[info exists modsource(LICENSE)]} {
+ puts $modsource(LICENSE)
+ return
+ }
+ foreach dir [list $autosetup(libdir) $autosetup(srcdir)] {
+ set path [file join $dir LICENSE]
+ if {[file exists $path]} {
+ puts [readfile $path]
+ return
+ }
+ }
+ puts "LICENSE not found"
+}
+
+# If not already paged and stdout is a tty, pipe the output through the pager
+# This is done by reinvoking autosetup with --nopager added
+proc use_pager {} {
+ if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
+ if {[catch {
+ exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& {*}[getenv PAGER] >@stdout <@stdin 2>@stderr
+ } msg opts] == 1} {
+ if {[dict get $opts -errorcode] eq "NONE"} {
+ # an internal/exec error
+ puts stderr $msg
+ exit 1
+ }
+ }
+ exit 0
+ }
+}
+
+# Outputs the autosetup references in one of several formats
+proc autosetup_reference {{type text}} {
+
+ use_pager
+
+ switch -glob -- $type {
+ wiki {use wiki-formatting}
+ ascii* {use asciidoc-formatting}
+ md - markdown {use markdown-formatting}
+ default {use text-formatting}
+ }
+
+ title "[autosetup_version] -- Command Reference"
+
+ section {Introduction}
+
+ p {
+ See https://msteveb.github.io/autosetup/ for the online documentation for 'autosetup'.
+ This documentation can also be accessed locally with `autosetup --ref`.
+ }
+
+ p {
+ 'autosetup' provides a number of built-in commands which
+ are documented below. These may be used from 'auto.def' to test
+ for features, define variables, create files from templates and
+ other similar actions.
+ }
+
+ automf_command_reference
+
+ exit 0
+}
+
+proc autosetup_output_block {type lines} {
+ if {[llength $lines]} {
+ switch $type {
+ section {
+ section $lines
+ }
+ subsection {
+ subsection $lines
+ }
+ code {
+ codelines $lines
+ }
+ p {
+ p [join $lines]
+ }
+ list {
+ foreach line $lines {
+ bullet $line
+ }
+ nl
+ }
+ }
+ }
+}
+
+# Generate a command reference from inline documentation
+proc automf_command_reference {} {
+ lappend files $::autosetup(prog)
+ lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
+
+ # We want to process all non-module files before module files
+ # and then modules in alphabetical order.
+ # So examine all files and extract docs into doc($modulename) and doc(_core_)
+ #
+ # Each entry is a list of {type data} where $type is one of: section, subsection, code, list, p
+ # and $data is a string for section, subsection or a list of text lines for other types.
+
+ # XXX: Should commands be in alphabetical order too? Currently they are in file order.
+
+ set doc(_core_) {}
+ lappend doc(_core_) [list section "Core Commands"]
+
+ foreach file $files {
+ set modulename [file rootname [file tail $file]]
+ set current _core_
+ set f [open $file]
+ while {![eof $f]} {
+ set line [gets $f]
+
+ if {[regexp {^#.*@section (.*)$} $line -> section]} {
+ lappend doc($current) [list section $section]
+ continue
+ }
+
+ # Find embedded module names
+ if {[regexp {^#.*@module ([^ ]*)} $line -> modulename]} {
+ continue
+ }
+
+ # Find lines starting with "# @*" and continuing through the remaining comment lines
+ if {![regexp {^# @(.*)} $line -> cmd]} {
+ continue
+ }
+
+ # Synopsis or command?
+ if {$cmd eq "synopsis:"} {
+ set current $modulename
+ lappend doc($current) [list section "Module: $modulename"]
+ } else {
+ lappend doc($current) [list subsection $cmd]
+ }
+
+ set lines {}
+ set type p
+
+ # Now the description
+ while {![eof $f]} {
+ set line [gets $f]
+
+ if {![regexp {^#(#)? ?(.*)} $line -> hash cmd]} {
+ break
+ }
+ if {$hash eq "#"} {
+ set t code
+ } elseif {[regexp {^- (.*)} $cmd -> cmd]} {
+ set t list
+ } else {
+ set t p
+ }
+
+ #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
+
+ if {$t ne $type || $cmd eq ""} {
+ # Finish the current block
+ lappend doc($current) [list $type $lines]
+ set lines {}
+ set type $t
+ }
+ if {$cmd ne ""} {
+ lappend lines $cmd
+ }
+ }
+
+ lappend doc($current) [list $type $lines]
+ }
+ close $f
+ }
+
+ # Now format and output the results
+
+ # _core_ will sort first
+ foreach module [lsort [array names doc]] {
+ foreach item $doc($module) {
+ autosetup_output_block {*}$item
+ }
+ }
+}
+}
+
+# ----- @module init.tcl -----
+
+set modsource(init.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module to help create auto.def and configure
+
+proc autosetup_init {type} {
+ set help 0
+ if {$type in {? help}} {
+ incr help
+ } elseif {![dict exists $::autosetup(inittypes) $type]} {
+ puts "Unknown type, --init=$type"
+ incr help
+ }
+ if {$help} {
+ puts "Use one of the following types (e.g. --init=make)\n"
+ foreach type [lsort [dict keys $::autosetup(inittypes)]] {
+ lassign [dict get $::autosetup(inittypes) $type] desc
+ # XXX: Use the options-show code to wrap the description
+ puts [format "%-10s %s" $type $desc]
+ }
+ return
+ }
+ lassign [dict get $::autosetup(inittypes) $type] desc script
+
+ puts "Initialising $type: $desc\n"
+
+ # All initialisations happens in the top level srcdir
+ cd $::autosetup(srcdir)
+
+ uplevel #0 $script
+}
+
+proc autosetup_add_init_type {type desc script} {
+ dict set ::autosetup(inittypes) $type [list $desc $script]
+}
+
+# This is for in creating build-system init scripts
+#
+# If the file doesn't exist, create it containing $contents
+# If the file does exist, only overwrite if --force is specified.
+#
+proc autosetup_check_create {filename contents} {
+ if {[file exists $filename]} {
+ if {!$::autosetup(force)} {
+ puts "I see $filename already exists."
+ return
+ } else {
+ puts "I will overwrite the existing $filename because you used --force."
+ }
+ } else {
+ puts "I don't see $filename, so I will create it."
+ }
+ writefile $filename $contents
+}
+}
+
+# ----- @module install.tcl -----
+
+set modsource(install.tcl) {
+# Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which can install autosetup
+
+# autosetup(installed)=1 means that autosetup is not running from source
+# autosetup(sysinstall)=1 means that autosetup is running from a sysinstall version
+# shared=1 means that we are trying to do a sysinstall. This is only possible from the development source.
+
+proc autosetup_install {dir {shared 0}} {
+ global autosetup
+ if {$shared} {
+ if {$autosetup(installed) || $autosetup(sysinstall)} {
+ user-error "Can only --sysinstall from development sources"
+ }
+ } elseif {$autosetup(installed) && !$autosetup(sysinstall)} {
+ user-error "Can't --install from project install"
+ }
+
+ if {$autosetup(sysinstall)} {
+ # This is the sysinstall version, so install just uses references
+ cd $dir
+
+ puts "[autosetup_version] creating configure to use system-installed autosetup"
+ autosetup_create_configure 1
+ puts "Creating autosetup/README.autosetup"
+ file mkdir autosetup
+ autosetup_install_readme autosetup/README.autosetup 1
+ return
+ }
+
+ if {[catch {
+ if {$shared} {
+ set target $dir/bin/autosetup
+ set installedas $target
+ } else {
+ if {$dir eq "."} {
+ set installedas autosetup
+ } else {
+ set installedas $dir/autosetup
+ }
+ cd $dir
+ file mkdir autosetup
+ set target autosetup/autosetup
+ }
+ set targetdir [file dirname $target]
+ file mkdir $targetdir
+
+ set f [open $target w]
+
+ set publicmodules {}
+
+ # First the main script, but only up until "CUT HERE"
+ set in [open $autosetup(dir)/autosetup]
+ while {[gets $in buf] >= 0} {
+ if {$buf ne "##-- CUT HERE --##"} {
+ puts $f $buf
+ continue
+ }
+
+ # Insert the static modules here
+ # i.e. those which don't contain @synopsis:
+ # All modules are inserted if $shared is set
+ puts $f "set autosetup(installed) 1"
+ puts $f "set autosetup(sysinstall) $shared"
+ foreach file [lsort [glob $autosetup(libdir)/*.{tcl,auto}]] {
+ set modname [file tail $file]
+ set ext [file ext $modname]
+ set buf [readfile $file]
+ if {!$shared} {
+ if {$ext eq ".auto" || [string match "*\n# @synopsis:*" $buf]} {
+ lappend publicmodules $file
+ continue
+ }
+ }
+ dputs "install: importing lib/[file tail $file]"
+ puts $f "# ----- @module $modname -----"
+ puts $f "\nset modsource($modname) \{"
+ puts $f $buf
+ puts $f "\}\n"
+ }
+ if {$shared} {
+ foreach {srcname destname} [list $autosetup(libdir)/README.autosetup-lib README.autosetup \
+ $autosetup(srcdir)/LICENSE LICENSE] {
+ dputs "install: importing $srcname as $destname"
+ puts $f "\nset modsource($destname) \\\n[list [readfile $srcname]\n]\n"
+ }
+ }
+ }
+ close $in
+ close $f
+ catch {exec chmod 755 $target}
+
+ set installfiles {autosetup-config.guess autosetup-config.sub autosetup-test-tclsh}
+ set removefiles {}
+
+ if {!$shared} {
+ autosetup_install_readme $targetdir/README.autosetup 0
+
+ # Install public modules
+ foreach file $publicmodules {
+ set tail [file tail $file]
+ autosetup_install_file $file $targetdir/$tail
+ }
+ lappend installfiles jimsh0.c autosetup-find-tclsh LICENSE
+ lappend removefiles config.guess config.sub test-tclsh find-tclsh
+ } else {
+ lappend installfiles {sys-find-tclsh autosetup-find-tclsh}
+ }
+
+ # Install support files
+ foreach fileinfo $installfiles {
+ if {[llength $fileinfo] == 2} {
+ lassign $fileinfo source dest
+ } else {
+ lassign $fileinfo source
+ set dest $source
+ }
+ autosetup_install_file $autosetup(dir)/$source $targetdir/$dest
+ }
+
+ # Remove obsolete files
+ foreach file $removefiles {
+ if {[file exists $targetdir/$file]} {
+ file delete $targetdir/$file
+ }
+ }
+ } error]} {
+ user-error "Failed to install autosetup: $error"
+ }
+ if {$shared} {
+ set type "system"
+ } else {
+ set type "local"
+ }
+ puts "Installed $type [autosetup_version] to $installedas"
+
+ if {!$shared} {
+ # Now create 'configure' if necessary
+ autosetup_create_configure 0
+ }
+}
+
+proc autosetup_create_configure {shared} {
+ if {[file exists configure]} {
+ if {!$::autosetup(force)} {
+ # Could this be an autosetup configure?
+ if {![string match "*\nWRAPPER=*" [readfile configure]]} {
+ puts "I see configure, but not created by autosetup, so I won't overwrite it."
+ puts "Remove it or use --force to overwrite."
+ return
+ }
+ } else {
+ puts "I will overwrite the existing configure because you used --force."
+ }
+ } else {
+ puts "I don't see configure, so I will create it."
+ }
+ if {$shared} {
+ writefile configure \
+{#!/bin/sh
+WRAPPER="$0"; export WRAPPER; "autosetup" "$@"
+}
+ } else {
+ writefile configure \
+{#!/bin/sh
+dir="`dirname "$0"`/autosetup"
+#@@INITCHECK@@#
+WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"
+}
+ }
+ catch {exec chmod 755 configure}
+}
+
+# Append the contents of $file to filehandle $f
+proc autosetup_install_append {f file} {
+ dputs "install: include $file"
+ set in [open $file]
+ puts $f [read $in]
+ close $in
+}
+
+proc autosetup_install_file {source target} {
+ dputs "install: $source => $target"
+ if {![file exists $source]} {
+ error "Missing installation file '$source'"
+ }
+ writefile $target [readfile $source]\n
+ # If possible, copy the file mode
+ file stat $source stat
+ set mode [format %o [expr {$stat(mode) & 0x1ff}]]
+ catch {exec chmod $mode $target}
+}
+
+proc autosetup_install_readme {target sysinstall} {
+ set readme "README.autosetup created by [autosetup_version]\n\n"
+ if {$sysinstall} {
+ append readme \
+{This is the autosetup directory for a system install of autosetup.
+Loadable modules can be added here.
+}
+ } else {
+ append readme \
+{This is the autosetup directory for a local install of autosetup.
+It contains autosetup, support files and loadable modules.
+}
+}
+
+ append readme {
+*.tcl files in this directory are optional modules which
+can be loaded with the 'use' directive.
+
+*.auto files in this directory are auto-loaded.
+
+For more information, see https://msteveb.github.io/autosetup/
+}
+ dputs "install: autosetup/README.autosetup"
+ writefile $target $readme
+}
+}
+
+# ----- @module markdown-formatting.tcl -----
+
+set modsource(markdown-formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# markdown format (kramdown syntax)
+
+use formatting
+
+proc para {text} {
+ regsub -all "\[ \t\n\]+" [string trim $text] " " text
+ regsub -all {([^a-zA-Z])'([^']*)'} $text {\1**`\2`**} text
+ regsub -all {^'([^']*)'} $text {**`\1`**} text
+ regsub -all {(http[^ \t\n]*)} $text {[\1](\1)} text
+ return $text
+}
+proc title {text} {
+ underline [para $text] =
+ nl
+}
+proc p {text} {
+ puts [para $text]
+ nl
+}
+proc codelines {lines} {
+ puts "~~~~~~~~~~~~"
+ foreach line $lines {
+ puts $line
+ }
+ puts "~~~~~~~~~~~~"
+ nl
+}
+proc code {text} {
+ puts "~~~~~~~~~~~~"
+ foreach line [parse_code_block $text] {
+ puts $line
+ }
+ puts "~~~~~~~~~~~~"
+ nl
+}
+proc nl {} {
+ puts ""
+}
+proc underline {text char} {
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
+ puts $text
+ puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+ underline "[para $text]" -
+ nl
+}
+proc subsection {text} {
+ puts "### `$text`"
+ nl
+}
+proc bullet {text} {
+ puts "* [para $text]"
+}
+proc defn {first args} {
+ puts "^"
+ set defn [string trim [join $args \n]]
+ if {$first ne ""} {
+ puts "**${first}**"
+ puts -nonewline ": "
+ regsub -all "\n\n" $defn "\n: " defn
+ }
+ puts "$defn"
+}
+}
+
+# ----- @module misc.tcl -----
+
+set modsource(misc.tcl) {
+# Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module containing misc procs useful to modules
+# Largely for platform compatibility
+
+set autosetup(istcl) [info exists ::tcl_library]
+set autosetup(iswin) [string equal windows $tcl_platform(platform)]
+
+if {$autosetup(iswin)} {
+ # mingw/windows separates $PATH with semicolons
+ # and doesn't have an executable bit
+ proc split-path {} {
+ split [getenv PATH .] {;}
+ }
+ proc file-isexec {exec} {
+ # Basic test for windows. We ignore .bat
+ if {[file isfile $exec] || [file isfile $exec.exe]} {
+ return 1
+ }
+ return 0
+ }
+} else {
+ # unix separates $PATH with colons and has and executable bit
+ proc split-path {} {
+ split [getenv PATH .] :
+ }
+ # Check for an executable file
+ proc file-isexec {exec} {
+ if {[file executable $exec] && [file isfile $exec]} {
+ return 1
+ }
+ return 0
+ }
+}
+
+# Assume that exec can return stdout and stderr
+proc exec-with-stderr {args} {
+ exec {*}$args 2>@1
+}
+
+if {$autosetup(istcl)} {
+ # Tcl doesn't have the env command
+ proc getenv {name args} {
+ if {[info exists ::env($name)]} {
+ return $::env($name)
+ }
+ if {[llength $args]} {
+ return [lindex $args 0]
+ }
+ return -code error "environment variable \"$name\" does not exist"
+ }
+ proc isatty? {channel} {
+ dict exists [fconfigure $channel] -xchar
+ }
+ # Jim-compatible stacktrace using info frame
+ proc stacktrace {} {
+ set stacktrace {}
+ # 2 to skip the current frame
+ for {set i 2} {$i < [info frame]} {incr i} {
+ set frame [info frame -$i]
+ if {[dict exists $frame file]} {
+ # We don't need proc, so use ""
+ lappend stacktrace "" [dict get $frame file] [dict get $frame line]
+ }
+ }
+ return $stacktrace
+ }
+} else {
+ if {$autosetup(iswin)} {
+ # On Windows, backslash convert all environment variables
+ # (Assume that Tcl does this for us)
+ proc getenv {name args} {
+ string map {\\ /} [env $name {*}$args]
+ }
+ } else {
+ # Jim on unix is simple
+ alias getenv env
+ }
+ proc isatty? {channel} {
+ set tty 0
+ catch {
+ # isatty is a recent addition to Jim Tcl
+ set tty [$channel isatty]
+ }
+ return $tty
+ }
+}
+
+# In case 'file normalize' doesn't exist
+#
+proc file-normalize {path} {
+ if {[catch {file normalize $path} result]} {
+ if {$path eq ""} {
+ return ""
+ }
+ set oldpwd [pwd]
+ if {[file isdir $path]} {
+ cd $path
+ set result [pwd]
+ } else {
+ cd [file dirname $path]
+ set result [file join [pwd] [file tail $path]]
+ }
+ cd $oldpwd
+ }
+ return $result
+}
+
+# If everything is working properly, the only errors which occur
+# should be generated in user code (e.g. auto.def).
+# By default, we only want to show the error location in user code.
+# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
+#
+# This is designed to be called for incorrect usage in auto.def, via autosetup-error
+#
+proc error-location {msg} {
+ if {$::autosetup(debug)} {
+ return -code error $msg
+ }
+ # Search back through the stack trace for the first error in a .def file
+ foreach {p f l} [stacktrace] {
+ if {[string match *.def $f]} {
+ return "[relative-path $f]:$l: Error: $msg"
+ }
+ #puts "Skipping $f:$l"
+ }
+ return $msg
+}
+
+# If everything is working properly, the only errors which occur
+# should be generated in user code (e.g. auto.def).
+# By default, we only want to show the error location in user code.
+# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
+#
+# This is designed to be called for incorrect usage in auto.def, via autosetup-error
+#
+proc error-stacktrace {msg} {
+ if {$::autosetup(debug)} {
+ return -code error $msg
+ }
+ # Search back through the stack trace for the first error in a .def file
+ for {set i 1} {$i < [info level]} {incr i} {
+ if {$::autosetup(istcl)} {
+ array set info [info frame -$i]
+ } else {
+ lassign [info frame -$i] info(caller) info(file) info(line)
+ }
+ if {[string match *.def $info(file)]} {
+ return "[relative-path $info(file)]:$info(line): Error: $msg"
+ }
+ #puts "Skipping $info(file):$info(line)"
+ }
+ return $msg
+}
+
+# Given the return from [catch {...} msg opts], returns an appropriate
+# error message. A nice one for Jim and a less-nice one for Tcl.
+# If 'fulltrace' is set, a full stack trace is provided.
+# Otherwise a simple message is provided.
+#
+# This is designed for developer errors, e.g. in module code or auto.def code
+#
+#
+proc error-dump {msg opts fulltrace} {
+ if {$::autosetup(istcl)} {
+ if {$fulltrace} {
+ return "Error: [dict get $opts -errorinfo]"
+ } else {
+ return "Error: $msg"
+ }
+ } else {
+ lassign $opts(-errorinfo) p f l
+ if {$f ne ""} {
+ set result "$f:$l: Error: "
+ }
+ append result "$msg\n"
+ if {$fulltrace} {
+ append result [stackdump $opts(-errorinfo)]
+ }
+
+ # Remove the trailing newline
+ string trim $result
+ }
+}
+}
+
+# ----- @module text-formatting.tcl -----
+
+set modsource(text-formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+
+use formatting
+
+proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
+ set len 0
+ set space $firstprefix
+
+ foreach word [split $text] {
+ set word [string trim $word]
+ if {$word eq ""} {
+ continue
+ }
+ if {[info exists partial]} {
+ append partial " " $word
+ if {[string first $quote $word] < 0} {
+ # Haven't found end of quoted word
+ continue
+ }
+ # Finished quoted word
+ set word $partial
+ unset partial
+ unset quote
+ } else {
+ set quote [string index $word 0]
+ if {$quote in {' *}} {
+ if {[string first $quote $word 1] < 0} {
+ # Haven't found end of quoted word
+ # Not a whole word.
+ set first [string index $word 0]
+ # Start of quoted word
+ set partial $word
+ continue
+ }
+ }
+ }
+
+ if {$len && [string length $space$word] + $len >= $length} {
+ puts ""
+ set len 0
+ set space $nextprefix
+ }
+ incr len [string length $space$word]
+
+ # Use man-page conventions for highlighting 'quoted' and *quoted*
+ # single words.
+ # Use x^Hx for *bold* and _^Hx for 'underline'.
+ #
+ # less and more will both understand this.
+ # Pipe through 'col -b' to remove them.
+ if {[regexp {^'(.*)'(.*)} $word -> quoted after]} {
+ set quoted [string map {~ " "} $quoted]
+ regsub -all . $quoted "&\b&" quoted
+ set word $quoted$after
+ } elseif {[regexp {^[*](.*)[*](.*)} $word -> quoted after]} {
+ set quoted [string map {~ " "} $quoted]
+ regsub -all . $quoted "_\b&" quoted
+ set word $quoted$after
+ }
+ puts -nonewline $space$word
+ set space " "
+ }
+ if {[info exists partial]} {
+ # Missing end of quote
+ puts -nonewline $space$partial
+ }
+ if {$len} {
+ puts ""
+ }
+}
+proc title {text} {
+ underline [string trim $text] =
+ nl
+}
+proc p {text} {
+ wordwrap $text 80
+ nl
+}
+proc codelines {lines} {
+ foreach line $lines {
+ puts " $line"
+ }
+ nl
+}
+proc nl {} {
+ puts ""
+}
+proc underline {text char} {
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
+ puts $text
+ puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+ underline "[string trim $text]" -
+ nl
+}
+proc subsection {text} {
+ underline "$text" ~
+ nl
+}
+proc bullet {text} {
+ wordwrap $text 76 " * " " "
+}
+proc indent {text} {
+ wordwrap $text 76 " " " "
+}
+proc defn {first args} {
+ if {$first ne ""} {
+ underline " $first" ~
+ }
+ foreach p $args {
+ if {$p ne ""} {
+ indent $p
+ }
+ }
+}
+}
+
+# ----- @module util.tcl -----
+
+set modsource(util.tcl) {
+# Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which contains miscellaneous utility functions
+
+# @section Utilities
+
+# @compare-versions version1 version2
+#
+# Versions are of the form 'a.b.c' (may be any number of numeric components)
+#
+# Compares the two versions and returns:
+## -1 if v1 < v2
+## 0 if v1 == v2
+## 1 if v1 > v2
+#
+# If one version has fewer components than the other, 0 is substituted to the right. e.g.
+## 0.2 < 0.3
+## 0.2.5 > 0.2
+## 1.1 == 1.1.0
+#
+proc compare-versions {v1 v2} {
+ foreach c1 [split $v1 .] c2 [split $v2 .] {
+ if {$c1 eq ""} {
+ set c1 0
+ }
+ if {$c2 eq ""} {
+ set c2 0
+ }
+ if {$c1 < $c2} {
+ return -1
+ }
+ if {$c1 > $c2} {
+ return 1
+ }
+ }
+ return 0
+}
+
+# @suffix suf list
+#
+# Takes a list and returns a new list with '$suf' appended
+# to each element
+#
+## suffix .c {a b c} => {a.c b.c c.c}
+#
+proc suffix {suf list} {
+ set result {}
+ foreach p $list {
+ lappend result $p$suf
+ }
+ return $result
+}
+
+# @prefix pre list
+#
+# Takes a list and returns a new list with '$pre' prepended
+# to each element
+#
+## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
+#
+proc prefix {pre list} {
+ set result {}
+ foreach p $list {
+ lappend result $pre$p
+ }
+ return $result
+}
+
+# @lpop list
+#
+# Removes the last entry from the given list and returns it.
+proc lpop {listname} {
+ upvar $listname list
+ set val [lindex $list end]
+ set list [lrange $list 0 end-1]
+ return $val
+}
+}
+
+# ----- @module wiki-formatting.tcl -----
+
+set modsource(wiki-formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# wiki.tcl.tk format output
+
+use formatting
+
+proc joinlines {text} {
+ set lines {}
+ foreach l [split [string trim $text] \n] {
+ lappend lines [string trim $l]
+ }
+ join $lines
+}
+proc p {text} {
+ puts [joinlines $text]
+ puts ""
+}
+proc title {text} {
+ puts "*** [joinlines $text] ***"
+ puts ""
+}
+proc codelines {lines} {
+ puts "======"
+ foreach line $lines {
+ puts " $line"
+ }
+ puts "======"
+}
+proc code {text} {
+ puts "======"
+ foreach line [parse_code_block $text] {
+ puts " $line"
+ }
+ puts "======"
+}
+proc nl {} {
+}
+proc section {text} {
+ puts "'''$text'''"
+ puts ""
+}
+proc subsection {text} {
+ puts "''$text''"
+ puts ""
+}
+proc bullet {text} {
+ puts " * [joinlines $text]"
+}
+proc indent {text} {
+ puts " : [joinlines $text]"
+}
+proc defn {first args} {
+ if {$first ne ""} {
+ indent '''$first'''
+ }
+
+ foreach p $args {
+ p $p
+ }
+}
+}
+
+
+##################################################################
+#
+# Entry/Exit
+#
+if {$autosetup(debug)} {
+ main $argv
+}
+if {[catch {main $argv} msg opts] == 1} {
+ show-notices
+ autosetup-full-error [error-dump $msg $opts $autosetup(debug)]
+ if {!$autosetup(debug)} {
+ puts stderr "Try: '[file tail $autosetup(exe)] --autosetup-debug' for a full stack trace"
+ }
+ exit 1
+}
diff --git a/contrib/sqlite3/config.guess b/contrib/sqlite3/autosetup/autosetup-config.guess
index 7f76b6228f73..48a684601bd2 100755
--- a/contrib/sqlite3/config.guess
+++ b/contrib/sqlite3/autosetup/autosetup-config.guess
@@ -1,10 +1,10 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2022 Free Software Foundation, Inc.
+# Copyright 1992-2024 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale
-timestamp='2022-01-09'
+timestamp='2024-07-27'
# 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
@@ -47,7 +47,7 @@ me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION]
-Output the configuration name of the system \`$me' is run on.
+Output the configuration name of the system '$me' is run on.
Options:
-h, --help print this help, then exit
@@ -60,13 +60,13 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2022 Free Software Foundation, Inc.
+Copyright 1992-2024 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."
help="
-Try \`$me --help' for more information."
+Try '$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
@@ -102,8 +102,8 @@ GUESS=
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
+# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
+# use 'HOST_CC' if defined, but it is deprecated.
# Portable tmp directory creation inspired by the Autoconf team.
@@ -123,7 +123,7 @@ set_cc_for_build() {
dummy=$tmp/dummy
case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
,,) echo "int x;" > "$dummy.c"
- for driver in cc gcc c89 c99 ; do
+ for driver in cc gcc c17 c99 c89 ; do
if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
CC_FOR_BUILD=$driver
break
@@ -155,6 +155,9 @@ Linux|GNU|GNU/*)
set_cc_for_build
cat <<-EOF > "$dummy.c"
+ #if defined(__ANDROID__)
+ LIBC=android
+ #else
#include <features.h>
#if defined(__UCLIBC__)
LIBC=uclibc
@@ -162,6 +165,8 @@ Linux|GNU|GNU/*)
LIBC=dietlibc
#elif defined(__GLIBC__)
LIBC=gnu
+ #elif defined(__LLVM_LIBC__)
+ LIBC=llvm
#else
#include <stdarg.h>
/* First heuristic to detect musl libc. */
@@ -169,6 +174,7 @@ Linux|GNU|GNU/*)
LIBC=musl
#endif
#endif
+ #endif
EOF
cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
eval "$cc_set_libc"
@@ -459,7 +465,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
UNAME_RELEASE=`uname -v`
;;
esac
- # Japanese Language versions have a version number like `4.1.3-JL'.
+ # Japanese Language versions have a version number like '4.1.3-JL'.
SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
GUESS=sparc-sun-sunos$SUN_REL
;;
@@ -628,7 +634,8 @@ EOF
sed 's/^ //' << EOF > "$dummy.c"
#include <sys/systemcfg.h>
- main()
+ int
+ main ()
{
if (!__power_pc())
exit(1);
@@ -712,7 +719,8 @@ EOF
#include <stdlib.h>
#include <unistd.h>
- int main ()
+ int
+ main ()
{
#if defined(_SC_KERNEL_BITS)
long bits = sysconf(_SC_KERNEL_BITS);
@@ -904,7 +912,7 @@ EOF
fi
;;
*:FreeBSD:*:*)
- UNAME_PROCESSOR=`/usr/bin/uname -p`
+ UNAME_PROCESSOR=`uname -p`
case $UNAME_PROCESSOR in
amd64)
UNAME_PROCESSOR=x86_64 ;;
@@ -966,11 +974,37 @@ EOF
GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
;;
+ x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
+ ;;
+ *:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
+ ;;
*:Minix:*:*)
GUESS=$UNAME_MACHINE-unknown-minix
;;
aarch64:Linux:*:*)
- GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ set_cc_for_build
+ CPU=$UNAME_MACHINE
+ LIBCABI=$LIBC
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ ABI=64
+ sed 's/^ //' << EOF > "$dummy.c"
+ #ifdef __ARM_EABI__
+ #ifdef __ARM_PCS_VFP
+ ABI=eabihf
+ #else
+ ABI=eabi
+ #endif
+ #endif
+EOF
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+ eval "$cc_set_abi"
+ case $ABI in
+ eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
+ esac
+ fi
+ GUESS=$CPU-unknown-linux-$LIBCABI
;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
@@ -1036,7 +1070,16 @@ EOF
k1om:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
- loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
+ kvx:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ kvx:cos:*:*)
+ GUESS=$UNAME_MACHINE-unknown-cos
+ ;;
+ kvx:mbr:*:*)
+ GUESS=$UNAME_MACHINE-unknown-mbr
+ ;;
+ loongarch32:Linux:*:* | loongarch64:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
m32r*:Linux:*:*)
@@ -1151,16 +1194,27 @@ EOF
;;
x86_64:Linux:*:*)
set_cc_for_build
+ CPU=$UNAME_MACHINE
LIBCABI=$LIBC
if test "$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
- LIBCABI=${LIBC}x32
- fi
+ ABI=64
+ sed 's/^ //' << EOF > "$dummy.c"
+ #ifdef __i386__
+ ABI=x86
+ #else
+ #ifdef __ILP32__
+ ABI=x32
+ #endif
+ #endif
+EOF
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+ eval "$cc_set_abi"
+ case $ABI in
+ x86) CPU=i686 ;;
+ x32) LIBCABI=${LIBC}x32 ;;
+ esac
fi
- GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
+ GUESS=$CPU-pc-linux-$LIBCABI
;;
xtensa*:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
@@ -1180,7 +1234,7 @@ EOF
GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
;;
i*86:OS/2:*:*)
- # If we were able to find `uname', then EMX Unix compatibility
+ # If we were able to find 'uname', then EMX Unix compatibility
# is probably installed.
GUESS=$UNAME_MACHINE-pc-os2-emx
;;
@@ -1321,7 +1375,7 @@ EOF
GUESS=ns32k-sni-sysv
fi
;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV>
GUESS=i586-unisys-sysv4
;;
@@ -1367,8 +1421,11 @@ EOF
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
GUESS=i586-pc-haiku
;;
- x86_64:Haiku:*:*)
- GUESS=x86_64-unknown-haiku
+ ppc:Haiku:*:*) # Haiku running on Apple PowerPC
+ GUESS=powerpc-apple-haiku
+ ;;
+ *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat)
+ GUESS=$UNAME_MACHINE-unknown-haiku
;;
SX-4:SUPER-UX:*:*)
GUESS=sx4-nec-superux$UNAME_RELEASE
@@ -1540,6 +1597,9 @@ EOF
*:Unleashed:*:*)
GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
;;
+ *:Ironclad:*:*)
+ GUESS=$UNAME_MACHINE-unknown-ironclad
+ ;;
esac
# Do we have a guess based on uname results?
@@ -1563,6 +1623,7 @@ cat > "$dummy.c" <<EOF
#endif
#endif
#endif
+int
main ()
{
#if defined (sony)
diff --git a/contrib/sqlite3/config.sub b/contrib/sqlite3/autosetup/autosetup-config.sub
index dba16e84c77c..4aaae46f6f74 100755
--- a/contrib/sqlite3/config.sub
+++ b/contrib/sqlite3/autosetup/autosetup-config.sub
@@ -1,10 +1,10 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2022 Free Software Foundation, Inc.
+# Copyright 1992-2024 Free Software Foundation, Inc.
-# shellcheck disable=SC2006,SC2268 # see below for rationale
+# shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale
-timestamp='2022-01-03'
+timestamp='2024-05-27'
# 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
@@ -76,13 +76,13 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2022 Free Software Foundation, Inc.
+Copyright 1992-2024 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."
help="
-Try \`$me --help' for more information."
+Try '$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
@@ -120,7 +120,6 @@ case $# in
esac
# Split fields of configuration type
-# shellcheck disable=SC2162
saved_IFS=$IFS
IFS="-" read field1 field2 field3 field4 <<EOF
$1
@@ -130,7 +129,7 @@ IFS=$saved_IFS
# Separate into logical components for further validation
case $1 in
*-*-*-*-*)
- echo Invalid configuration \`"$1"\': more than four components >&2
+ echo "Invalid configuration '$1': more than four components" >&2
exit 1
;;
*-*-*-*)
@@ -142,10 +141,21 @@ case $1 in
# parts
maybe_os=$field2-$field3
case $maybe_os in
- nto-qnx* | linux-* | uclinux-uclibc* \
- | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
- | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
- | storm-chaos* | os2-emx* | rtmk-nova*)
+ cloudabi*-eabi* \
+ | kfreebsd*-gnu* \
+ | knetbsd*-gnu* \
+ | kopensolaris*-gnu* \
+ | linux-* \
+ | managarm-* \
+ | netbsd*-eabi* \
+ | netbsd*-gnu* \
+ | nto-qnx* \
+ | os2-emx* \
+ | rtmk-nova* \
+ | storm-chaos* \
+ | uclinux-gnu* \
+ | uclinux-uclibc* \
+ | windows-* )
basic_machine=$field1
basic_os=$maybe_os
;;
@@ -160,8 +170,12 @@ case $1 in
esac
;;
*-*)
- # A lone config we happen to match not fitting any pattern
case $field1-$field2 in
+ # Shorthands that happen to contain a single dash
+ convex-c[12] | convex-c3[248])
+ basic_machine=$field2-convex
+ basic_os=
+ ;;
decstation-3100)
basic_machine=mips-dec
basic_os=
@@ -169,28 +183,88 @@ case $1 in
*-*)
# Second component is usually, but not always the OS
case $field2 in
- # Prevent following clause from handling this valid os
+ # Do not treat sunos as a manufacturer
sun*os*)
basic_machine=$field1
basic_os=$field2
;;
- zephyr*)
- basic_machine=$field1-unknown
- basic_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)
+ 3100* \
+ | 32* \
+ | 3300* \
+ | 3600* \
+ | 7300* \
+ | acorn \
+ | altos* \
+ | apollo \
+ | apple \
+ | atari \
+ | att* \
+ | axis \
+ | be \
+ | bull \
+ | cbm \
+ | ccur \
+ | cisco \
+ | commodore \
+ | convergent* \
+ | convex* \
+ | cray \
+ | crds \
+ | dec* \
+ | delta* \
+ | dg \
+ | digital \
+ | dolphin \
+ | encore* \
+ | gould \
+ | harris \
+ | highlevel \
+ | hitachi* \
+ | hp \
+ | ibm* \
+ | intergraph \
+ | isi* \
+ | knuth \
+ | masscomp \
+ | microblaze* \
+ | mips* \
+ | motorola* \
+ | ncr* \
+ | news \
+ | next \
+ | ns \
+ | oki \
+ | omron* \
+ | pc533* \
+ | rebel \
+ | rom68k \
+ | rombug \
+ | semi \
+ | sequent* \
+ | siemens \
+ | sgi* \
+ | siemens \
+ | sim \
+ | sni \
+ | sony* \
+ | stratus \
+ | sun \
+ | sun[234]* \
+ | tektronix \
+ | tti* \
+ | ultra \
+ | unicom* \
+ | wec \
+ | winbond \
+ | wrs)
basic_machine=$field1-$field2
basic_os=
;;
+ zephyr*)
+ basic_machine=$field1-unknown
+ basic_os=$field2
+ ;;
*)
basic_machine=$field1
basic_os=$field2
@@ -271,26 +345,6 @@ case $1 in
basic_machine=arm-unknown
basic_os=cegcc
;;
- convex-c1)
- basic_machine=c1-convex
- basic_os=bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- basic_os=bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- basic_os=bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- basic_os=bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- basic_os=bsd
- ;;
cray)
basic_machine=j90-cray
basic_os=unicos
@@ -713,15 +767,26 @@ case $basic_machine in
vendor=dec
basic_os=tops20
;;
- delta | 3300 | motorola-3300 | motorola-delta \
- | 3300-motorola | delta-motorola)
+ delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300)
cpu=m68k
vendor=motorola
;;
- dpx2*)
+ # This used to be dpx2*, but that gets the RS6000-based
+ # DPX/20 and the x86-based DPX/2-100 wrong. See
+ # https://oldskool.silicium.org/stations/bull_dpx20.htm
+ # https://www.feb-patrimoine.com/english/bull_dpx2.htm
+ # https://www.feb-patrimoine.com/english/unix_and_bull.htm
+ dpx2 | dpx2[23]00 | dpx2[23]xx)
cpu=m68k
vendor=bull
- basic_os=sysv3
+ ;;
+ dpx2100 | dpx21xx)
+ cpu=i386
+ vendor=bull
+ ;;
+ dpx20)
+ cpu=rs6000
+ vendor=bull
;;
encore | umax | mmax)
cpu=ns32k
@@ -836,18 +901,6 @@ case $basic_machine in
next | m*-next)
cpu=m68k
vendor=next
- case $basic_os in
- openstep*)
- ;;
- nextstep*)
- ;;
- ns2*)
- basic_os=nextstep2
- ;;
- *)
- basic_os=nextstep3
- ;;
- esac
;;
np1)
cpu=np1
@@ -936,14 +989,13 @@ case $basic_machine in
;;
*-*)
- # shellcheck disable=SC2162
saved_IFS=$IFS
IFS="-" read cpu vendor <<EOF
$basic_machine
EOF
IFS=$saved_IFS
;;
- # We use `pc' rather than `unknown'
+ # 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)
@@ -971,15 +1023,19 @@ 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.
+ # 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.
+ c[12]-convex | c[12]-unknown | c3[248]-convex | c3[248]-unknown)
+ vendor=convex
+ basic_os=${basic_os:-bsd}
+ ;;
craynv-unknown)
vendor=cray
basic_os=${basic_os:-unicosmp}
;;
c90-unknown | c90-cray)
vendor=cray
- basic_os=${Basic_os:-unicos}
+ basic_os=${basic_os:-unicos}
;;
fx80-unknown)
vendor=alliant
@@ -1025,11 +1081,29 @@ case $cpu-$vendor in
vendor=alt
basic_os=${basic_os:-linux-gnueabihf}
;;
- dpx20-unknown | dpx20-bull)
- cpu=rs6000
- vendor=bull
+
+ # Normalized CPU+vendor pairs that imply an OS, if not otherwise specified
+ m68k-isi)
+ basic_os=${basic_os:-sysv}
+ ;;
+ m68k-sony)
+ basic_os=${basic_os:-newsos}
+ ;;
+ m68k-tektronix)
+ basic_os=${basic_os:-bsd}
+ ;;
+ m88k-harris)
+ basic_os=${basic_os:-sysv3}
+ ;;
+ i386-bull | m68k-bull)
+ basic_os=${basic_os:-sysv3}
+ ;;
+ rs6000-bull)
basic_os=${basic_os:-bosx}
;;
+ mips-sni)
+ basic_os=${basic_os:-sysv4}
+ ;;
# Here we normalize CPU types irrespective of the vendor
amd64-*)
@@ -1037,7 +1111,7 @@ case $cpu-$vendor in
;;
blackfin-*)
cpu=bfin
- basic_os=linux
+ basic_os=${basic_os:-linux}
;;
c54x-*)
cpu=tic54x
@@ -1060,7 +1134,7 @@ case $cpu-$vendor in
;;
m68knommu-*)
cpu=m68k
- basic_os=linux
+ basic_os=${basic_os:-linux}
;;
m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
cpu=s12z
@@ -1070,12 +1144,12 @@ case $cpu-$vendor in
;;
parisc-*)
cpu=hppa
- basic_os=linux
+ basic_os=${basic_os:-linux}
;;
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
cpu=i586
;;
- pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
cpu=i686
;;
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
@@ -1084,9 +1158,6 @@ case $cpu-$vendor in
pentium4-*)
cpu=i786
;;
- pc98-*)
- cpu=i386
- ;;
ppc-* | ppcbe-*)
cpu=powerpc
;;
@@ -1120,9 +1191,6 @@ case $cpu-$vendor in
tx39el-*)
cpu=mipstx39el
;;
- x64-*)
- cpu=x86_64
- ;;
xscale-* | xscalee[bl]-*)
cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
;;
@@ -1178,114 +1246,231 @@ case $cpu-$vendor in
# Recognize the canonical CPU types that are allowed with any
# company name.
case $cpu in
- 1750a | 580 \
+ 1750a \
+ | 580 \
+ | [cjt]90 \
| a29k \
- | aarch64 | aarch64_be \
+ | aarch64 \
+ | aarch64_be \
+ | aarch64c \
| abacus \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
- | alphapca5[67] | alpha64pca5[67] \
+ | alpha \
+ | alpha64 \
+ | alpha64ev56 \
+ | alpha64ev6[78] \
+ | alpha64ev[4-8] \
+ | alpha64pca5[67] \
+ | alphaev56 \
+ | alphaev6[78] \
+ | alphaev[4-8] \
+ | alphapca5[67] \
| am33_2.0 \
| amdgcn \
- | arc | arceb | arc32 | arc64 \
- | arm | arm[lb]e | arme[lb] | armv* \
- | avr | avr32 \
+ | arc \
+ | arc32 \
+ | arc64 \
+ | arceb \
+ | arm \
+ | arm64e \
+ | arm64ec \
+ | arm[lb]e \
+ | arme[lb] \
+ | armv* \
| asmjs \
+ | avr \
+ | avr32 \
| ba \
- | be32 | be64 \
- | bfin | bpf | bs2000 \
- | c[123]* | c30 | [cjt]90 | c4x \
- | c8051 | clipper | craynv | csky | cydra \
- | d10v | d30v | dlx | dsp16xx \
- | e2k | elxsi | epiphany \
- | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
- | h8300 | h8500 \
- | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | be32 \
+ | be64 \
+ | bfin \
+ | bpf \
+ | bs2000 \
+ | c30 \
+ | c4x \
+ | c8051 \
+ | c[123]* \
+ | clipper \
+ | craynv \
+ | csky \
+ | cydra \
+ | d10v \
+ | d30v \
+ | dlx \
+ | dsp16xx \
+ | e2k \
+ | elxsi \
+ | epiphany \
+ | f30[01] \
+ | f700 \
+ | fido \
+ | fr30 \
+ | frv \
+ | ft32 \
+ | fx80 \
+ | h8300 \
+ | h8500 \
| hexagon \
- | i370 | i*86 | i860 | i960 | ia16 | ia64 \
- | ip2k | iq2000 \
+ | hppa \
+ | hppa1.[01] \
+ | hppa2.0 \
+ | hppa2.0[nw] \
+ | hppa64 \
+ | i*86 \
+ | i370 \
+ | i860 \
+ | i960 \
+ | ia16 \
+ | ia64 \
+ | ip2k \
+ | iq2000 \
+ | javascript \
| k1om \
- | le32 | le64 \
+ | kvx \
+ | le32 \
+ | le64 \
| lm32 \
- | loongarch32 | loongarch64 | loongarchx32 \
- | 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 \
- | mipsisa32r3 | mipsisa32r3el \
- | mipsisa32r5 | mipsisa32r5el \
- | mipsisa32r6 | mipsisa32r6el \
- | mipsisa64 | mipsisa64el \
- | mipsisa64r2 | mipsisa64r2el \
- | mipsisa64r3 | mipsisa64r3el \
- | mipsisa64r5 | mipsisa64r5el \
- | mipsisa64r6 | mipsisa64r6el \
- | mipsisa64sb1 | mipsisa64sb1el \
- | mipsisa64sr71k | mipsisa64sr71kel \
- | mipsr5900 | mipsr5900el \
- | mipstx39 | mipstx39el \
+ | loongarch32 \
+ | loongarch64 \
+ | m32c \
+ | m32r \
+ | m32rle \
+ | m5200 \
+ | m68000 \
+ | m680[012346]0 \
+ | m6811 \
+ | m6812 \
+ | m68360 \
+ | m683?2 \
+ | m68hc11 \
+ | m68hc12 \
+ | m68hcs12x \
+ | m68k \
+ | m88110 \
+ | m88k \
+ | maxq \
+ | mb \
+ | mcore \
+ | mep \
+ | metag \
+ | microblaze \
+ | microblazeel \
+ | mips* \
| mmix \
- | mn10200 | mn10300 \
+ | mn10200 \
+ | mn10300 \
| moxie \
- | mt \
| msp430 \
- | nds32 | nds32le | nds32be \
+ | mt \
+ | nanomips* \
+ | nds32 \
+ | nds32be \
+ | nds32le \
| nfp \
- | nios | nios2 | nios2eb | nios2el \
- | none | np1 | ns16k | ns32k | nvptx \
+ | nios \
+ | nios2 \
+ | nios2eb \
+ | nios2el \
+ | none \
+ | np1 \
+ | ns16k \
+ | ns32k \
+ | nvptx \
| open8 \
| or1k* \
| or32 \
| orion \
+ | pdp10 \
+ | pdp11 \
| picochip \
- | pdp10 | pdp11 | pj | pjl | pn | power \
- | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+ | pj \
+ | pjl \
+ | pn \
+ | power \
+ | powerpc \
+ | powerpc64 \
+ | powerpc64le \
+ | powerpcle \
+ | powerpcspe \
| pru \
| pyramid \
- | riscv | riscv32 | riscv32be | riscv64 | riscv64be \
- | rl78 | romp | rs6000 | rx \
- | s390 | s390x \
+ | riscv \
+ | riscv32 \
+ | riscv32be \
+ | riscv64 \
+ | riscv64be \
+ | rl78 \
+ | romp \
+ | rs6000 \
+ | rx \
+ | s390 \
+ | s390x \
| 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 \
+ | sh \
+ | sh64 \
+ | sh64le \
+ | sh[12345][lb]e \
+ | sh[1234] \
+ | sh[1234]e[lb] \
+ | sh[23]e \
+ | sh[23]ele \
+ | sh[24]a \
+ | sh[24]ae[lb] \
+ | sh[lb]e \
+ | she[lb] \
+ | shl \
+ | sparc \
+ | sparc64 \
+ | sparc64b \
+ | sparc64v \
+ | sparc86x \
+ | sparclet \
| sparclite \
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+ | sparcv8 \
+ | sparcv9 \
+ | sparcv9b \
+ | sparcv9v \
| spu \
+ | sv1 \
+ | sx* \
| tahoe \
| thumbv7* \
- | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+ | tic30 \
+ | tic4x \
+ | tic54x \
+ | tic55x \
+ | tic6x \
+ | tic80 \
| tron \
| ubicom32 \
- | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+ | v70 \
+ | v810 \
+ | v850 \
+ | v850e \
+ | v850e1 \
+ | v850e2 \
+ | v850e2v3 \
+ | v850es \
| vax \
+ | vc4 \
| visium \
| w65 \
- | wasm32 | wasm64 \
+ | wasm32 \
+ | wasm64 \
| we32k \
- | x86 | x86_64 | xc16x | xgate | xps100 \
- | xstormy16 | xtensa* \
+ | x86 \
+ | x86_64 \
+ | xc16x \
+ | xgate \
+ | xps100 \
+ | xstormy16 \
+ | xtensa* \
| ymp \
- | z8k | z80)
+ | z80 \
+ | z8k)
;;
*)
- echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+ echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2
exit 1
;;
esac
@@ -1306,11 +1491,12 @@ esac
# Decode manufacturer-specific aliases for certain operating systems.
-if test x$basic_os != x
+if test x"$basic_os" != x
then
# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
# set os.
+obj=
case $basic_os in
gnu/linux*)
kernel=linux
@@ -1325,7 +1511,6 @@ case $basic_os in
os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
;;
*-*)
- # shellcheck disable=SC2162
saved_IFS=$IFS
IFS="-" read kernel os <<EOF
$basic_os
@@ -1341,6 +1526,10 @@ EOF
kernel=linux
os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
;;
+ managarm*)
+ kernel=managarm
+ os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
+ ;;
*)
kernel=
os=$basic_os
@@ -1368,6 +1557,23 @@ case $os in
unixware*)
os=sysv4.2uw
;;
+ # The marketing names for NeXT's operating systems were
+ # NeXTSTEP, NeXTSTEP 2, OpenSTEP 3, OpenSTEP 4. 'openstep' is
+ # mapped to 'openstep3', but 'openstep1' and 'openstep2' are
+ # mapped to 'nextstep' and 'nextstep2', consistent with the
+ # treatment of SunOS/Solaris.
+ ns | ns1 | nextstep | nextstep1 | openstep1)
+ os=nextstep
+ ;;
+ ns2 | nextstep2 | openstep2)
+ os=nextstep2
+ ;;
+ ns3 | nextstep3 | openstep | openstep3)
+ os=openstep3
+ ;;
+ ns4 | nextstep4 | openstep4)
+ os=openstep4
+ ;;
# es1800 is here to avoid being matched by es* (a different OS)
es1800*)
os=ose
@@ -1438,6 +1644,7 @@ case $os in
;;
utek*)
os=bsd
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|tektronix|'`
;;
dynix*)
os=bsd
@@ -1454,21 +1661,25 @@ case $os in
386bsd)
os=bsd
;;
- ctix* | uts*)
+ ctix*)
os=sysv
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|convergent|'`
;;
- nova*)
- os=rtmk-nova
+ uts*)
+ os=sysv
;;
- ns2)
- os=nextstep2
+ nova*)
+ kernel=rtmk
+ os=nova
;;
# Preserve the version number of sinix5.
sinix5.*)
os=`echo "$os" | sed -e 's|sinix|sysv|'`
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
;;
sinix*)
os=sysv4
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
;;
tpf*)
os=tpf
@@ -1506,10 +1717,16 @@ case $os in
os=eabi
;;
*)
- os=elf
+ os=
+ obj=elf
;;
esac
;;
+ aout* | coff* | elf* | pe*)
+ # These are machine code file formats, not OSes
+ obj=$os
+ os=
+ ;;
*)
# No normalization, but not necessarily accepted, that comes below.
;;
@@ -1528,12 +1745,15 @@ else
# system, and we'll never get to this point.
kernel=
+obj=
case $cpu-$vendor in
score-*)
- os=elf
+ os=
+ obj=elf
;;
spu-*)
- os=elf
+ os=
+ obj=elf
;;
*-acorn)
os=riscix1.2
@@ -1543,28 +1763,35 @@ case $cpu-$vendor in
os=gnu
;;
arm*-semi)
- os=aout
+ os=
+ obj=aout
;;
c4x-* | tic4x-*)
- os=coff
+ os=
+ obj=coff
;;
c8051-*)
- os=elf
+ os=
+ obj=elf
;;
clipper-intergraph)
os=clix
;;
hexagon-*)
- os=elf
+ os=
+ obj=elf
;;
tic54x-*)
- os=coff
+ os=
+ obj=coff
;;
tic55x-*)
- os=coff
+ os=
+ obj=coff
;;
tic6x-*)
- os=coff
+ os=
+ obj=coff
;;
# This must come before the *-dec entry.
pdp10-*)
@@ -1586,28 +1813,43 @@ case $cpu-$vendor in
os=sunos3
;;
m68*-cisco)
- os=aout
+ os=
+ obj=aout
;;
mep-*)
- os=elf
+ os=
+ obj=elf
+ ;;
+ # The -sgi and -siemens entries must be before the mips- entry
+ # or we get the wrong os.
+ *-sgi)
+ os=irix
+ ;;
+ *-siemens)
+ os=sysv4
;;
mips*-cisco)
- os=elf
+ os=
+ obj=elf
;;
- mips*-*)
- os=elf
+ mips*-*|nanomips*-*)
+ os=
+ obj=elf
;;
or32-*)
- os=coff
+ os=
+ obj=coff
;;
- *-tti) # must be before sparc entry or we get the wrong os.
+ # This must be before the sparc-* entry or we get the wrong os.
+ *-tti)
os=sysv3
;;
sparc-* | *-sun)
os=sunos4.1.1
;;
pru-*)
- os=elf
+ os=
+ obj=elf
;;
*-be)
os=beos
@@ -1631,7 +1873,7 @@ case $cpu-$vendor in
os=hpux
;;
*-hitachi)
- os=hiux
+ os=hiuxwe2
;;
i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
os=sysv
@@ -1675,12 +1917,6 @@ case $cpu-$vendor in
*-encore)
os=bsd
;;
- *-sgi)
- os=irix
- ;;
- *-siemens)
- os=sysv4
- ;;
*-masscomp)
os=rtu
;;
@@ -1688,10 +1924,12 @@ case $cpu-$vendor in
os=uxpv
;;
*-rom68k)
- os=coff
+ os=
+ obj=coff
;;
*-*bug)
- os=coff
+ os=
+ obj=coff
;;
*-apple)
os=macos
@@ -1709,10 +1947,11 @@ esac
fi
-# Now, validate our (potentially fixed-up) OS.
+# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
+
case $os in
# Sometimes we do "kernel-libc", so those need to count as OSes.
- musl* | newlib* | relibc* | uclibc*)
+ llvm* | musl* | newlib* | relibc* | uclibc*)
;;
# Likewise for "kernel-abi"
eabi* | gnueabi*)
@@ -1720,83 +1959,308 @@ case $os in
# VxWorks passes extra cpu info in the 4th filed.
simlinux | simwindows | spe)
;;
+ # See `case $cpu-$os` validation below
+ ghcjs)
+ ;;
# Now accept the basic system types.
- # The portable systems comes first.
# Each alternative MUST end in a * to match a version number.
- gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
- | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
- | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
- | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
- | hiux* | abug | nacl* | netware* | windows* \
- | os9* | macos* | osx* | ios* \
- | mpw* | magic* | mmixware* | mon960* | lnews* \
- | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
- | aos* | aros* | cloudabi* | sortix* | twizzler* \
- | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
- | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
- | mirbsd* | netbsd* | dicos* | openedition* | ose* \
- | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
- | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
- | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
- | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
- | udi* | lites* | ieee* | go32* | aux* | hcos* \
- | chorusrdb* | cegcc* | glidix* | serenity* \
- | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
- | midipix* | mingw32* | mingw64* | mint* \
- | uxpv* | beos* | mpeix* | udk* | moxiebox* \
- | interix* | uwin* | mks* | rhapsody* | darwin* \
- | openstep* | oskit* | conix* | pw32* | nonstopux* \
- | storm-chaos* | tops10* | tenex* | tops20* | its* \
- | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
- | scout* | superux* | sysv* | rtmk* | tpf* | 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* | genode* | zvmoe* | qnx* | emx* | zephyr* \
- | fiwix* )
+ abug \
+ | aix* \
+ | amdhsa* \
+ | amigados* \
+ | amigaos* \
+ | android* \
+ | aof* \
+ | aos* \
+ | aros* \
+ | atheos* \
+ | auroraux* \
+ | aux* \
+ | beos* \
+ | bitrig* \
+ | bme* \
+ | bosx* \
+ | bsd* \
+ | cegcc* \
+ | chorusos* \
+ | chorusrdb* \
+ | clix* \
+ | cloudabi* \
+ | cnk* \
+ | conix* \
+ | cos* \
+ | cxux* \
+ | cygwin* \
+ | darwin* \
+ | dgux* \
+ | dicos* \
+ | dnix* \
+ | domain* \
+ | dragonfly* \
+ | drops* \
+ | ebmon* \
+ | ecoff* \
+ | ekkobsd* \
+ | emscripten* \
+ | emx* \
+ | es* \
+ | fiwix* \
+ | freebsd* \
+ | fuchsia* \
+ | genix* \
+ | genode* \
+ | glidix* \
+ | gnu* \
+ | go32* \
+ | haiku* \
+ | hcos* \
+ | hiux* \
+ | hms* \
+ | hpux* \
+ | ieee* \
+ | interix* \
+ | ios* \
+ | iris* \
+ | irix* \
+ | ironclad* \
+ | isc* \
+ | its* \
+ | l4re* \
+ | libertybsd* \
+ | lites* \
+ | lnews* \
+ | luna* \
+ | lynxos* \
+ | mach* \
+ | macos* \
+ | magic* \
+ | mbr* \
+ | midipix* \
+ | midnightbsd* \
+ | mingw32* \
+ | mingw64* \
+ | minix* \
+ | mint* \
+ | mirbsd* \
+ | mks* \
+ | mlibc* \
+ | mmixware* \
+ | mon960* \
+ | morphos* \
+ | moss* \
+ | moxiebox* \
+ | mpeix* \
+ | mpw* \
+ | msdos* \
+ | msys* \
+ | mvs* \
+ | nacl* \
+ | netbsd* \
+ | netware* \
+ | newsos* \
+ | nextstep* \
+ | nindy* \
+ | nonstopux* \
+ | nova* \
+ | nsk* \
+ | nucleus* \
+ | nx6 \
+ | nx7 \
+ | oabi* \
+ | ohos* \
+ | onefs* \
+ | openbsd* \
+ | openedition* \
+ | openstep* \
+ | os108* \
+ | os2* \
+ | os400* \
+ | os68k* \
+ | os9* \
+ | ose* \
+ | osf* \
+ | oskit* \
+ | osx* \
+ | palmos* \
+ | phoenix* \
+ | plan9* \
+ | powermax* \
+ | powerunix* \
+ | proelf* \
+ | psos* \
+ | psp* \
+ | ptx* \
+ | pw32* \
+ | qnx* \
+ | rdos* \
+ | redox* \
+ | rhapsody* \
+ | riscix* \
+ | riscos* \
+ | rtems* \
+ | rtmk* \
+ | rtu* \
+ | scout* \
+ | secbsd* \
+ | sei* \
+ | serenity* \
+ | sim* \
+ | skyos* \
+ | solaris* \
+ | solidbsd* \
+ | sortix* \
+ | storm-chaos* \
+ | sunos \
+ | sunos[34]* \
+ | superux* \
+ | syllable* \
+ | sym* \
+ | sysv* \
+ | tenex* \
+ | tirtos* \
+ | toppers* \
+ | tops10* \
+ | tops20* \
+ | tpf* \
+ | tvos* \
+ | twizzler* \
+ | uclinux* \
+ | udi* \
+ | udk* \
+ | ultrix* \
+ | unicos* \
+ | uniplus* \
+ | unleashed* \
+ | unos* \
+ | uwin* \
+ | uxpv* \
+ | v88r* \
+ |*vms* \
+ | vos* \
+ | vsta* \
+ | vxsim* \
+ | vxworks* \
+ | wasi* \
+ | watchos* \
+ | wince* \
+ | windiss* \
+ | windows* \
+ | winnt* \
+ | xenix* \
+ | xray* \
+ | zephyr* \
+ | zvmoe* )
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
# Don't forget version if it is 3.2v4 or newer.
;;
+ # This refers to builds using the UEFI calling convention
+ # (which depends on the architecture) and PE file format.
+ # Note that this is both a different calling convention and
+ # different file format than that of GNU-EFI
+ # (x86_64-w64-mingw32).
+ uefi)
+ ;;
none)
;;
+ kernel* | msvc* )
+ # Restricted further below
+ ;;
+ '')
+ if test x"$obj" = x
+ then
+ echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
+ fi
+ ;;
+ *)
+ echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
+ exit 1
+ ;;
+esac
+
+case $obj in
+ aout* | coff* | elf* | pe*)
+ ;;
+ '')
+ # empty is fine
+ ;;
*)
- echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
+ echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we handle the constraint that a (synthetic) cpu and os are
+# valid only in combination with each other and nowhere else.
+case $cpu-$os in
+ # The "javascript-unknown-ghcjs" triple is used by GHC; we
+ # accept it here in order to tolerate that, but reject any
+ # variations.
+ javascript-ghcjs)
+ ;;
+ javascript-* | *-ghcjs)
+ echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
exit 1
;;
esac
# As a final step for OS-related things, validate the OS-kernel combination
# (given a valid OS), if there is a kernel.
-case $kernel-$os in
- linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
- | linux-musl* | linux-relibc* | linux-uclibc* )
+case $kernel-$os-$obj in
+ linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \
+ | linux-mlibc*- | linux-musl*- | linux-newlib*- \
+ | linux-relibc*- | linux-uclibc*- | linux-ohos*- )
+ ;;
+ uclinux-uclibc*- | uclinux-gnu*- )
+ ;;
+ managarm-mlibc*- | managarm-kernel*- )
;;
- uclinux-uclibc* )
+ windows*-msvc*-)
;;
- -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* )
+ -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \
+ | -uclibc*- )
# These are just libc implementations, not actual OSes, and thus
# require a kernel.
- echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
+ echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
exit 1
;;
- kfreebsd*-gnu* | kopensolaris*-gnu*)
+ -kernel*- )
+ echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
+ exit 1
;;
- vxworks-simlinux | vxworks-simwindows | vxworks-spe)
+ *-kernel*- )
+ echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
+ exit 1
;;
- nto-qnx*)
+ *-msvc*- )
+ echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
+ exit 1
;;
- os2-emx)
+ kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-)
+ ;;
+ vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
+ ;;
+ nto-qnx*-)
;;
- *-eabi* | *-gnueabi*)
+ os2-emx-)
;;
- -*)
+ rtmk-nova-)
+ ;;
+ *-eabi*- | *-gnueabi*-)
+ ;;
+ none--*)
+ # None (no kernel, i.e. freestanding / bare metal),
+ # can be paired with an machine code file format
+ ;;
+ -*-)
# Blank kernel with real OS is always fine.
;;
- *-*)
- echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+ --*)
+ # Blank kernel and OS with real machine code file format is always fine.
+ ;;
+ *-*-*)
+ echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
exit 1
;;
esac
@@ -1809,7 +2273,7 @@ case $vendor in
*-riscix*)
vendor=acorn
;;
- *-sunos*)
+ *-sunos* | *-solaris*)
vendor=sun
;;
*-cnk* | *-aix*)
@@ -1879,7 +2343,7 @@ case $vendor in
;;
esac
-echo "$cpu-$vendor-${kernel:+$kernel-}$os"
+echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
exit
# Local variables:
diff --git a/contrib/sqlite3/autosetup/autosetup-find-tclsh b/contrib/sqlite3/autosetup/autosetup-find-tclsh
new file mode 100755
index 000000000000..9f6d6e9402f4
--- /dev/null
+++ b/contrib/sqlite3/autosetup/autosetup-find-tclsh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Looks for a suitable tclsh or jimsh in the PATH
+# If not found, builds a bootstrap jimsh in current dir from source
+# Prefer $autosetup_tclsh if is set in the environment (unless ./jimsh0 works)
+# If an argument is given, use that as the test instead of autosetup-test-tclsh
+d="`dirname "$0"`"
+for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; do
+ { $tclsh "$d/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
+done
+echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
+for cc in ${CC_FOR_BUILD:-cc} gcc; do
+ { $cc -o jimsh0 "$d/jimsh0.c"; } 2>/dev/null >/dev/null || continue
+ ./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
+done
+echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
+echo false
diff --git a/contrib/sqlite3/autosetup/autosetup-test-tclsh b/contrib/sqlite3/autosetup/autosetup-test-tclsh
new file mode 100644
index 000000000000..75126d2444b6
--- /dev/null
+++ b/contrib/sqlite3/autosetup/autosetup-test-tclsh
@@ -0,0 +1,20 @@
+# A small Tcl script to verify that the chosen
+# interpreter works. Sometimes we might e.g. pick up
+# an interpreter for a different arch.
+# Outputs the full path to the interpreter
+
+if {[catch {info version} version] == 0} {
+ # This is Jim Tcl
+ if {$version >= 0.72} {
+ # Ensure that regexp works
+ regexp (a.*?) a
+ puts [info nameofexecutable]
+ exit 0
+ }
+} elseif {[catch {info tclversion} version] == 0} {
+ if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
+ puts [info nameofexecutable]
+ exit 0
+ }
+}
+exit 1
diff --git a/contrib/sqlite3/autosetup/cc-db.tcl b/contrib/sqlite3/autosetup/cc-db.tcl
new file mode 100644
index 000000000000..12f1aed2c91b
--- /dev/null
+++ b/contrib/sqlite3/autosetup/cc-db.tcl
@@ -0,0 +1,15 @@
+# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc-db' module provides a knowledge-base of system idiosyncrasies.
+# In general, this module can always be included.
+
+use cc
+
+options {}
+
+# openbsd needs sys/types.h to detect some system headers
+cc-include-needs sys/socket.h sys/types.h
+cc-include-needs netinet/in.h sys/types.h
diff --git a/contrib/sqlite3/autosetup/cc-lib.tcl b/contrib/sqlite3/autosetup/cc-lib.tcl
new file mode 100644
index 000000000000..01a0fb387760
--- /dev/null
+++ b/contrib/sqlite3/autosetup/cc-lib.tcl
@@ -0,0 +1,187 @@
+# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# Provides a library of common tests on top of the 'cc' module.
+
+use cc
+
+# @cc-check-lfs
+#
+# The equivalent of the 'AC_SYS_LARGEFILE' macro.
+#
+# defines 'HAVE_LFS' if LFS is available,
+# and defines '_FILE_OFFSET_BITS=64' if necessary
+#
+# Returns 1 if 'LFS' is available or 0 otherwise
+#
+proc cc-check-lfs {} {
+ cc-check-includes sys/types.h
+ msg-checking "Checking if -D_FILE_OFFSET_BITS=64 is needed..."
+ set lfs 1
+ if {[msg-quiet cc-with {-includes sys/types.h} {cc-check-sizeof off_t}] == 8} {
+ msg-result no
+ } elseif {[msg-quiet cc-with {-includes sys/types.h -cflags -D_FILE_OFFSET_BITS=64} {cc-check-sizeof off_t}] == 8} {
+ define _FILE_OFFSET_BITS 64
+ msg-result yes
+ } else {
+ set lfs 0
+ msg-result none
+ }
+ define-feature lfs $lfs
+ return $lfs
+}
+
+# @cc-check-endian
+#
+# The equivalent of the 'AC_C_BIGENDIAN' macro.
+#
+# defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
+# or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
+#
+# Returns 1 if determined, or 0 if not.
+#
+proc cc-check-endian {} {
+ cc-check-includes sys/types.h sys/param.h
+ set rc 0
+ msg-checking "Checking endian..."
+ cc-with {-includes {sys/types.h sys/param.h}} {
+ if {[cctest -code {
+ #if !defined(BIG_ENDIAN) || !defined(BYTE_ORDER)
+ #error unknown
+ #elif BYTE_ORDER != BIG_ENDIAN
+ #error little
+ #endif
+ }]} {
+ define-feature big-endian
+ msg-result "big"
+ set rc 1
+ } elseif {[cctest -code {
+ #if !defined(LITTLE_ENDIAN) || !defined(BYTE_ORDER)
+ #error unknown
+ #elif BYTE_ORDER != LITTLE_ENDIAN
+ #error big
+ #endif
+ }]} {
+ define-feature little-endian
+ msg-result "little"
+ set rc 1
+ } else {
+ msg-result "unknown"
+ }
+ }
+ return $rc
+}
+
+# @cc-check-flags flag ?...?
+#
+# Checks whether the given C/C++ compiler flags can be used. Defines feature
+# names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and
+# appends working flags to '-cflags' and 'AS_CFLAGS' or 'AS_CXXFLAGS'.
+proc cc-check-flags {args} {
+ set result 1
+ array set opts [cc-get-settings]
+ switch -exact -- $opts(-lang) {
+ c++ {
+ set lang C++
+ set prefix CXXFLAG
+ }
+ c {
+ set lang C
+ set prefix CFLAG
+ }
+ default {
+ autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)"
+ }
+ }
+ foreach flag $args {
+ msg-checking "Checking whether the $lang compiler accepts $flag..."
+ if {[cctest -cflags $flag]} {
+ msg-result yes
+ define-feature $prefix$flag
+ cc-with [list -cflags [list $flag]]
+ define-append AS_${prefix}S $flag
+ } else {
+ msg-result no
+ set result 0
+ }
+ }
+ return $result
+}
+
+# @cc-check-standards ver ?...?
+#
+# Checks whether the C/C++ compiler accepts one of the specified '-std=$ver'
+# options, and appends the first working one to '-cflags' and 'AS_CFLAGS' or
+# 'AS_CXXFLAGS'.
+proc cc-check-standards {args} {
+ array set opts [cc-get-settings]
+ foreach std $args {
+ if {[cc-check-flags -std=$std]} {
+ return $std
+ }
+ }
+ return ""
+}
+
+# Checks whether $keyword is usable as alignof
+proc cctest_alignof {keyword} {
+ msg-checking "Checking for $keyword..."
+ if {[cctest -code "int x = ${keyword}(char), y = ${keyword}('x');"]} then {
+ msg-result ok
+ define-feature $keyword
+ } else {
+ msg-result "not found"
+ }
+}
+
+# @cc-check-c11
+#
+# Checks for several C11/C++11 extensions and their alternatives. Currently
+# checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'.
+proc cc-check-c11 {} {
+ msg-checking "Checking for _Static_assert..."
+ if {[cctest -code {
+ _Static_assert(1, "static assertions are available");
+ }]} then {
+ msg-result ok
+ define-feature _Static_assert
+ } else {
+ msg-result "not found"
+ }
+
+ cctest_alignof _Alignof
+ cctest_alignof __alignof__
+ cctest_alignof __alignof
+}
+
+# @cc-check-alloca
+#
+# The equivalent of the 'AC_FUNC_ALLOCA' macro.
+#
+# Checks for the existence of 'alloca'
+# defines 'HAVE_ALLOCA' and returns 1 if it exists.
+proc cc-check-alloca {} {
+ cc-check-some-feature alloca {
+ cctest -includes alloca.h -code { alloca (2 * sizeof (int)); }
+ }
+}
+
+# @cc-signal-return-type
+#
+# The equivalent of the 'AC_TYPE_SIGNAL' macro.
+#
+# defines 'RETSIGTYPE' to 'int' or 'void'.
+proc cc-signal-return-type {} {
+ msg-checking "Checking return type of signal handlers..."
+ cc-with {-includes {sys/types.h signal.h}} {
+ if {[cctest -code {return *(signal (0, 0)) (0) == 1;}]} {
+ set type int
+ } else {
+ set type void
+ }
+ define RETSIGTYPE $type
+ msg-result $type
+ }
+}
diff --git a/contrib/sqlite3/autosetup/cc-shared.tcl b/contrib/sqlite3/autosetup/cc-shared.tcl
new file mode 100644
index 000000000000..cbe568018e96
--- /dev/null
+++ b/contrib/sqlite3/autosetup/cc-shared.tcl
@@ -0,0 +1,113 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc-shared' module provides support for shared libraries and shared objects.
+# It defines the following variables:
+#
+## SH_CFLAGS Flags to use compiling sources destined for a shared library
+## SH_LDFLAGS Flags to use linking (creating) a shared library
+## SH_SOPREFIX Prefix to use to set the soname when creating a shared library
+## SH_SOFULLPATH Set to 1 if the shared library soname should include the full install path
+## SH_SOEXT Extension for shared libs
+## SH_SOEXTVER Format for versioned shared libs - %s = version
+## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object
+## SHOBJ_LDFLAGS Flags to use linking a shared object, undefined symbols allowed
+## SHOBJ_LDFLAGS_R - as above, but all symbols must be resolved
+## SH_LINKRPATH Format for setting the rpath when linking an executable, %s = path
+## SH_LINKFLAGS Flags to use linking an executable which will load shared objects
+## LD_LIBRARY_PATH Environment variable which specifies path to shared libraries
+## STRIPLIBFLAGS Arguments to strip a dynamic library
+
+options {}
+
+# Defaults: gcc on unix
+define SHOBJ_CFLAGS -fPIC
+define SHOBJ_LDFLAGS -shared
+define SH_CFLAGS -fPIC
+define SH_LDFLAGS -shared
+define SH_LINKFLAGS -rdynamic
+define SH_LINKRPATH "-Wl,-rpath -Wl,%s"
+define SH_SOEXT .so
+define SH_SOEXTVER .so.%s
+define SH_SOPREFIX -Wl,-soname,
+define LD_LIBRARY_PATH LD_LIBRARY_PATH
+define STRIPLIBFLAGS --strip-unneeded
+
+# Note: This is a helpful reference for identifying the toolchain
+# http://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers
+
+switch -glob -- [get-define host] {
+ *-*-darwin* {
+ define SHOBJ_CFLAGS "-dynamic -fno-common"
+ define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"
+ define SHOBJ_LDFLAGS_R -bundle
+ define SH_CFLAGS -dynamic
+ define SH_LDFLAGS -dynamiclib
+ define SH_LINKFLAGS ""
+ define SH_SOEXT .dylib
+ define SH_SOEXTVER .%s.dylib
+ define SH_SOPREFIX -Wl,-install_name,
+ define SH_SOFULLPATH
+ define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
+ define STRIPLIBFLAGS -x
+ }
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ define SHOBJ_CFLAGS ""
+ define SHOBJ_LDFLAGS -shared
+ define SH_CFLAGS ""
+ define SH_LDFLAGS -shared
+ define SH_LINKRPATH ""
+ define SH_LINKFLAGS ""
+ define SH_SOEXT .dll
+ define SH_SOEXTVER .dll
+ define SH_SOPREFIX ""
+ define LD_LIBRARY_PATH PATH
+ }
+ sparc* {
+ if {[msg-quiet cc-check-decls __SUNPRO_C]} {
+ msg-result "Found sun stdio compiler"
+ # sun stdio compiler
+ # XXX: These haven't been fully tested.
+ define SHOBJ_CFLAGS -KPIC
+ define SHOBJ_LDFLAGS "-G"
+ define SH_CFLAGS -KPIC
+ define SH_LINKFLAGS -Wl,-export-dynamic
+ define SH_SOPREFIX -Wl,-h,
+ }
+ }
+ *-*-solaris* {
+ if {[msg-quiet cc-check-decls __SUNPRO_C]} {
+ msg-result "Found sun stdio compiler"
+ # sun stdio compiler
+ # XXX: These haven't been fully tested.
+ define SHOBJ_CFLAGS -KPIC
+ define SHOBJ_LDFLAGS "-G"
+ define SH_CFLAGS -KPIC
+ define SH_LINKFLAGS -Wl,-export-dynamic
+ define SH_SOPREFIX -Wl,-h,
+ }
+ }
+ *-*-hpux {
+ # XXX: These haven't been tested
+ define SHOBJ_CFLAGS "+O3 +z"
+ define SHOBJ_LDFLAGS -b
+ define SH_CFLAGS +z
+ define SH_LINKFLAGS -Wl,+s
+ define LD_LIBRARY_PATH SHLIB_PATH
+ }
+ *-*-haiku {
+ define SHOBJ_CFLAGS ""
+ define SHOBJ_LDFLAGS -shared
+ define SH_CFLAGS ""
+ define SH_LDFLAGS -shared
+ define SH_LINKFLAGS ""
+ define SH_SOPREFIX ""
+ define LD_LIBRARY_PATH LIBRARY_PATH
+ }
+}
+
+if {![is-defined SHOBJ_LDFLAGS_R]} {
+ define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
+}
diff --git a/contrib/sqlite3/autosetup/cc.tcl b/contrib/sqlite3/autosetup/cc.tcl
new file mode 100644
index 000000000000..05c1b1cf4068
--- /dev/null
+++ b/contrib/sqlite3/autosetup/cc.tcl
@@ -0,0 +1,758 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc' module supports checking various 'features' of the C or C++
+# compiler/linker environment. Common commands are 'cc-check-includes',
+# 'cc-check-types', 'cc-check-functions', 'cc-with' and 'make-config-header'
+#
+# The following environment variables are used if set:
+#
+## CC - C compiler
+## CXX - C++ compiler
+## CPP - C preprocessor
+## CCACHE - Set to "none" to disable automatic use of ccache
+## CPPFLAGS - Additional C preprocessor compiler flags (C and C++), before CFLAGS, CXXFLAGS
+## CFLAGS - Additional C compiler flags
+## CXXFLAGS - Additional C++ compiler flags
+## LDFLAGS - Additional compiler flags during linking
+## LINKFLAGS - ?How is this different from LDFLAGS?
+## LIBS - Additional libraries to use (for all tests)
+## CROSS - Tool prefix for cross compilation
+#
+# The following variables are defined from the corresponding
+# environment variables if set.
+#
+## CC_FOR_BUILD
+## LD
+
+use system
+
+options {}
+
+# Checks for the existence of the given function by linking
+#
+proc cctest_function {function} {
+ cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
+}
+
+# Checks for the existence of the given type by compiling
+proc cctest_type {type} {
+ cctest -code "$type _x;"
+}
+
+# Checks for the existence of the given type/structure member.
+# e.g. "struct stat.st_mtime"
+proc cctest_member {struct_member} {
+ # split at the first dot
+ regexp {^([^.]+)[.](.*)$} $struct_member -> struct member
+ cctest -code "static $struct _s; return sizeof(_s.$member);"
+}
+
+# Checks for the existence of the given define by compiling
+#
+proc cctest_define {name} {
+ cctest -code "#ifndef $name\n#error not defined\n#endif"
+}
+
+# Checks for the existence of the given name either as
+# a macro (#define) or an rvalue (such as an enum)
+#
+proc cctest_decl {name} {
+ cctest -code "#ifndef $name\n(void)$name;\n#endif"
+}
+
+# @cc-check-sizeof type ...
+#
+# Checks the size of the given types (between 1 and 32, inclusive).
+# Defines a variable with the size determined, or 'unknown' otherwise.
+# e.g. for type 'long long', defines 'SIZEOF_LONG_LONG'.
+# Returns the size of the last type.
+#
+proc cc-check-sizeof {args} {
+ foreach type $args {
+ msg-checking "Checking for sizeof $type..."
+ set size unknown
+ # Try the most common sizes first
+ foreach i {4 8 1 2 16 32} {
+ if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
+ set size $i
+ break
+ }
+ }
+ msg-result $size
+ set define [feature-define-name $type SIZEOF_]
+ define $define $size
+ }
+ # Return the last result
+ get-define $define
+}
+
+# Checks for each feature in $list by using the given script.
+#
+# When the script is evaluated, $each is set to the feature
+# being checked, and $extra is set to any additional cctest args.
+#
+# Returns 1 if all features were found, or 0 otherwise.
+proc cc-check-some-feature {list script} {
+ set ret 1
+ foreach each $list {
+ if {![check-feature $each $script]} {
+ set ret 0
+ }
+ }
+ return $ret
+}
+
+# @cc-check-includes includes ...
+#
+# Checks that the given include files can be used.
+proc cc-check-includes {args} {
+ cc-check-some-feature $args {
+ set with {}
+ if {[dict exists $::autosetup(cc-include-deps) $each]} {
+ set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
+ msg-quiet cc-check-includes {*}$deps
+ foreach i $deps {
+ if {[have-feature $i]} {
+ lappend with $i
+ }
+ }
+ }
+ if {[llength $with]} {
+ cc-with [list -includes $with] {
+ cctest -includes $each
+ }
+ } else {
+ cctest -includes $each
+ }
+ }
+}
+
+# @cc-include-needs include required ...
+#
+# Ensures that when checking for '$include', a check is first
+# made for each '$required' file, and if found, it is included with '#include'.
+proc cc-include-needs {file args} {
+ foreach depfile $args {
+ dict set ::autosetup(cc-include-deps) $file $depfile 1
+ }
+}
+
+# @cc-check-types type ...
+#
+# Checks that the types exist.
+proc cc-check-types {args} {
+ cc-check-some-feature $args {
+ cctest_type $each
+ }
+}
+
+# @cc-check-defines define ...
+#
+# Checks that the given preprocessor symbols are defined.
+proc cc-check-defines {args} {
+ cc-check-some-feature $args {
+ cctest_define $each
+ }
+}
+
+# @cc-check-decls name ...
+#
+# Checks that each given name is either a preprocessor symbol or rvalue
+# such as an enum. Note that the define used is 'HAVE_DECL_xxx'
+# rather than 'HAVE_xxx'.
+proc cc-check-decls {args} {
+ set ret 1
+ foreach name $args {
+ msg-checking "Checking for $name..."
+ set r [cctest_decl $name]
+ define-feature "decl $name" $r
+ if {$r} {
+ msg-result "ok"
+ } else {
+ msg-result "not found"
+ set ret 0
+ }
+ }
+ return $ret
+}
+
+# @cc-check-functions function ...
+#
+# Checks that the given functions exist (can be linked).
+proc cc-check-functions {args} {
+ cc-check-some-feature $args {
+ cctest_function $each
+ }
+}
+
+# @cc-check-members type.member ...
+#
+# Checks that the given type/structure members exist.
+# A structure member is of the form 'struct stat.st_mtime'.
+proc cc-check-members {args} {
+ cc-check-some-feature $args {
+ cctest_member $each
+ }
+}
+
+# @cc-check-function-in-lib function libs ?otherlibs?
+#
+# Checks that the given function can be found in one of the libs.
+#
+# First checks for no library required, then checks each of the libraries
+# in turn.
+#
+# If the function is found, the feature is defined and 'lib_$function' is defined
+# to '-l$lib' where the function was found, or "" if no library required.
+# In addition, '-l$lib' is prepended to the 'LIBS' define.
+#
+# If additional libraries may be needed for linking, they should be specified
+# with '$extralibs' as '-lotherlib1 -lotherlib2'.
+# These libraries are not automatically added to 'LIBS'.
+#
+# Returns 1 if found or 0 if not.
+#
+proc cc-check-function-in-lib {function libs {otherlibs {}}} {
+ msg-checking "Checking libs for $function..."
+ set found 0
+ cc-with [list -libs $otherlibs] {
+ if {[cctest_function $function]} {
+ msg-result "none needed"
+ define lib_$function ""
+ incr found
+ } else {
+ foreach lib $libs {
+ cc-with [list -libs -l$lib] {
+ if {[cctest_function $function]} {
+ msg-result -l$lib
+ define lib_$function -l$lib
+ # prepend to LIBS
+ define LIBS "-l$lib [get-define LIBS]"
+ incr found
+ break
+ }
+ }
+ }
+ }
+ }
+ define-feature $function $found
+ if {!$found} {
+ msg-result "no"
+ }
+ return $found
+}
+
+# @cc-check-tools tool ...
+#
+# Checks for existence of the given compiler tools, taking
+# into account any cross compilation prefix.
+#
+# For example, when checking for 'ar', first 'AR' is checked on the command
+# line and then in the environment. If not found, '${host}-ar' or
+# simply 'ar' is assumed depending upon whether cross compiling.
+# The path is searched for this executable, and if found 'AR' is defined
+# to the executable name.
+# Note that even when cross compiling, the simple 'ar' is used as a fallback,
+# but a warning is generated. This is necessary for some toolchains.
+#
+# It is an error if the executable is not found.
+#
+proc cc-check-tools {args} {
+ foreach tool $args {
+ set TOOL [string toupper $tool]
+ set exe [get-env $TOOL [get-define cross]$tool]
+ if {[find-executable $exe]} {
+ define $TOOL $exe
+ continue
+ }
+ if {[find-executable $tool]} {
+ msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect"
+ define $TOOL $tool
+ continue
+ }
+ user-error "Failed to find $exe"
+ }
+}
+
+# @cc-check-progs prog ...
+#
+# Checks for existence of the given executables on the path.
+#
+# For example, when checking for 'grep', the path is searched for
+# the executable, 'grep', and if found 'GREP' is defined as 'grep'.
+#
+# If the executable is not found, the variable is defined as 'false'.
+# Returns 1 if all programs were found, or 0 otherwise.
+#
+proc cc-check-progs {args} {
+ set failed 0
+ foreach prog $args {
+ set PROG [string toupper $prog]
+ msg-checking "Checking for $prog..."
+ if {![find-executable $prog]} {
+ msg-result no
+ define $PROG false
+ incr failed
+ } else {
+ msg-result ok
+ define $PROG $prog
+ }
+ }
+ expr {!$failed}
+}
+
+# @cc-path-progs prog ...
+#
+# Like cc-check-progs, but sets the define to the full path rather
+# than just the program name.
+#
+proc cc-path-progs {args} {
+ set failed 0
+ foreach prog $args {
+ set PROG [string toupper $prog]
+ msg-checking "Checking for $prog..."
+ set path [find-executable-path $prog]
+ if {$path eq ""} {
+ msg-result no
+ define $PROG false
+ incr failed
+ } else {
+ msg-result $path
+ define $PROG $path
+ }
+ }
+ expr {!$failed}
+}
+
+# Adds the given settings to $::autosetup(ccsettings) and
+# returns the old settings.
+#
+proc cc-add-settings {settings} {
+ if {[llength $settings] % 2} {
+ autosetup-error "settings list is missing a value: $settings"
+ }
+
+ set prev [cc-get-settings]
+ # workaround a bug in some versions of jimsh by forcing
+ # conversion of $prev to a list
+ llength $prev
+
+ array set new $prev
+
+ foreach {name value} $settings {
+ switch -exact -- $name {
+ -cflags - -includes {
+ # These are given as lists
+ lappend new($name) {*}[list-non-empty $value]
+ }
+ -declare {
+ lappend new($name) $value
+ }
+ -libs {
+ # Note that new libraries are added before previous libraries
+ set new($name) [list {*}[list-non-empty $value] {*}$new($name)]
+ }
+ -link - -lang - -nooutput {
+ set new($name) $value
+ }
+ -source - -sourcefile - -code {
+ # XXX: These probably are only valid directly from cctest
+ set new($name) $value
+ }
+ default {
+ autosetup-error "unknown cctest setting: $name"
+ }
+ }
+ }
+
+ cc-store-settings [array get new]
+
+ return $prev
+}
+
+proc cc-store-settings {new} {
+ set ::autosetup(ccsettings) $new
+}
+
+proc cc-get-settings {} {
+ return $::autosetup(ccsettings)
+}
+
+# Similar to cc-add-settings, but each given setting
+# simply replaces the existing value.
+#
+# Returns the previous settings
+proc cc-update-settings {args} {
+ set prev [cc-get-settings]
+ cc-store-settings [dict merge $prev $args]
+ return $prev
+}
+
+# @cc-with settings ?{ script }?
+#
+# Sets the given 'cctest' settings and then runs the tests in '$script'.
+# Note that settings such as '-lang' replace the current setting, while
+# those such as '-includes' are appended to the existing setting.
+#
+# If no script is given, the settings become the default for the remainder
+# of the 'auto.def' file.
+#
+## cc-with {-lang c++} {
+## # This will check with the C++ compiler
+## cc-check-types bool
+## cc-with {-includes signal.h} {
+## # This will check with the C++ compiler, signal.h and any existing includes.
+## ...
+## }
+## # back to just the C++ compiler
+## }
+#
+# The '-libs' setting is special in that newer values are added *before* earlier ones.
+#
+## cc-with {-libs {-lc -lm}} {
+## cc-with {-libs -ldl} {
+## cctest -libs -lsocket ...
+## # libs will be in this order: -lsocket -ldl -lc -lm
+## }
+## }
+#
+# If you wish to invoke something like cc-check-flags but not have -cflags updated,
+# use the following idiom:
+#
+## cc-with {} {
+## cc-check-flags ...
+## }
+proc cc-with {settings args} {
+ if {[llength $args] == 0} {
+ cc-add-settings $settings
+ } elseif {[llength $args] > 1} {
+ autosetup-error "usage: cc-with settings ?script?"
+ } else {
+ set save [cc-add-settings $settings]
+ set rc [catch {uplevel 1 [lindex $args 0]} result info]
+ cc-store-settings $save
+ if {$rc != 0} {
+ return -code [dict get $info -code] $result
+ }
+ return $result
+ }
+}
+
+# @cctest ?settings?
+#
+# Low level C/C++ compiler checker. Compiles and or links a small C program
+# according to the arguments and returns 1 if OK, or 0 if not.
+#
+# Supported settings are:
+#
+## -cflags cflags A list of flags to pass to the compiler
+## -includes list A list of includes, e.g. {stdlib.h stdio.h}
+## -declare code Code to declare before main()
+## -link 1 Don't just compile, link too
+## -lang c|c++ Use the C (default) or C++ compiler
+## -libs liblist List of libraries to link, e.g. {-ldl -lm}
+## -code code Code to compile in the body of main()
+## -source code Compile a complete program. Ignore -includes, -declare and -code
+## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
+## -nooutput 1 Treat any compiler output (e.g. a warning) as an error
+#
+# Unless '-source' or '-sourcefile' is specified, the C program looks like:
+#
+## #include <firstinclude> /* same for remaining includes in the list */
+## declare-code /* any code in -declare, verbatim */
+## int main(void) {
+## code /* any code in -code, verbatim */
+## return 0;
+## }
+#
+# And the command line looks like:
+#
+## CC -cflags CFLAGS CPPFLAGS conftest.c -o conftest.o
+## CXX -cflags CXXFLAGS CPPFLAGS conftest.cpp -o conftest.o
+#
+# And if linking:
+#
+## CC LDFLAGS -cflags CFLAGS conftest.c -o conftest -libs LIBS
+## CXX LDFLAGS -cflags CXXFLAGS conftest.c -o conftest -libs LIBS
+#
+# Any failures are recorded in 'config.log'
+#
+proc cctest {args} {
+ set tmp conftest__
+
+ # Easiest way to merge in the settings
+ cc-with $args {
+ array set opts [cc-get-settings]
+ }
+
+ if {[info exists opts(-sourcefile)]} {
+ set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
+ }
+ if {[info exists opts(-source)]} {
+ set lines $opts(-source)
+ } else {
+ foreach i $opts(-includes) {
+ if {$opts(-code) ne "" && ![feature-checked $i]} {
+ # Compiling real code with an unchecked header file
+ # Quickly (and silently) check for it now
+
+ # Remove all -includes from settings before checking
+ set saveopts [cc-update-settings -includes {}]
+ msg-quiet cc-check-includes $i
+ cc-store-settings $saveopts
+ }
+ if {$opts(-code) eq "" || [have-feature $i]} {
+ lappend source "#include <$i>"
+ }
+ }
+ lappend source {*}$opts(-declare)
+ lappend source "int main(void) {"
+ lappend source $opts(-code)
+ lappend source "return 0;"
+ lappend source "}"
+
+ set lines [join $source \n]
+ }
+
+ # Build the command line
+ set cmdline {}
+ lappend cmdline {*}[get-define CCACHE]
+ switch -exact -- $opts(-lang) {
+ c++ {
+ set src conftest__.cpp
+ lappend cmdline {*}[get-define CXX]
+ set cflags [get-define CXXFLAGS]
+ }
+ c {
+ set src conftest__.c
+ lappend cmdline {*}[get-define CC]
+ set cflags [get-define CFLAGS]
+ }
+ default {
+ autosetup-error "cctest called with unknown language: $opts(-lang)"
+ }
+ }
+
+ if {$opts(-link)} {
+ lappend cmdline {*}[get-define LDFLAGS]
+ } else {
+ lappend cflags {*}[get-define CPPFLAGS]
+ set tmp conftest__.o
+ lappend cmdline -c
+ }
+ lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""] {*}$cflags
+ lappend cmdline $src -o $tmp
+ if {$opts(-link)} {
+ lappend cmdline {*}$opts(-libs) {*}[get-define LIBS]
+ }
+
+ # At this point we have the complete command line and the
+ # complete source to be compiled. Get the result from cache if
+ # we can
+ if {[info exists ::cc_cache($cmdline,$lines)]} {
+ msg-checking "(cached) "
+ set ok $::cc_cache($cmdline,$lines)
+ if {$::autosetup(debug)} {
+ configlog "From cache (ok=$ok): [join $cmdline]"
+ configlog "============"
+ configlog $lines
+ configlog "============"
+ }
+ return $ok
+ }
+
+ writefile $src $lines\n
+
+ set ok 1
+ set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
+ if {$err || ($opts(-nooutput) && [string length $result])} {
+ configlog "Failed: [join $cmdline]"
+ configlog $result
+ configlog "============"
+ configlog "The failed code was:"
+ configlog $lines
+ configlog "============"
+ set ok 0
+ } elseif {$::autosetup(debug)} {
+ configlog "Compiled OK: [join $cmdline]"
+ configlog "============"
+ configlog $lines
+ configlog "============"
+ }
+ file delete $src
+ file delete $tmp
+
+ # cache it
+ set ::cc_cache($cmdline,$lines) $ok
+
+ return $ok
+}
+
+# @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
+#
+# Deprecated - see 'make-config-header'
+proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
+ user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
+ make-config-header $file -auto $autopatterns -bare $barepatterns
+}
+
+# @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
+#
+# Examines all defined variables which match the given patterns
+# and writes an include file, '$file', which defines each of these.
+# Variables which match '-auto' are output as follows:
+# - defines which have the value '0' are ignored.
+# - defines which have integer values are defined as the integer value.
+# - any other value is defined as a string, e.g. '"value"'
+# Variables which match '-bare' are defined as-is.
+# Variables which match '-str' are defined as a string, e.g. '"value"'
+# Variables which match '-none' are omitted.
+#
+# Note that order is important. The first pattern that matches is selected.
+# Default behaviour is:
+#
+## -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
+#
+# If the file would be unchanged, it is not written.
+proc make-config-header {file args} {
+ set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
+ file mkdir [file dirname $file]
+ set lines {}
+ lappend lines "#ifndef $guard"
+ lappend lines "#define $guard"
+
+ # Add some defaults
+ lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
+
+ foreach n [lsort [dict keys [all-defines]]] {
+ set value [get-define $n]
+ set type [calc-define-output-type $n $args]
+ switch -exact -- $type {
+ -bare {
+ # Just output the value unchanged
+ }
+ -none {
+ continue
+ }
+ -str {
+ set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
+ }
+ -auto {
+ # Automatically determine the type
+ if {$value eq "0"} {
+ lappend lines "/* #undef $n */"
+ continue
+ }
+ if {![string is integer -strict $value]} {
+ set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
+ }
+ }
+ "" {
+ continue
+ }
+ default {
+ autosetup-error "Unknown type in make-config-header: $type"
+ }
+ }
+ lappend lines "#define $n $value"
+ }
+ lappend lines "#endif"
+ set buf [join $lines \n]
+ write-if-changed $file $buf {
+ msg-result "Created $file"
+ }
+}
+
+proc calc-define-output-type {name spec} {
+ foreach {type patterns} $spec {
+ foreach pattern $patterns {
+ if {[string match $pattern $name]} {
+ return $type
+ }
+ }
+ }
+ return ""
+}
+
+proc cc-init {} {
+ global autosetup
+
+ # Initialise some values from the environment or commandline or default settings
+ foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS CFLAGS} {
+ lassign $i var default
+ define $var [get-env $var $default]
+ }
+
+ if {[env-is-set CC]} {
+ # Set by the user, so don't try anything else
+ set try [list [get-env CC ""]]
+ } else {
+ # Try some reasonable options
+ set try [list [get-define cross]cc [get-define cross]gcc]
+ }
+ define CC [find-an-executable {*}$try]
+ if {[get-define CC] eq ""} {
+ user-error "Could not find a C compiler. Tried: [join $try ", "]"
+ }
+
+ define CPP [get-env CPP "[get-define CC] -E"]
+
+ # XXX: Could avoid looking for a C++ compiler until requested
+ # If CXX isn't found, it is set to the empty string.
+ if {[env-is-set CXX]} {
+ define CXX [find-an-executable -required [get-env CXX ""]]
+ } else {
+ define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++]
+ }
+
+ # CXXFLAGS default to CFLAGS if not specified
+ define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
+
+ # May need a CC_FOR_BUILD, so look for one
+ define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
+
+ # These start empty and never come from the user or environment
+ define AS_CFLAGS ""
+ define AS_CPPFLAGS ""
+ define AS_CXXFLAGS ""
+
+ define CCACHE [find-an-executable [get-env CCACHE ccache]]
+
+ # If any of these are set in the environment, propagate them to the AUTOREMAKE commandline
+ foreach i {CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAGS LINKFLAGS CC_FOR_BUILD LD} {
+ if {[env-is-set $i]} {
+ # Note: If the variable is set on the command line, get-env will return that value
+ # so the command line will continue to override the environment
+ define-append-argv AUTOREMAKE $i=[get-env $i ""]
+ }
+ }
+
+ # Initial cctest settings
+ cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
+ set autosetup(cc-include-deps) {}
+
+ msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS] [get-define CPPFLAGS]"
+ if {[get-define CXX] ne "false"} {
+ msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS] [get-define CPPFLAGS]"
+ }
+ msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
+
+ # On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
+ # but some compilers may not support it, so test here.
+ switch -glob -- [get-define host] {
+ *-*-darwin* {
+ if {[cctest -cflags {-g0}]} {
+ define cc-default-debug -g0
+ }
+ }
+ }
+
+ if {![cc-check-includes stdlib.h]} {
+ user-error "Compiler does not work. See config.log"
+ }
+}
+
+cc-init
diff --git a/contrib/sqlite3/autosetup/find_tclconfig.tcl b/contrib/sqlite3/autosetup/find_tclconfig.tcl
new file mode 100644
index 000000000000..c3d3df8ec3ab
--- /dev/null
+++ b/contrib/sqlite3/autosetup/find_tclconfig.tcl
@@ -0,0 +1,24 @@
+#
+# Run this TCL script to find and print the pathname for the tclConfig.sh
+# file. Used by ../configure
+#
+if {[catch {
+ set libdir [tcl::pkgconfig get libdir,install]
+}]} {
+ puts stderr "tclsh too old: does not support tcl::pkgconfig"
+ exit 1
+}
+if {![file exists $libdir]} {
+ puts stderr "tclsh reported library directory \"$libdir\" does not exist"
+ exit 1
+}
+if {![file exists $libdir/tclConfig.sh]} {
+ set n1 $libdir/tcl$::tcl_version
+ if {[file exists $n1/tclConfig.sh]} {
+ set libdir $n1
+ } else {
+ puts stderr "cannot find tclConfig.sh in either $libdir or $n1"
+ exit 1
+ }
+}
+puts $libdir
diff --git a/contrib/sqlite3/autosetup/jimsh0.c b/contrib/sqlite3/autosetup/jimsh0.c
new file mode 100644
index 000000000000..b035524c9681
--- /dev/null
+++ b/contrib/sqlite3/autosetup/jimsh0.c
@@ -0,0 +1,24519 @@
+/* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
+#define JIM_COMPAT
+#define JIM_ANSIC
+#define JIM_REGEXP
+#define HAVE_NO_AUTOCONF
+#define JIM_TINY
+#define _JIMAUTOCONF_H
+#define TCL_LIBRARY "."
+#define jim_ext_bootstrap
+#define jim_ext_aio
+#define jim_ext_readdir
+#define jim_ext_regexp
+#define jim_ext_file
+#define jim_ext_glob
+#define jim_ext_exec
+#define jim_ext_clock
+#define jim_ext_array
+#define jim_ext_stdlib
+#define jim_ext_tclcompat
+#if defined(_MSC_VER)
+#define TCL_PLATFORM_OS "windows"
+#define TCL_PLATFORM_PLATFORM "windows"
+#define TCL_PLATFORM_PATH_SEPARATOR ";"
+#define HAVE_MKDIR_ONE_ARG
+#define HAVE_SYSTEM
+#elif defined(__MINGW32__)
+#define TCL_PLATFORM_OS "mingw"
+#define TCL_PLATFORM_PLATFORM "windows"
+#define TCL_PLATFORM_PATH_SEPARATOR ";"
+#define HAVE_MKDIR_ONE_ARG
+#define HAVE_SYSTEM
+#define HAVE_SYS_TIME_H
+#define HAVE_DIRENT_H
+#define HAVE_UNISTD_H
+#define HAVE_UMASK
+#include <sys/stat.h>
+#ifndef S_IRWXG
+#define S_IRWXG 0
+#endif
+#ifndef S_IRWXO
+#define S_IRWXO 0
+#endif
+#else
+#define TCL_PLATFORM_OS "unknown"
+#define TCL_PLATFORM_PLATFORM "unix"
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#ifdef _MINIX
+#define vfork fork
+#define _POSIX_SOURCE
+#else
+#define _GNU_SOURCE
+#endif
+#define HAVE_FORK
+#define HAVE_WAITPID
+#define HAVE_ISATTY
+#define HAVE_MKSTEMP
+#define HAVE_LINK
+#define HAVE_SYS_TIME_H
+#define HAVE_DIRENT_H
+#define HAVE_UNISTD_H
+#define HAVE_UMASK
+#define HAVE_PIPE
+#define _FILE_OFFSET_BITS 64
+#endif
+#define JIM_VERSION 84
+#ifndef JIM_WIN32COMPAT_H
+#define JIM_WIN32COMPAT_H
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if defined(_WIN32) || defined(WIN32)
+
+#define HAVE_DLOPEN
+void *dlopen(const char *path, int mode);
+int dlclose(void *handle);
+void *dlsym(void *handle, const char *symbol);
+char *dlerror(void);
+
+
+#if defined(__MINGW32__)
+ #define JIM_SPRINTF_DOUBLE_NEEDS_FIX
+#endif
+
+#ifdef _MSC_VER
+
+
+#if _MSC_VER >= 1000
+ #pragma warning(disable:4146)
+#endif
+
+#include <limits.h>
+#define jim_wide _int64
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG
+#endif
+#ifndef LLONG_MAX
+ #define LLONG_MAX 9223372036854775807I64
+#endif
+#ifndef LLONG_MIN
+ #define LLONG_MIN (-LLONG_MAX - 1I64)
+#endif
+#define JIM_WIDE_MIN LLONG_MIN
+#define JIM_WIDE_MAX LLONG_MAX
+#define JIM_WIDE_MODIFIER "I64d"
+#define strcasecmp _stricmp
+#define strtoull _strtoui64
+
+#include <io.h>
+
+#include <winsock.h>
+int gettimeofday(struct timeval *tv, void *unused);
+
+#define HAVE_OPENDIR
+struct dirent {
+ char *d_name;
+};
+
+typedef struct DIR {
+ long handle;
+ struct _finddata_t info;
+ struct dirent result;
+ char *name;
+} DIR;
+
+DIR *opendir(const char *name);
+int closedir(DIR *dir);
+struct dirent *readdir(DIR *dir);
+
+#endif
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#ifndef UTF8_UTIL_H
+#define UTF8_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#define MAX_UTF8_LEN 4
+
+int utf8_fromunicode(char *p, unsigned uc);
+
+#ifndef JIM_UTF8
+#include <ctype.h>
+
+
+#define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
+#define utf8_strwidth(S, B) utf8_strlen((S), (B))
+#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
+#define utf8_getchars(CP, C) (*(CP) = (C), 1)
+#define utf8_upper(C) toupper(C)
+#define utf8_title(C) toupper(C)
+#define utf8_lower(C) tolower(C)
+#define utf8_index(C, I) (I)
+#define utf8_charlen(C) 1
+#define utf8_prev_len(S, L) 1
+#define utf8_width(C) 1
+
+#else
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#ifndef __JIM__H
+#define __JIM__H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+
+#ifndef HAVE_NO_AUTOCONF
+#endif
+
+
+
+#ifndef jim_wide
+# ifdef HAVE_LONG_LONG
+# define jim_wide long long
+# ifndef LLONG_MAX
+# define LLONG_MAX 9223372036854775807LL
+# endif
+# ifndef LLONG_MIN
+# define LLONG_MIN (-LLONG_MAX - 1LL)
+# endif
+# define JIM_WIDE_MIN LLONG_MIN
+# define JIM_WIDE_MAX LLONG_MAX
+# else
+# define jim_wide long
+# define JIM_WIDE_MIN LONG_MIN
+# define JIM_WIDE_MAX LONG_MAX
+# endif
+
+
+# ifdef HAVE_LONG_LONG
+# define JIM_WIDE_MODIFIER "lld"
+# else
+# define JIM_WIDE_MODIFIER "ld"
+# define strtoull strtoul
+# endif
+#endif
+
+#define UCHAR(c) ((unsigned char)(c))
+
+
+
+#define JIM_ABI_VERSION 101
+
+#define JIM_OK 0
+#define JIM_ERR 1
+#define JIM_RETURN 2
+#define JIM_BREAK 3
+#define JIM_CONTINUE 4
+#define JIM_SIGNAL 5
+#define JIM_EXIT 6
+
+#define JIM_EVAL 7
+
+#define JIM_MAX_CALLFRAME_DEPTH 1000
+#define JIM_MAX_EVAL_DEPTH 2000
+
+
+#define JIM_PRIV_FLAG_SHIFT 20
+
+#define JIM_NONE 0
+#define JIM_ERRMSG 1
+#define JIM_ENUM_ABBREV 2
+#define JIM_UNSHARED 4
+#define JIM_MUSTEXIST 8
+#define JIM_NORESULT 16
+
+
+#define JIM_SUBST_NOVAR 1
+#define JIM_SUBST_NOCMD 2
+#define JIM_SUBST_NOESC 4
+#define JIM_SUBST_FLAG 128
+
+
+#define JIM_CASESENS 0
+#define JIM_NOCASE 1
+#define JIM_OPT_END 2
+
+
+#define JIM_PATH_LEN 1024
+
+
+#define JIM_NOTUSED(V) ((void) V)
+
+#define JIM_LIBPATH "auto_path"
+#define JIM_INTERACTIVE "tcl_interactive"
+
+
+typedef struct Jim_Stack {
+ int len;
+ int maxlen;
+ void **vector;
+} Jim_Stack;
+
+
+typedef struct Jim_HashEntry {
+ void *key;
+ union {
+ void *val;
+ int intval;
+ } u;
+ struct Jim_HashEntry *next;
+} Jim_HashEntry;
+
+typedef struct Jim_HashTableType {
+ unsigned int (*hashFunction)(const void *key);
+ void *(*keyDup)(void *privdata, const void *key);
+ void *(*valDup)(void *privdata, const void *obj);
+ int (*keyCompare)(void *privdata, const void *key1, const void *key2);
+ void (*keyDestructor)(void *privdata, void *key);
+ void (*valDestructor)(void *privdata, void *obj);
+} Jim_HashTableType;
+
+typedef struct Jim_HashTable {
+ Jim_HashEntry **table;
+ const Jim_HashTableType *type;
+ void *privdata;
+ unsigned int size;
+ unsigned int sizemask;
+ unsigned int used;
+ unsigned int collisions;
+ unsigned int uniq;
+} Jim_HashTable;
+
+typedef struct Jim_HashTableIterator {
+ Jim_HashTable *ht;
+ Jim_HashEntry *entry, *nextEntry;
+ int index;
+} Jim_HashTableIterator;
+
+
+#define JIM_HT_INITIAL_SIZE 16
+
+
+#define Jim_FreeEntryVal(ht, entry) \
+ if ((ht)->type->valDestructor) \
+ (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
+
+#define Jim_SetHashVal(ht, entry, _val_) do { \
+ if ((ht)->type->valDup) \
+ (entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \
+ else \
+ (entry)->u.val = (_val_); \
+} while(0)
+
+#define Jim_SetHashIntVal(ht, entry, _val_) (entry)->u.intval = (_val_)
+
+#define Jim_FreeEntryKey(ht, entry) \
+ if ((ht)->type->keyDestructor) \
+ (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
+
+#define Jim_SetHashKey(ht, entry, _key_) do { \
+ if ((ht)->type->keyDup) \
+ (entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \
+ else \
+ (entry)->key = (void *)(_key_); \
+} while(0)
+
+#define Jim_CompareHashKeys(ht, key1, key2) \
+ (((ht)->type->keyCompare) ? \
+ (ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \
+ (key1) == (key2))
+
+#define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq)
+
+#define Jim_GetHashEntryKey(he) ((he)->key)
+#define Jim_GetHashEntryVal(he) ((he)->u.val)
+#define Jim_GetHashEntryIntVal(he) ((he)->u.intval)
+#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
+#define Jim_GetHashTableSize(ht) ((ht)->size)
+#define Jim_GetHashTableUsed(ht) ((ht)->used)
+
+
+typedef struct Jim_Obj {
+ char *bytes;
+ const struct Jim_ObjType *typePtr;
+ int refCount;
+ int length;
+
+ union {
+
+ jim_wide wideValue;
+
+ int intValue;
+
+ double doubleValue;
+
+ void *ptr;
+
+ struct {
+ void *ptr1;
+ void *ptr2;
+ } twoPtrValue;
+
+ struct {
+ void *ptr;
+ int int1;
+ int int2;
+ } ptrIntValue;
+
+ struct {
+ struct Jim_VarVal *vv;
+ unsigned long callFrameId;
+ int global;
+ } varValue;
+
+ struct {
+ struct Jim_Obj *nsObj;
+ struct Jim_Cmd *cmdPtr;
+ unsigned long procEpoch;
+ } cmdValue;
+
+ struct {
+ struct Jim_Obj **ele;
+ int len;
+ int maxLen;
+ } listValue;
+
+ struct Jim_Dict *dictValue;
+
+ struct {
+ int maxLength;
+ int charLength;
+ } strValue;
+
+ struct {
+ unsigned long id;
+ struct Jim_Reference *refPtr;
+ } refValue;
+
+ struct {
+ struct Jim_Obj *fileNameObj;
+ int lineNumber;
+ } sourceValue;
+
+ struct {
+ struct Jim_Obj *varNameObjPtr;
+ struct Jim_Obj *indexObjPtr;
+ } dictSubstValue;
+ struct {
+ int line;
+ int argc;
+ } scriptLineValue;
+ } internalRep;
+ struct Jim_Obj *prevObjPtr;
+ struct Jim_Obj *nextObjPtr;
+} Jim_Obj;
+
+
+#define Jim_IncrRefCount(objPtr) \
+ ++(objPtr)->refCount
+#define Jim_DecrRefCount(interp, objPtr) \
+ if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
+#define Jim_IsShared(objPtr) \
+ ((objPtr)->refCount > 1)
+
+#define Jim_FreeNewObj Jim_FreeObj
+
+
+#define Jim_FreeIntRep(i,o) \
+ if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
+ (o)->typePtr->freeIntRepProc(i, o)
+
+
+#define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
+
+
+#define Jim_SetIntRepPtr(o, p) \
+ (o)->internalRep.ptr = (p)
+
+
+struct Jim_Interp;
+
+typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
+ struct Jim_Obj *objPtr);
+typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
+ struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
+
+typedef struct Jim_ObjType {
+ const char *name;
+ Jim_FreeInternalRepProc *freeIntRepProc;
+ Jim_DupInternalRepProc *dupIntRepProc;
+ Jim_UpdateStringProc *updateStringProc;
+ int flags;
+} Jim_ObjType;
+
+
+#define JIM_TYPE_NONE 0
+#define JIM_TYPE_REFERENCES 1
+
+
+
+typedef struct Jim_CallFrame {
+ unsigned long id;
+ int level;
+ struct Jim_HashTable vars;
+ struct Jim_HashTable *staticVars;
+ struct Jim_CallFrame *parent;
+ Jim_Obj *const *argv;
+ int argc;
+ Jim_Obj *procArgsObjPtr;
+ Jim_Obj *procBodyObjPtr;
+ struct Jim_CallFrame *next;
+ Jim_Obj *nsObj;
+ Jim_Obj *unused_fileNameObj;
+ int unused_line;
+ Jim_Stack *localCommands;
+ struct Jim_Obj *tailcallObj;
+ struct Jim_Cmd *tailcallCmd;
+} Jim_CallFrame;
+
+
+typedef struct Jim_EvalFrame {
+ Jim_CallFrame *framePtr;
+ int level;
+ int procLevel;
+ struct Jim_Cmd *cmd;
+ struct Jim_EvalFrame *parent;
+ Jim_Obj *const *argv;
+ int argc;
+ Jim_Obj *scriptObj;
+} Jim_EvalFrame;
+
+typedef struct Jim_VarVal {
+ Jim_Obj *objPtr;
+ struct Jim_CallFrame *linkFramePtr;
+ int refCount;
+} Jim_VarVal;
+
+
+typedef int Jim_CmdProc(struct Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv);
+typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData);
+
+typedef struct Jim_Dict {
+ struct JimDictHashEntry {
+ int offset;
+ unsigned hash;
+ } *ht;
+ unsigned int size;
+ unsigned int sizemask;
+ unsigned int uniq;
+ Jim_Obj **table;
+ int len;
+ int maxLen;
+ unsigned int dummy;
+} Jim_Dict;
+
+typedef struct Jim_Cmd {
+ int inUse;
+ int isproc;
+ struct Jim_Cmd *prevCmd;
+ Jim_Obj *cmdNameObj;
+ union {
+ struct {
+
+ Jim_CmdProc *cmdProc;
+ Jim_DelCmdProc *delProc;
+ void *privData;
+ } native;
+ struct {
+
+ Jim_Obj *argListObjPtr;
+ Jim_Obj *bodyObjPtr;
+ Jim_HashTable *staticVars;
+ int argListLen;
+ int reqArity;
+ int optArity;
+ int argsPos;
+ int upcall;
+ struct Jim_ProcArg {
+ Jim_Obj *nameObjPtr;
+ Jim_Obj *defaultObjPtr;
+ } *arglist;
+ Jim_Obj *nsObj;
+ } proc;
+ } u;
+} Jim_Cmd;
+
+
+typedef struct Jim_PrngState {
+ unsigned char sbox[256];
+ unsigned int i, j;
+} Jim_PrngState;
+
+typedef struct Jim_Interp {
+ Jim_Obj *result;
+ int unused_errorLine;
+ Jim_Obj *currentFilenameObj;
+ int break_level;
+ int maxCallFrameDepth;
+ int maxEvalDepth;
+ int evalDepth;
+ int returnCode;
+ int returnLevel;
+ int exitCode;
+ long id;
+ int signal_level;
+ jim_wide sigmask;
+ int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask);
+ Jim_CallFrame *framePtr;
+ Jim_CallFrame *topFramePtr;
+ struct Jim_HashTable commands;
+ unsigned long procEpoch; /* Incremented every time the result
+ of procedures names lookup caching
+ may no longer be valid. */
+ unsigned long callFrameEpoch; /* Incremented every time a new
+ callframe is created. This id is used for the
+ 'ID' field contained in the Jim_CallFrame
+ structure. */
+ int local;
+ int quitting;
+ int safeexpr;
+ Jim_Obj *liveList;
+ Jim_Obj *freeList;
+ Jim_Obj *unused_currentScriptObj;
+ Jim_EvalFrame topEvalFrame;
+ Jim_EvalFrame *evalFrame;
+ int procLevel;
+ Jim_Obj * const *unused_argv;
+ Jim_Obj *nullScriptObj;
+ Jim_Obj *emptyObj;
+ Jim_Obj *trueObj;
+ Jim_Obj *falseObj;
+ unsigned long referenceNextId;
+ struct Jim_HashTable references;
+ unsigned long lastCollectId; /* reference max Id of the last GC
+ execution. It's set to ~0 while the collection
+ is running as sentinel to avoid to recursive
+ calls via the [collect] command inside
+ finalizers. */
+ jim_wide lastCollectTime;
+ Jim_Obj *stackTrace;
+ Jim_Obj *errorProc;
+ Jim_Obj *unknown;
+ Jim_Obj *defer;
+ Jim_Obj *traceCmdObj;
+ int unknown_called;
+ int errorFlag;
+ void *cmdPrivData; /* Used to pass the private data pointer to
+ a command. It is set to what the user specified
+ via Jim_CreateCommand(). */
+
+ Jim_Cmd *oldCmdCache;
+ int oldCmdCacheSize;
+ struct Jim_CallFrame *freeFramesList;
+ struct Jim_HashTable assocData;
+ Jim_PrngState *prngState;
+ struct Jim_HashTable packages;
+ Jim_Stack *loadHandles;
+} Jim_Interp;
+
+#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
+#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
+
+#define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
+#define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
+#define Jim_GetResult(i) ((i)->result)
+#define Jim_CmdPrivData(i) ((i)->cmdPrivData)
+
+#define Jim_SetResult(i,o) do { \
+ Jim_Obj *_resultObjPtr_ = (o); \
+ Jim_IncrRefCount(_resultObjPtr_); \
+ Jim_DecrRefCount(i,(i)->result); \
+ (i)->result = _resultObjPtr_; \
+} while(0)
+
+
+#define Jim_GetId(i) (++(i)->id)
+
+
+#define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
+ string representation must be fixed length. */
+typedef struct Jim_Reference {
+ Jim_Obj *objPtr;
+ Jim_Obj *finalizerCmdNamePtr;
+ char tag[JIM_REFERENCE_TAGLEN+1];
+} Jim_Reference;
+
+
+#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
+#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
+
+#define JIM_EXPORT extern
+
+
+
+JIM_EXPORT void *(*Jim_Allocator)(void *ptr, size_t size);
+
+#define Jim_Free(P) Jim_Allocator((P), 0)
+#define Jim_Realloc(P, S) Jim_Allocator((P), (S))
+#define Jim_Alloc(S) Jim_Allocator(NULL, (S))
+JIM_EXPORT char * Jim_StrDup (const char *s);
+JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
+
+
+JIM_EXPORT char **Jim_GetEnviron(void);
+JIM_EXPORT void Jim_SetEnviron(char **env);
+JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file);
+#ifndef CLOCK_REALTIME
+# define CLOCK_REALTIME 0
+#endif
+#ifndef CLOCK_MONOTONIC
+# define CLOCK_MONOTONIC 1
+#endif
+#ifndef CLOCK_MONOTONIC_RAW
+# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+#endif
+JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
+
+
+JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
+
+
+JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
+
+#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
+
+JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
+JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
+ Jim_Obj *const *objv);
+JIM_EXPORT int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listObj);
+JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
+ int objc, Jim_Obj *const *objv);
+#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
+JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj);
+JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
+ Jim_Obj **resObjPtrPtr, int flags);
+
+
+JIM_EXPORT Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ int *lineptr);
+
+JIM_EXPORT void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *fileNameObj, int lineNumber);
+
+
+
+JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
+JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
+JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
+JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
+JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
+
+
+JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
+ const Jim_HashTableType *type, void *privdata);
+JIM_EXPORT void Jim_ExpandHashTable (Jim_HashTable *ht,
+ unsigned int size);
+JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
+ void *val);
+JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
+ const void *key, void *val);
+JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
+ const void *key);
+JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
+ const void *key);
+JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
+ (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
+ (Jim_HashTableIterator *iter);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
+JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
+JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
+ Jim_Obj *objPtr);
+JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
+ int *lenPtr);
+JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
+ const char *s, int len);
+JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
+ const char *s, int charlen);
+JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
+ char *s, int len);
+JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
+ const char *str, int len);
+JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *appendObjPtr);
+JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
+ Jim_Obj *objPtr, ...);
+JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr);
+JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr,
+ Jim_Obj *objPtr, int nocase);
+JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
+ Jim_Obj *lastObjPtr);
+JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
+ Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
+JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
+ Jim_Obj *fmtObjPtr, int flags);
+JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
+ Jim_Obj *objPtr, const char *str);
+JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
+ Jim_Obj *secondObjPtr, int nocase);
+JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
+ Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
+ Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
+
+
+JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
+JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
+JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
+JIM_EXPORT const char *Jim_ReturnCode(int code);
+JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
+
+
+JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
+JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
+ const char *cmdName, Jim_CmdProc *cmdProc, void *privData,
+ Jim_DelCmdProc *delProc);
+JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
+ Jim_Obj *cmdNameObj);
+JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
+ Jim_Obj *oldNameObj, Jim_Obj *newNameObj);
+JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
+ Jim_Obj *objPtr, int flags);
+JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
+JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
+ const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
+ const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
+ const char *name, const char *val);
+JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
+ Jim_CallFrame *targetCallFrame);
+JIM_EXPORT Jim_Obj * Jim_MakeGlobalNamespaceName(Jim_Interp *interp,
+ Jim_Obj *nameObjPtr);
+JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
+ const char *name, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
+ const char *name, int flags);
+JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, int flags);
+
+
+JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
+ Jim_Obj *levelObjPtr);
+
+
+JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
+JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
+
+
+JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
+ int *indexPtr);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
+ Jim_Obj *const *elements, int len);
+JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
+ Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
+JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
+ Jim_Obj *listPtr, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
+ Jim_Obj *listPtr, Jim_Obj *appendListPtr);
+JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
+ int listindex, Jim_Obj **objPtrPtr, int seterr);
+JIM_EXPORT Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx);
+JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
+ Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
+ Jim_Obj *newObjPtr);
+JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
+ Jim_Obj *const *objv);
+JIM_EXPORT Jim_Obj *Jim_ListJoin(Jim_Interp *interp,
+ Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
+ Jim_Obj *const *elements, int len);
+JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
+ Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
+ Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
+ Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
+ Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
+ Jim_Obj *newObjPtr, int flags);
+JIM_EXPORT Jim_Obj **Jim_DictPairs(Jim_Interp *interp,
+ Jim_Obj *dictPtr, int *len);
+JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
+
+#define JIM_DICTMATCH_KEYS 0x0001
+#define JIM_DICTMATCH_VALUES 0x002
+
+JIM_EXPORT int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types);
+JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv);
+
+
+JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
+ int *intPtr);
+
+
+JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
+ Jim_Obj *exprObjPtr);
+JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
+ Jim_Obj *exprObjPtr, int *boolPtr);
+
+
+JIM_EXPORT int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr,
+ int *booleanPtr);
+
+
+JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
+ jim_wide *widePtr);
+JIM_EXPORT int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr,
+ jim_wide *widePtr);
+JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
+ long *longPtr);
+#define Jim_NewWideObj Jim_NewIntObj
+JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
+ jim_wide wideValue);
+
+
+JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+ double *doublePtr);
+JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+ double doubleValue);
+JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
+
+
+JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv, const char *msg);
+JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
+ const char * const *tablePtr, int *indexPtr, const char *name, int flags);
+JIM_EXPORT int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr,
+ const char *const *tablePtr);
+JIM_EXPORT int Jim_ScriptIsComplete(Jim_Interp *interp,
+ Jim_Obj *scriptObj, char *stateCharPtr);
+
+JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
+
+
+typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
+JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
+ Jim_InterpDeleteProc *delProc, void *data);
+JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version);
+
+
+
+
+JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
+ const char *name, const char *ver, int flags);
+JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
+ const char *name, int flags);
+#define Jim_PackageProvideCheck(INTERP, NAME) \
+ if (Jim_CheckAbiVersion(INTERP, JIM_ABI_VERSION) == JIM_ERR || Jim_PackageProvide(INTERP, NAME, "1.0", JIM_ERRMSG)) \
+ return JIM_ERR
+
+
+JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
+
+
+JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
+JIM_EXPORT void Jim_HistoryLoad(const char *filename);
+JIM_EXPORT void Jim_HistorySave(const char *filename);
+JIM_EXPORT char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt);
+JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj);
+JIM_EXPORT void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj);
+JIM_EXPORT void Jim_HistoryAdd(const char *line);
+JIM_EXPORT void Jim_HistoryShow(void);
+JIM_EXPORT void Jim_HistorySetMaxLen(int length);
+JIM_EXPORT int Jim_HistoryGetMaxLen(void);
+
+
+JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
+JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
+JIM_EXPORT int Jim_IsBigEndian(void);
+
+#define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
+JIM_EXPORT void Jim_SignalSetIgnored(jim_wide mask);
+
+
+JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
+JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
+
+
+JIM_EXPORT int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
+
+
+JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#ifndef JIM_SUBCMD_H
+#define JIM_SUBCMD_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define JIM_MODFLAG_HIDDEN 0x0001
+#define JIM_MODFLAG_FULLARGV 0x0002
+
+
+
+typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+typedef struct {
+ const char *cmd;
+ const char *args;
+ jim_subcmd_function *function;
+ short minargs;
+ short maxargs;
+ unsigned short flags;
+} jim_subcmd_type;
+
+#define JIM_DEF_SUBCMD(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs }
+#define JIM_DEF_SUBCMD_HIDDEN(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs, JIM_MODFLAG_HIDDEN }
+
+const jim_subcmd_type *
+Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
+
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
+
+void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type *ct, Jim_Obj *subcmd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#ifndef JIMREGEXP_H
+#define JIMREGEXP_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+typedef struct {
+ int rm_so;
+ int rm_eo;
+} regmatch_t;
+
+
+typedef struct regexp {
+
+ int re_nsub;
+
+
+ int cflags;
+ int err;
+ int regstart;
+ int reganch;
+ int regmust;
+ int regmlen;
+ int *program;
+
+
+ const char *regparse;
+ int p;
+ int proglen;
+
+
+ int eflags;
+ const char *start;
+ const char *reginput;
+ const char *regbol;
+
+
+ regmatch_t *pmatch;
+ int nmatch;
+} regexp;
+
+typedef regexp regex_t;
+
+#define REG_EXTENDED 0
+#define REG_NEWLINE 1
+#define REG_ICASE 2
+
+#define REG_NOTBOL 16
+
+enum {
+ REG_NOERROR,
+ REG_NOMATCH,
+ REG_BADPAT,
+ REG_ERR_NULL_ARGUMENT,
+ REG_ERR_UNKNOWN,
+ REG_ERR_TOO_BIG,
+ REG_ERR_NOMEM,
+ REG_ERR_TOO_MANY_PAREN,
+ REG_ERR_UNMATCHED_PAREN,
+ REG_ERR_UNMATCHED_BRACES,
+ REG_ERR_BAD_COUNT,
+ REG_ERR_JUNK_ON_END,
+ REG_ERR_OPERAND_COULD_BE_EMPTY,
+ REG_ERR_NESTED_COUNT,
+ REG_ERR_INTERNAL,
+ REG_ERR_COUNT_FOLLOWS_NOTHING,
+ REG_ERR_INVALID_ESCAPE,
+ REG_ERR_CORRUPTED,
+ REG_ERR_NULL_CHAR,
+ REG_ERR_UNMATCHED_BRACKET,
+ REG_ERR_NUM
+};
+
+int jim_regcomp(regex_t *preg, const char *regex, int cflags);
+int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
+void jim_regfree(regex_t *preg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#ifndef JIM_SIGNAL_H
+#define JIM_SIGNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *Jim_SignalId(int sig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#ifndef JIMIOCOMPAT_H
+#define JIMIOCOMPAT_H
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+
+void Jim_SetResultErrno(Jim_Interp *interp, const char *msg);
+
+int Jim_OpenForWrite(const char *filename, int append);
+
+int Jim_OpenForRead(const char *filename);
+
+#if defined(__MINGW32__) || defined(_WIN32)
+ #ifndef STRICT
+ #define STRICT
+ #endif
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+ #include <fcntl.h>
+ #include <io.h>
+ #include <process.h>
+
+ typedef HANDLE phandle_t;
+ #define JIM_BAD_PHANDLE INVALID_HANDLE_VALUE
+
+
+ #define WIFEXITED(STATUS) (((STATUS) & 0xff00) == 0)
+ #define WEXITSTATUS(STATUS) ((STATUS) & 0x00ff)
+ #define WIFSIGNALED(STATUS) (((STATUS) & 0xff00) != 0)
+ #define WTERMSIG(STATUS) (((STATUS) >> 8) & 0xff)
+ #define WNOHANG 1
+
+ int Jim_Errno(void);
+
+ long waitpid(phandle_t phandle, int *status, int nohang);
+
+ phandle_t JimWaitPid(long processid, int *status, int nohang);
+
+ long JimProcessPid(phandle_t phandle);
+
+ #define HAVE_PIPE
+ #define pipe(P) _pipe((P), 0, O_NOINHERIT)
+
+ typedef struct __stat64 jim_stat_t;
+ #define Jim_Stat _stat64
+ #define Jim_FileStat _fstat64
+ #define Jim_Lseek _lseeki64
+ #define O_TEXT _O_TEXT
+ #define O_BINARY _O_BINARY
+ #define Jim_SetMode _setmode
+ #ifndef STDIN_FILENO
+ #define STDIN_FILENO 0
+ #endif
+
+#else
+ #if defined(HAVE_STAT64)
+ typedef struct stat64 jim_stat_t;
+ #define Jim_Stat stat64
+ #if defined(HAVE_FSTAT64)
+ #define Jim_FileStat fstat64
+ #endif
+ #if defined(HAVE_LSTAT64)
+ #define Jim_LinkStat lstat64
+ #endif
+ #else
+ typedef struct stat jim_stat_t;
+ #define Jim_Stat stat
+ #if defined(HAVE_FSTAT)
+ #define Jim_FileStat fstat
+ #endif
+ #if defined(HAVE_LSTAT)
+ #define Jim_LinkStat lstat
+ #endif
+ #endif
+ #if defined(HAVE_LSEEK64)
+ #define Jim_Lseek lseek64
+ #else
+ #define Jim_Lseek lseek
+ #endif
+
+ #if defined(HAVE_UNISTD_H)
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/wait.h>
+
+ typedef int phandle_t;
+ #define Jim_Errno() errno
+ #define JIM_BAD_PHANDLE -1
+ #define JimProcessPid(PIDTYPE) (PIDTYPE)
+ #define JimWaitPid waitpid
+
+ #ifndef HAVE_EXECVPE
+ #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
+ #endif
+ #endif
+
+ #ifndef O_TEXT
+ #define O_TEXT 0
+ #endif
+
+#endif
+
+# ifndef MAXPATHLEN
+# ifdef PATH_MAX
+# define MAXPATHLEN PATH_MAX
+# else
+# define MAXPATHLEN JIM_PATH_LEN
+# endif
+# endif
+
+
+int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb);
+
+#endif
+int Jim_bootstrapInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "bootstrap.tcl", 1,
+"\n"
+"proc package {cmd args} {\n"
+" if {$cmd eq \"require\"} {\n"
+" foreach path $::auto_path {\n"
+" lassign $args pkg\n"
+" set pkgpath $path/$pkg.tcl\n"
+" if {$path eq \".\"} {\n"
+" set pkgpath $pkg.tcl\n"
+" }\n"
+" if {[file exists $pkgpath]} {\n"
+" tailcall uplevel #0 [list source $pkgpath]\n"
+" }\n"
+" }\n"
+" }\n"
+"}\n"
+"set tcl_platform(bootstrap) 1\n"
+);
+}
+int Jim_initjimshInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "initjimsh", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "initjimsh.tcl", 1,
+"\n"
+"\n"
+"\n"
+"proc _jimsh_init {} {\n"
+" rename _jimsh_init {}\n"
+" global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n"
+"\n"
+"\n"
+" if {[exists jim::argv0]} {\n"
+" if {[string match \"*/*\" $jim::argv0]} {\n"
+" set jim::exe [file join [pwd] $jim::argv0]\n"
+" } else {\n"
+" set jim::argv0 [file tail $jim::argv0]\n"
+" set path [split [env PATH \"\"] $tcl_platform(pathSeparator)]\n"
+" if {$tcl_platform(platform) eq \"windows\"} {\n"
+"\n"
+" set path [lmap p [list \"\" {*}$path] { string map {\\\\ /} $p }]\n"
+" }\n"
+" foreach p $path {\n"
+" set exec [file join [pwd] $p $jim::argv0]\n"
+" if {[file executable $exec]} {\n"
+" set jim::exe $exec\n"
+" break\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+"\n"
+"\n"
+" lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n"
+" if {[exists jim::exe]} {\n"
+" lappend p [file dirname $jim::exe]\n"
+" }\n"
+" lappend p {*}$auto_path\n"
+" set auto_path $p\n"
+"\n"
+" if {$tcl_interactive && [env HOME {}] ne \"\"} {\n"
+" foreach src {.jimrc jimrc.tcl} {\n"
+" if {[file exists [env HOME]/$src]} {\n"
+" uplevel #0 source [env HOME]/$src\n"
+" break\n"
+" }\n"
+" }\n"
+" }\n"
+" return \"\"\n"
+"}\n"
+"\n"
+"if {$tcl_platform(platform) eq \"windows\"} {\n"
+" set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
+"}\n"
+"\n"
+"\n"
+"set tcl::autocomplete_commands {array clock debug dict file history info namespace package signal socket string tcl::prefix zlib}\n"
+"\n"
+"\n"
+"\n"
+"proc tcl::autocomplete {prefix} {\n"
+" if {[set space [string first \" \" $prefix]] != -1} {\n"
+" set cmd [string range $prefix 0 $space-1]\n"
+" if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n"
+" set arg [string range $prefix $space+1 end]\n"
+"\n"
+" return [lmap p [$cmd -commands] {\n"
+" if {![string match \"${arg}*\" $p]} continue\n"
+" function \"$cmd $p\"\n"
+" }]\n"
+" }\n"
+" }\n"
+"\n"
+" if {[string match \"source *\" $prefix]} {\n"
+" set path [string range $prefix 7 end]\n"
+" return [lmap p [glob -nocomplain \"${path}*\"] {\n"
+" function \"source $p\"\n"
+" }]\n"
+" }\n"
+"\n"
+" return [lmap p [lsort [info commands $prefix*]] {\n"
+" if {[string match \"* *\" $p]} {\n"
+" continue\n"
+" }\n"
+" function $p\n"
+" }]\n"
+"}\n"
+"\n"
+"\n"
+"set tcl::stdhint_commands {array clock debug dict file history info namespace package signal string zlib}\n"
+"\n"
+"set tcl::stdhint_cols {\n"
+" none {0}\n"
+" black {30}\n"
+" red {31}\n"
+" green {32}\n"
+" yellow {33}\n"
+" blue {34}\n"
+" purple {35}\n"
+" cyan {36}\n"
+" normal {37}\n"
+" grey {30 1}\n"
+" gray {30 1}\n"
+" lred {31 1}\n"
+" lgreen {32 1}\n"
+" lyellow {33 1}\n"
+" lblue {34 1}\n"
+" lpurple {35 1}\n"
+" lcyan {36 1}\n"
+" white {37 1}\n"
+"}\n"
+"\n"
+"\n"
+"set tcl::stdhint_col $tcl::stdhint_cols(lcyan)\n"
+"\n"
+"\n"
+"proc tcl::stdhint {string} {\n"
+" set result \"\"\n"
+" if {[llength $string] >= 2} {\n"
+" lassign $string cmd arg\n"
+" if {$cmd in $::tcl::stdhint_commands || [info channel $cmd] ne \"\"} {\n"
+" catch {\n"
+" set help [$cmd -help $arg]\n"
+" if {[string match \"Usage: $cmd *\" $help]} {\n"
+" set n [llength $string]\n"
+" set subcmd [lindex $help $n]\n"
+" incr n\n"
+" set hint [join [lrange $help $n end]]\n"
+" set prefix \"\"\n"
+" if {![string match \"* \" $string]} {\n"
+" if {$n == 3 && $subcmd ne $arg} {\n"
+"\n"
+" set prefix \"[string range $subcmd [string length $arg] end] \"\n"
+" } else {\n"
+" set prefix \" \"\n"
+" }\n"
+" }\n"
+" set result [list $prefix$hint {*}$::tcl::stdhint_col]\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+" return $result\n"
+"}\n"
+"\n"
+"_jimsh_init\n"
+);
+}
+int Jim_globInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "glob.tcl", 1,
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"package require readdir\n"
+"\n"
+"\n"
+"proc glob.globdir {dir pattern} {\n"
+" if {[file exists $dir/$pattern]} {\n"
+"\n"
+" return [list $pattern]\n"
+" }\n"
+"\n"
+" set result {}\n"
+" set files [readdir $dir]\n"
+" lappend files . ..\n"
+"\n"
+" foreach name $files {\n"
+" if {[string match $pattern $name]} {\n"
+"\n"
+" if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
+" continue\n"
+" }\n"
+" lappend result $name\n"
+" }\n"
+" }\n"
+"\n"
+" return $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc glob.explode {pattern} {\n"
+" set oldexp {}\n"
+" set newexp {\"\"}\n"
+"\n"
+" while 1 {\n"
+" set oldexp $newexp\n"
+" set newexp {}\n"
+" set ob [string first \\{ $pattern]\n"
+" set cb [string first \\} $pattern]\n"
+"\n"
+" if {$ob < $cb && $ob != -1} {\n"
+" set mid [string range $pattern 0 $ob-1]\n"
+" set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
+" if {$pattern eq \"\"} {\n"
+" error \"unmatched open brace in glob pattern\"\n"
+" }\n"
+" set pattern [string range $pattern 1 end]\n"
+"\n"
+" foreach subs $subexp {\n"
+" foreach sub [split $subs ,] {\n"
+" foreach old $oldexp {\n"
+" lappend newexp $old$mid$sub\n"
+" }\n"
+" }\n"
+" }\n"
+" } elseif {$cb != -1} {\n"
+" set suf [string range $pattern 0 $cb-1]\n"
+" set rest [string range $pattern $cb end]\n"
+" break\n"
+" } else {\n"
+" set suf $pattern\n"
+" set rest \"\"\n"
+" break\n"
+" }\n"
+" }\n"
+"\n"
+" foreach old $oldexp {\n"
+" lappend newexp $old$suf\n"
+" }\n"
+" list $rest {*}$newexp\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc glob.glob {base pattern} {\n"
+" set dir [file dirname $pattern]\n"
+" if {$pattern eq $dir || $pattern eq \"\"} {\n"
+" return [list [file join $base $dir] $pattern]\n"
+" } elseif {$pattern eq [file tail $pattern]} {\n"
+" set dir \"\"\n"
+" }\n"
+"\n"
+"\n"
+" set dirlist [glob.glob $base $dir]\n"
+" set pattern [file tail $pattern]\n"
+"\n"
+"\n"
+" set result {}\n"
+" foreach {realdir dir} $dirlist {\n"
+" if {![file isdir $realdir]} {\n"
+" continue\n"
+" }\n"
+" if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
+" append dir /\n"
+" }\n"
+" foreach name [glob.globdir $realdir $pattern] {\n"
+" lappend result [file join $realdir $name] $dir$name\n"
+" }\n"
+" }\n"
+" return $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc glob {args} {\n"
+" set nocomplain 0\n"
+" set base \"\"\n"
+" set tails 0\n"
+"\n"
+" set n 0\n"
+" foreach arg $args {\n"
+" if {[info exists param]} {\n"
+" set $param $arg\n"
+" unset param\n"
+" incr n\n"
+" continue\n"
+" }\n"
+" switch -glob -- $arg {\n"
+" -d* {\n"
+" set switch $arg\n"
+" set param base\n"
+" }\n"
+" -n* {\n"
+" set nocomplain 1\n"
+" }\n"
+" -ta* {\n"
+" set tails 1\n"
+" }\n"
+" -- {\n"
+" incr n\n"
+" break\n"
+" }\n"
+" -* {\n"
+" return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n"
+" }\n"
+" * {\n"
+" break\n"
+" }\n"
+" }\n"
+" incr n\n"
+" }\n"
+" if {[info exists param]} {\n"
+" return -code error \"missing argument to \\\"$switch\\\"\"\n"
+" }\n"
+" if {[llength $args] <= $n} {\n"
+" return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
+" }\n"
+"\n"
+" set args [lrange $args $n end]\n"
+"\n"
+" set result {}\n"
+" foreach pattern $args {\n"
+" set escpattern [string map {\n"
+" \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
+" } $pattern]\n"
+" set patexps [lassign [glob.explode $escpattern] rest]\n"
+" if {$rest ne \"\"} {\n"
+" return -code error \"unmatched close brace in glob pattern\"\n"
+" }\n"
+" foreach patexp $patexps {\n"
+" set patexp [string map {\n"
+" \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
+" } $patexp]\n"
+" foreach {realname name} [glob.glob $base $patexp] {\n"
+" incr n\n"
+" if {$tails} {\n"
+" lappend result $name\n"
+" } else {\n"
+" lappend result [file join $base $name]\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+"\n"
+" if {!$nocomplain && [llength $result] == 0} {\n"
+" set s $(([llength $args] > 1) ? \"s\" : \"\")\n"
+" return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n"
+" }\n"
+"\n"
+" return $result\n"
+"}\n"
+);
+}
+int Jim_stdlibInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "stdlib.tcl", 1,
+"\n"
+"\n"
+"if {![exists -command ref]} {\n"
+"\n"
+" proc ref {args} {{count 0}} {\n"
+" format %08x [incr count]\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc lambda {arglist args} {\n"
+" tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
+"}\n"
+"\n"
+"proc lambda.finalizer {name val} {\n"
+" rename $name {}\n"
+"}\n"
+"\n"
+"\n"
+"proc curry {args} {\n"
+" alias [ref {} function lambda.finalizer] {*}$args\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc function {value} {\n"
+" return $value\n"
+"}\n"
+"\n"
+"\n"
+"proc stackdump {stacktrace} {\n"
+" set lines {}\n"
+" lappend lines \"Traceback (most recent call last):\"\n"
+" foreach {cmd l f p} [lreverse $stacktrace] {\n"
+" set line {}\n"
+" if {$f ne \"\"} {\n"
+" append line \" File \\\"$f\\\", line $l\"\n"
+" }\n"
+" if {$p ne \"\"} {\n"
+" append line \", in $p\"\n"
+" }\n"
+" if {$line ne \"\"} {\n"
+" lappend lines $line\n"
+" if {$cmd ne \"\"} {\n"
+" set nl [string first \\n $cmd 1]\n"
+" if {$nl >= 0} {\n"
+" set cmd [string range $cmd 0 $nl-1]...\n"
+" }\n"
+" lappend lines \" $cmd\"\n"
+" }\n"
+" }\n"
+" }\n"
+" if {[llength $lines] > 1} {\n"
+" return [join $lines \\n]\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc defer {script} {\n"
+" upvar jim::defer v\n"
+" lappend v $script\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc errorInfo {msg {stacktrace \"\"}} {\n"
+" if {$stacktrace eq \"\"} {\n"
+"\n"
+" set stacktrace [info stacktrace]\n"
+" }\n"
+" lassign $stacktrace p f l cmd\n"
+" if {$f ne \"\"} {\n"
+" set result \"$f:$l: Error: \"\n"
+" }\n"
+" append result \"$msg\\n\"\n"
+" append result [stackdump $stacktrace]\n"
+"\n"
+"\n"
+" string trim $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc {info nameofexecutable} {} {\n"
+" if {[exists ::jim::exe]} {\n"
+" return $::jim::exe\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict update} {&varName args script} {\n"
+" set keys {}\n"
+" foreach {n v} $args {\n"
+" upvar $v var_$v\n"
+" if {[dict exists $varName $n]} {\n"
+" set var_$v [dict get $varName $n]\n"
+" }\n"
+" }\n"
+" catch {uplevel 1 $script} msg opts\n"
+" if {[info exists varName]} {\n"
+" foreach {n v} $args {\n"
+" if {[info exists var_$v]} {\n"
+" dict set varName $n [set var_$v]\n"
+" } else {\n"
+" dict unset varName $n\n"
+" }\n"
+" }\n"
+" }\n"
+" return {*}$opts $msg\n"
+"}\n"
+"\n"
+"proc {dict replace} {dictionary {args {key value}}} {\n"
+" if {[llength ${key value}] % 2} {\n"
+" tailcall {dict replace}\n"
+" }\n"
+" tailcall dict merge $dictionary ${key value}\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict lappend} {varName key {args value}} {\n"
+" upvar $varName dict\n"
+" if {[exists dict] && [dict exists $dict $key]} {\n"
+" set list [dict get $dict $key]\n"
+" }\n"
+" lappend list {*}$value\n"
+" dict set dict $key $list\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict append} {varName key {args value}} {\n"
+" upvar $varName dict\n"
+" if {[exists dict] && [dict exists $dict $key]} {\n"
+" set str [dict get $dict $key]\n"
+" }\n"
+" append str {*}$value\n"
+" dict set dict $key $str\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict incr} {varName key {increment 1}} {\n"
+" upvar $varName dict\n"
+" if {[exists dict] && [dict exists $dict $key]} {\n"
+" set value [dict get $dict $key]\n"
+" }\n"
+" incr value $increment\n"
+" dict set dict $key $value\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict remove} {dictionary {args key}} {\n"
+" foreach k $key {\n"
+" dict unset dictionary $k\n"
+" }\n"
+" return $dictionary\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict for} {vars dictionary script} {\n"
+" if {[llength $vars] != 2} {\n"
+" return -code error \"must have exactly two variable names\"\n"
+" }\n"
+" dict size $dictionary\n"
+" tailcall foreach $vars $dictionary $script\n"
+"}\n"
+);
+}
+int Jim_tclcompatInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "tclcompat.tcl", 1,
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"set env [env]\n"
+"\n"
+"\n"
+"if {[exists -command stdout]} {\n"
+"\n"
+" foreach p {gets flush close eof seek tell} {\n"
+" proc $p {chan args} {p} {\n"
+" tailcall $chan $p {*}$args\n"
+" }\n"
+" }\n"
+" unset p\n"
+"\n"
+"\n"
+"\n"
+" proc puts {{-nonewline {}} {chan stdout} msg} {\n"
+" if {${-nonewline} ni {-nonewline {}}} {\n"
+" tailcall ${-nonewline} puts $msg\n"
+" }\n"
+" tailcall $chan puts {*}${-nonewline} $msg\n"
+" }\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+" proc read {{-nonewline {}} chan} {\n"
+" if {${-nonewline} ni {-nonewline {}}} {\n"
+" tailcall ${-nonewline} read {*}${chan}\n"
+" }\n"
+" tailcall $chan read {*}${-nonewline}\n"
+" }\n"
+"\n"
+" proc fconfigure {f args} {\n"
+" foreach {n v} $args {\n"
+" switch -glob -- $n {\n"
+" -bl* {\n"
+" $f ndelay $(!$v)\n"
+" }\n"
+" -bu* {\n"
+" $f buffering $v\n"
+" }\n"
+" -tr* {\n"
+" $f translation $v\n"
+" }\n"
+" default {\n"
+" return -code error \"fconfigure: unknown option $n\"\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc fileevent {args} {\n"
+" tailcall {*}$args\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc parray {arrayname {pattern *} {puts puts}} {\n"
+" upvar $arrayname a\n"
+"\n"
+" set max 0\n"
+" foreach name [array names a $pattern]] {\n"
+" if {[string length $name] > $max} {\n"
+" set max [string length $name]\n"
+" }\n"
+" }\n"
+" incr max [string length $arrayname]\n"
+" incr max 2\n"
+" foreach name [lsort [array names a $pattern]] {\n"
+" $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc {file copy} {{force {}} source target} {\n"
+" try {\n"
+" if {$force ni {{} -force}} {\n"
+" error \"bad option \\\"$force\\\": should be -force\"\n"
+" }\n"
+"\n"
+" set in [open $source rb]\n"
+"\n"
+" if {[file exists $target]} {\n"
+" if {$force eq \"\"} {\n"
+" error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
+" }\n"
+"\n"
+" if {$source eq $target} {\n"
+" return\n"
+" }\n"
+"\n"
+"\n"
+" file stat $source ss\n"
+" file stat $target ts\n"
+" if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
+" return\n"
+" }\n"
+" }\n"
+" set out [open $target wb]\n"
+" $in copyto $out\n"
+" $out close\n"
+" } on error {msg opts} {\n"
+" incr opts(-level)\n"
+" return {*}$opts $msg\n"
+" } finally {\n"
+" catch {$in close}\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc popen {cmd {mode r}} {\n"
+" lassign [pipe] r w\n"
+" try {\n"
+" if {[string match \"w*\" $mode]} {\n"
+" lappend cmd <@$r &\n"
+" set pids [exec {*}$cmd]\n"
+" $r close\n"
+" set f $w\n"
+" } else {\n"
+" lappend cmd >@$w &\n"
+" set pids [exec {*}$cmd]\n"
+" $w close\n"
+" set f $r\n"
+" }\n"
+" lambda {cmd args} {f pids} {\n"
+" if {$cmd eq \"pid\"} {\n"
+" return $pids\n"
+" }\n"
+" if {$cmd eq \"close\"} {\n"
+" $f close\n"
+"\n"
+" set retopts {}\n"
+" foreach p $pids {\n"
+" lassign [wait $p] status - rc\n"
+" if {$status eq \"CHILDSTATUS\"} {\n"
+" if {$rc == 0} {\n"
+" continue\n"
+" }\n"
+" set msg \"child process exited abnormally\"\n"
+" } else {\n"
+" set msg \"child killed: received signal\"\n"
+" }\n"
+" set retopts [list -code error -errorcode [list $status $p $rc] $msg]\n"
+" }\n"
+" return {*}$retopts\n"
+" }\n"
+" tailcall $f $cmd {*}$args\n"
+" }\n"
+" } on error {error opts} {\n"
+" $r close\n"
+" $w close\n"
+" error $error\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"local proc pid {{channelId {}}} {\n"
+" if {$channelId eq \"\"} {\n"
+" tailcall upcall pid\n"
+" }\n"
+" if {[catch {$channelId tell}]} {\n"
+" return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
+" }\n"
+" if {[catch {$channelId pid} pids]} {\n"
+" return \"\"\n"
+" }\n"
+" return $pids\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc throw {code {msg \"\"}} {\n"
+" return -code $code $msg\n"
+"}\n"
+"\n"
+"\n"
+"proc {file delete force} {path} {\n"
+" foreach e [readdir $path] {\n"
+" file delete -force $path/$e\n"
+" }\n"
+" file delete $path\n"
+"}\n"
+);
+}
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
+
+
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#define HAVE_SOCKETS
+#elif defined (__MINGW32__)
+
+#endif
+
+#if defined(JIM_SSL)
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+#endif
+
+
+#define AIO_CMD_LEN 32
+#define AIO_DEFAULT_RBUF_LEN 256
+#define AIO_DEFAULT_WBUF_LIMIT (64 * 1024)
+
+#define AIO_KEEPOPEN 1
+#define AIO_NODELETE 2
+#define AIO_EOF 4
+#define AIO_WBUF_NONE 8
+#define AIO_NONBLOCK 16
+
+#define AIO_ONEREAD 32
+
+enum wbuftype {
+ WBUF_OPT_NONE,
+ WBUF_OPT_LINE,
+ WBUF_OPT_FULL,
+};
+
+#if defined(JIM_IPV6)
+#define IPV6 1
+#else
+#define IPV6 0
+#ifndef PF_INET6
+#define PF_INET6 0
+#endif
+#endif
+#if defined(HAVE_SYS_UN_H) && defined(PF_UNIX)
+#define UNIX_SOCKETS 1
+#else
+#define UNIX_SOCKETS 0
+#endif
+
+
+
+
+static int JimReadableTimeout(int fd, long ms)
+{
+#ifdef HAVE_SELECT
+ int retval;
+ struct timeval tv;
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+
+ FD_SET(fd, &rfds);
+ tv.tv_sec = ms / 1000;
+ tv.tv_usec = (ms % 1000) * 1000;
+
+ retval = select(fd + 1, &rfds, NULL, NULL, ms == 0 ? NULL : &tv);
+
+ if (retval > 0) {
+ return JIM_OK;
+ }
+ return JIM_ERR;
+#else
+ return JIM_OK;
+#endif
+}
+
+
+struct AioFile;
+
+typedef struct {
+ int (*writer)(struct AioFile *af, const char *buf, int len);
+ int (*reader)(struct AioFile *af, char *buf, int len, int pending);
+ int (*error)(const struct AioFile *af);
+ const char *(*strerror)(struct AioFile *af);
+ int (*verify)(struct AioFile *af);
+} JimAioFopsType;
+
+typedef struct AioFile
+{
+ Jim_Obj *filename;
+ int wbuft;
+ int flags;
+ long timeout;
+ int fd;
+ int addr_family;
+ void *ssl;
+ const JimAioFopsType *fops;
+ Jim_Obj *readbuf;
+ Jim_Obj *writebuf;
+ char *rbuf;
+ size_t rbuf_len;
+ size_t wbuf_limit;
+} AioFile;
+
+static void aio_consume(Jim_Obj *objPtr, int n);
+
+static int stdio_writer(struct AioFile *af, const char *buf, int len)
+{
+ int ret = write(af->fd, buf, len);
+ if (ret < 0 && errno == EPIPE) {
+ aio_consume(af->writebuf, Jim_Length(af->writebuf));
+ }
+ return ret;
+}
+
+static int stdio_reader(struct AioFile *af, char *buf, int len, int nb)
+{
+ if (nb || af->timeout == 0 || JimReadableTimeout(af->fd, af->timeout) == JIM_OK) {
+
+ int ret;
+
+ errno = 0;
+ ret = read(af->fd, buf, len);
+ if (ret <= 0 && errno != EAGAIN && errno != EINTR) {
+ af->flags |= AIO_EOF;
+ }
+ return ret;
+ }
+ errno = ETIMEDOUT;
+ return -1;
+}
+
+static int stdio_error(const AioFile *af)
+{
+ if (af->flags & AIO_EOF) {
+ return JIM_OK;
+ }
+
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ case ETIMEDOUT:
+#ifdef ECONNRESET
+ case ECONNRESET:
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED:
+#endif
+ return JIM_OK;
+ default:
+ return JIM_ERR;
+ }
+}
+
+static const char *stdio_strerror(struct AioFile *af)
+{
+ return strerror(errno);
+}
+
+static const JimAioFopsType stdio_fops = {
+ stdio_writer,
+ stdio_reader,
+ stdio_error,
+ stdio_strerror,
+ NULL,
+};
+
+
+static void aio_set_nonblocking(AioFile *af, int nb)
+{
+#ifdef O_NDELAY
+ int old = !!(af->flags & AIO_NONBLOCK);
+ if (old != nb) {
+ int fmode = fcntl(af->fd, F_GETFL);
+ if (nb) {
+ fmode |= O_NDELAY;
+ af->flags |= AIO_NONBLOCK;
+ }
+ else {
+ fmode &= ~O_NDELAY;
+ af->flags &= ~AIO_NONBLOCK;
+ }
+ (void)fcntl(af->fd, F_SETFL, fmode);
+ }
+#endif
+}
+
+static int aio_start_nonblocking(AioFile *af)
+{
+ int old = !!(af->flags & AIO_NONBLOCK);
+ if (af->timeout) {
+ aio_set_nonblocking(af, 1);
+ }
+ return old;
+}
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
+ const char *hdlfmt, int family, int flags);
+
+
+static const char *JimAioErrorString(AioFile *af)
+{
+ if (af && af->fops)
+ return af->fops->strerror(af);
+
+ return strerror(errno);
+}
+
+static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (name) {
+ Jim_SetResultFormatted(interp, "%#s: %s", name, JimAioErrorString(af));
+ }
+ else {
+ Jim_SetResultString(interp, JimAioErrorString(af), -1);
+ }
+}
+
+static int aio_eof(AioFile *af)
+{
+ return af->flags & AIO_EOF;
+}
+
+static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
+{
+ int ret = 0;
+ if (!aio_eof(af)) {
+ ret = af->fops->error(af);
+ if (ret) {
+ JimAioSetError(interp, af->filename);
+ }
+ }
+ return ret;
+}
+
+static void aio_consume(Jim_Obj *objPtr, int n)
+{
+ assert(objPtr->bytes);
+ assert(n <= objPtr->length);
+
+
+ memmove(objPtr->bytes, objPtr->bytes + n, objPtr->length - n + 1);
+ objPtr->length -= n;
+}
+
+
+static int aio_flush(Jim_Interp *interp, AioFile *af);
+
+#ifdef jim_ext_eventloop
+static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
+{
+ AioFile *af = clientData;
+
+ aio_flush(interp, af);
+ if (Jim_Length(af->writebuf) == 0) {
+
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+
+static int aio_flush(Jim_Interp *interp, AioFile *af)
+{
+ int len;
+ const char *pt = Jim_GetString(af->writebuf, &len);
+ if (len) {
+ int ret = af->fops->writer(af, pt, len);
+ if (ret > 0) {
+
+ aio_consume(af->writebuf, ret);
+ }
+ if (ret < 0) {
+ return JimCheckStreamError(interp, af);
+ }
+ if (Jim_Length(af->writebuf)) {
+#ifdef jim_ext_eventloop
+ void *handler = Jim_FindFileHandler(interp, af->fd, JIM_EVENT_WRITABLE);
+ if (handler == NULL) {
+ Jim_CreateFileHandler(interp, af->fd, JIM_EVENT_WRITABLE, aio_autoflush, af, NULL);
+ return JIM_OK;
+ }
+ else if (handler == af) {
+
+ return JIM_OK;
+ }
+#endif
+
+ Jim_SetResultString(interp, "send buffer is full", -1);
+ return JIM_ERR;
+ }
+ }
+ return JIM_OK;
+}
+
+static int aio_read_len(Jim_Interp *interp, AioFile *af, unsigned flags, int neededLen)
+{
+ if (!af->readbuf) {
+ af->readbuf = Jim_NewStringObj(interp, NULL, 0);
+ }
+
+ if (neededLen >= 0) {
+ neededLen -= Jim_Length(af->readbuf);
+ if (neededLen <= 0) {
+ return JIM_OK;
+ }
+ }
+
+ while (neededLen && !aio_eof(af)) {
+ int retval;
+ int readlen;
+
+ if (neededLen == -1) {
+ readlen = af->rbuf_len;
+ }
+ else {
+ readlen = (neededLen > af->rbuf_len ? af->rbuf_len : neededLen);
+ }
+
+ if (!af->rbuf) {
+ af->rbuf = Jim_Alloc(af->rbuf_len);
+ }
+ retval = af->fops->reader(af, af->rbuf, readlen, flags & AIO_NONBLOCK);
+ if (retval > 0) {
+ if (retval) {
+ Jim_AppendString(interp, af->readbuf, af->rbuf, retval);
+ }
+ if (neededLen != -1) {
+ neededLen -= retval;
+ }
+ if (flags & AIO_ONEREAD) {
+ return JIM_OK;
+ }
+ continue;
+ }
+ if ((flags & AIO_ONEREAD) || JimCheckStreamError(interp, af)) {
+ return JIM_ERR;
+ }
+ break;
+ }
+
+ return JIM_OK;
+}
+
+static Jim_Obj *aio_read_consume(Jim_Interp *interp, AioFile *af, int neededLen)
+{
+ Jim_Obj *objPtr = NULL;
+
+ if (neededLen < 0 || af->readbuf == NULL || Jim_Length(af->readbuf) <= neededLen) {
+ objPtr = af->readbuf;
+ af->readbuf = NULL;
+ }
+ else if (af->readbuf) {
+
+ int len;
+ const char *pt = Jim_GetString(af->readbuf, &len);
+
+ objPtr = Jim_NewStringObj(interp, pt, neededLen);
+ aio_consume(af->readbuf, neededLen);
+ }
+
+ return objPtr;
+}
+
+static void JimAioDelProc(Jim_Interp *interp, void *privData)
+{
+ AioFile *af = privData;
+
+ JIM_NOTUSED(interp);
+
+
+ aio_flush(interp, af);
+ Jim_DecrRefCount(interp, af->writebuf);
+
+#if UNIX_SOCKETS
+ if (af->addr_family == PF_UNIX && (af->flags & AIO_NODELETE) == 0) {
+
+ Jim_Obj *filenameObj = aio_sockname(interp, af->fd);
+ if (filenameObj) {
+ if (Jim_Length(filenameObj)) {
+ remove(Jim_String(filenameObj));
+ }
+ Jim_FreeNewObj(interp, filenameObj);
+ }
+ }
+#endif
+
+ Jim_DecrRefCount(interp, af->filename);
+
+#ifdef jim_ext_eventloop
+
+ Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
+#endif
+
+#if defined(JIM_SSL)
+ if (af->ssl != NULL) {
+ SSL_free(af->ssl);
+ }
+#endif
+ if (!(af->flags & AIO_KEEPOPEN)) {
+ close(af->fd);
+ }
+ if (af->readbuf) {
+ Jim_FreeNewObj(interp, af->readbuf);
+ }
+
+ Jim_Free(af->rbuf);
+ Jim_Free(af);
+}
+
+static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ int nonewline = 0;
+ jim_wide neededLen = -1;
+ static const char * const options[] = { "-pending", "-nonewline", NULL };
+ enum { OPT_PENDING, OPT_NONEWLINE };
+ int option;
+ int nb;
+ Jim_Obj *objPtr;
+
+ if (argc) {
+ if (*Jim_String(argv[0]) == '-') {
+ if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_PENDING:
+
+ break;
+ case OPT_NONEWLINE:
+ nonewline++;
+ break;
+ }
+ }
+ else {
+ if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK)
+ return JIM_ERR;
+ if (neededLen < 0) {
+ Jim_SetResultString(interp, "invalid parameter: negative len", -1);
+ return JIM_ERR;
+ }
+ }
+ argc--;
+ argv++;
+ }
+ if (argc) {
+ return -1;
+ }
+
+
+ nb = aio_start_nonblocking(af);
+
+ if (aio_read_len(interp, af, nb ? AIO_NONBLOCK : 0, neededLen) != JIM_OK) {
+ aio_set_nonblocking(af, nb);
+ return JIM_ERR;
+ }
+ objPtr = aio_read_consume(interp, af, neededLen);
+
+ aio_set_nonblocking(af, nb);
+
+ if (objPtr) {
+ if (nonewline) {
+ int len;
+ const char *s = Jim_GetString(objPtr, &len);
+
+ if (len > 0 && s[len - 1] == '\n') {
+ objPtr->length--;
+ objPtr->bytes[objPtr->length] = '\0';
+ }
+ }
+ Jim_SetResult(interp, objPtr);
+ }
+ else {
+ Jim_SetEmptyResult(interp);
+ }
+ return JIM_OK;
+}
+
+int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
+{
+ Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
+
+
+ if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
+ return ((AioFile *) cmdPtr->u.native.privData)->fd;
+ }
+ Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
+ return -1;
+}
+
+static int aio_cmd_getfd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+
+ aio_flush(interp, af);
+
+ Jim_SetResultInt(interp, af->fd);
+
+ return JIM_OK;
+}
+
+static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ jim_wide count = 0;
+ jim_wide maxlen = JIM_WIDE_MAX;
+ int ok = 1;
+ Jim_Obj *objv[4];
+
+ if (argc == 2) {
+ if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+
+ objv[0] = argv[0];
+ objv[1] = Jim_NewStringObj(interp, "flush", -1);
+ if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", argv[0]);
+ return JIM_ERR;
+ }
+
+
+ objv[0] = argv[0];
+ objv[1] = Jim_NewStringObj(interp, "puts", -1);
+ objv[2] = Jim_NewStringObj(interp, "-nonewline", -1);
+ Jim_IncrRefCount(objv[1]);
+ Jim_IncrRefCount(objv[2]);
+
+ while (count < maxlen) {
+ jim_wide len = maxlen - count;
+ if (len > af->rbuf_len) {
+ len = af->rbuf_len;
+ }
+ if (aio_read_len(interp, af, 0, len) != JIM_OK) {
+ ok = 0;
+ break;
+ }
+ objv[3] = aio_read_consume(interp, af, len);
+ count += Jim_Length(objv[3]);
+ if (Jim_EvalObjVector(interp, 4, objv) != JIM_OK) {
+ ok = 0;
+ break;
+ }
+ if (aio_eof(af)) {
+ break;
+ }
+ if (count >= 16384 && af->rbuf_len < 65536) {
+
+ af->rbuf_len = 65536;
+ af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
+ }
+ }
+
+ Jim_DecrRefCount(interp, objv[1]);
+ Jim_DecrRefCount(interp, objv[2]);
+
+ if (!ok) {
+ return JIM_ERR;
+ }
+
+ Jim_SetResultInt(interp, count);
+
+ return JIM_OK;
+}
+
+static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_Obj *objPtr = NULL;
+ int len;
+ int nb;
+ unsigned flags = AIO_ONEREAD;
+ char *nl = NULL;
+ int offset = 0;
+
+ errno = 0;
+
+
+ nb = aio_start_nonblocking(af);
+ if (nb) {
+ flags |= AIO_NONBLOCK;
+ }
+
+ while (!aio_eof(af)) {
+ if (af->readbuf) {
+ const char *pt = Jim_GetString(af->readbuf, &len);
+ nl = memchr(pt + offset, '\n', len - offset);
+ if (nl) {
+
+ objPtr = Jim_NewStringObj(interp, pt, nl - pt);
+
+ aio_consume(af->readbuf, nl - pt + 1);
+ break;
+ }
+ offset = len;
+ }
+
+
+ if (aio_read_len(interp, af, flags, -1) != JIM_OK) {
+ break;
+ }
+ }
+
+ aio_set_nonblocking(af, nb);
+
+ if (!nl && aio_eof(af) && af->readbuf) {
+
+ objPtr = af->readbuf;
+ af->readbuf = NULL;
+ }
+ else if (!objPtr) {
+ objPtr = Jim_NewStringObj(interp, NULL, 0);
+ }
+
+ if (argc) {
+ if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, objPtr);
+ return JIM_ERR;
+ }
+
+ len = Jim_Length(objPtr);
+
+ if (!nl && len == 0) {
+
+ len = -1;
+ }
+ Jim_SetResultInt(interp, len);
+ }
+ else {
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+}
+
+static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ int wlen;
+ const char *wdata;
+ Jim_Obj *strObj;
+ int wnow = 0;
+ int nl = 1;
+
+ if (argc == 2) {
+ if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
+ return -1;
+ }
+ strObj = argv[1];
+ nl = 0;
+ }
+ else {
+ strObj = argv[0];
+ }
+
+#ifdef JIM_MAINTAINER
+ if (Jim_IsShared(af->writebuf)) {
+ Jim_DecrRefCount(interp, af->writebuf);
+ af->writebuf = Jim_DuplicateObj(interp, af->writebuf);
+ Jim_IncrRefCount(af->writebuf);
+ }
+#endif
+ Jim_AppendObj(interp, af->writebuf, strObj);
+ if (nl) {
+ Jim_AppendString(interp, af->writebuf, "\n", 1);
+ }
+
+
+ wdata = Jim_GetString(af->writebuf, &wlen);
+ switch (af->wbuft) {
+ case WBUF_OPT_NONE:
+
+ wnow = 1;
+ break;
+
+ case WBUF_OPT_LINE:
+
+ if (nl || memchr(wdata, '\n', wlen) != NULL) {
+ wnow = 1;
+ }
+ break;
+
+ case WBUF_OPT_FULL:
+ if (wlen >= af->wbuf_limit) {
+ wnow = 1;
+ }
+ break;
+ }
+
+ if (wnow) {
+ return aio_flush(interp, af);
+ }
+ return JIM_OK;
+}
+
+static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_ISATTY
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_SetResultInt(interp, isatty(af->fd));
+#else
+ Jim_SetResultInt(interp, 0);
+#endif
+
+ return JIM_OK;
+}
+
+
+static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ return aio_flush(interp, af);
+}
+
+static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ Jim_SetResultInt(interp, !!aio_eof(af));
+ return JIM_OK;
+}
+
+static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ if (argc == 3) {
+ int option = -1;
+#if defined(HAVE_SOCKETS)
+ static const char * const options[] = { "r", "w", "-nodelete", NULL };
+ enum { OPT_R, OPT_W, OPT_NODELETE };
+
+ if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+#endif
+ switch (option) {
+#if defined(HAVE_SHUTDOWN)
+ case OPT_R:
+ case OPT_W:
+ if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) {
+ return JIM_OK;
+ }
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+#endif
+#if UNIX_SOCKETS
+ case OPT_NODELETE:
+ if (af->addr_family == PF_UNIX) {
+ af->flags |= AIO_NODELETE;
+ break;
+ }
+
+#endif
+ default:
+ Jim_SetResultString(interp, "not supported", -1);
+ return JIM_ERR;
+ }
+ }
+
+
+ af->flags &= ~AIO_KEEPOPEN;
+
+ return Jim_DeleteCommand(interp, argv[0]);
+}
+
+static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ int orig = SEEK_SET;
+ jim_wide offset;
+
+ if (argc == 2) {
+ if (Jim_CompareStringImmediate(interp, argv[1], "start"))
+ orig = SEEK_SET;
+ else if (Jim_CompareStringImmediate(interp, argv[1], "current"))
+ orig = SEEK_CUR;
+ else if (Jim_CompareStringImmediate(interp, argv[1], "end"))
+ orig = SEEK_END;
+ else {
+ return -1;
+ }
+ }
+ if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (orig != SEEK_CUR || offset != 0) {
+
+ aio_flush(interp, af);
+ }
+ if (Jim_Lseek(af->fd, offset, orig) == -1) {
+ JimAioSetError(interp, af->filename);
+ return JIM_ERR;
+ }
+ if (af->readbuf) {
+ Jim_FreeNewObj(interp, af->readbuf);
+ af->readbuf = NULL;
+ }
+ af->flags &= ~AIO_EOF;
+ return JIM_OK;
+}
+
+static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ Jim_SetResultInt(interp, Jim_Lseek(af->fd, 0, SEEK_CUR));
+ return JIM_OK;
+}
+
+static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ Jim_SetResult(interp, af->filename);
+ return JIM_OK;
+}
+
+#ifdef O_NDELAY
+static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (argc) {
+ long nb;
+
+ if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ aio_set_nonblocking(af, nb);
+ }
+ Jim_SetResultInt(interp, (af->flags & AIO_NONBLOCK) ? 1 : 0);
+ return JIM_OK;
+}
+#endif
+
+
+#ifdef HAVE_FSYNC
+static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (aio_flush(interp, af) != JIM_OK) {
+ return JIM_ERR;
+ }
+ fsync(af->fd);
+ return JIM_OK;
+}
+#endif
+
+static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_Obj *resultObj;
+
+ static const char * const options[] = {
+ "none",
+ "line",
+ "full",
+ NULL
+ };
+
+ if (argc) {
+ if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ if (af->wbuft == WBUF_OPT_FULL && argc == 2) {
+ long l;
+ if (Jim_GetLong(interp, argv[1], &l) != JIM_OK || l <= 0) {
+ return JIM_ERR;
+ }
+ af->wbuf_limit = l;
+ }
+
+ if (af->wbuft == WBUF_OPT_NONE) {
+ if (aio_flush(interp, af) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+
+ }
+
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, resultObj, Jim_NewStringObj(interp, options[af->wbuft], -1));
+ if (af->wbuft == WBUF_OPT_FULL) {
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, af->wbuf_limit));
+ }
+ Jim_SetResult(interp, resultObj);
+
+ return JIM_OK;
+}
+
+static int aio_cmd_translation(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ enum {OPT_BINARY, OPT_TEXT};
+ static const char * const options[] = {
+ "binary",
+ "text",
+ NULL
+ };
+ int opt;
+
+ if (Jim_GetEnum(interp, argv[0], options, &opt, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+#if defined(Jim_SetMode)
+ else {
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_SetMode(af->fd, opt == OPT_BINARY ? O_BINARY : O_TEXT);
+ }
+#endif
+ return JIM_OK;
+}
+
+static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (argc) {
+ long l;
+ if (Jim_GetLong(interp, argv[0], &l) != JIM_OK || l <= 0) {
+ return JIM_ERR;
+ }
+ af->rbuf_len = l;
+ if (af->rbuf) {
+ af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
+ }
+ }
+ Jim_SetResultInt(interp, af->rbuf_len);
+
+ return JIM_OK;
+}
+
+#ifdef jim_ext_eventloop
+static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_SELECT
+ AioFile *af = Jim_CmdPrivData(interp);
+ if (argc == 1) {
+ if (Jim_GetLong(interp, argv[0], &af->timeout) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ Jim_SetResultInt(interp, af->timeout);
+ return JIM_OK;
+#else
+ Jim_SetResultString(interp, "timeout not supported", -1);
+ return JIM_ERR;
+#endif
+}
+
+static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask,
+ int argc, Jim_Obj * const *argv)
+{
+ if (argc == 0) {
+
+ Jim_Obj *objPtr = Jim_FindFileHandler(interp, af->fd, mask);
+ if (objPtr) {
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+ }
+
+
+ Jim_DeleteFileHandler(interp, af->fd, mask);
+
+
+ if (Jim_Length(argv[0])) {
+ Jim_CreateScriptFileHandler(interp, af->fd, mask, argv[0]);
+ }
+
+ return JIM_OK;
+}
+
+static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ return aio_eventinfo(interp, af, JIM_EVENT_READABLE, argc, argv);
+}
+
+static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, argc, argv);
+}
+
+static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, argc, argv);
+}
+#endif
+
+#if defined(jim_ext_file) && defined(Jim_FileStat)
+static int aio_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (Jim_FileStat(af->fd, &sb) == -1) {
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+ }
+ return Jim_FileStoreStatData(interp, argc == 0 ? NULL : argv[0], &sb);
+}
+#endif
+
+
+
+
+static const jim_subcmd_type aio_command_table[] = {
+ { "read",
+ "?-nonewline|len?",
+ aio_cmd_read,
+ 0,
+ 2,
+
+ },
+ { "copyto",
+ "handle ?size?",
+ aio_cmd_copy,
+ 1,
+ 2,
+
+ },
+ { "getfd",
+ NULL,
+ aio_cmd_getfd,
+ 0,
+ 0,
+
+ },
+ { "gets",
+ "?var?",
+ aio_cmd_gets,
+ 0,
+ 1,
+
+ },
+ { "puts",
+ "?-nonewline? str",
+ aio_cmd_puts,
+ 1,
+ 2,
+
+ },
+ { "isatty",
+ NULL,
+ aio_cmd_isatty,
+ 0,
+ 0,
+
+ },
+ { "flush",
+ NULL,
+ aio_cmd_flush,
+ 0,
+ 0,
+
+ },
+ { "eof",
+ NULL,
+ aio_cmd_eof,
+ 0,
+ 0,
+
+ },
+ { "close",
+ "?r(ead)|w(rite)?",
+ aio_cmd_close,
+ 0,
+ 1,
+ JIM_MODFLAG_FULLARGV,
+
+ },
+ { "seek",
+ "offset ?start|current|end",
+ aio_cmd_seek,
+ 1,
+ 2,
+
+ },
+ { "tell",
+ NULL,
+ aio_cmd_tell,
+ 0,
+ 0,
+
+ },
+ { "filename",
+ NULL,
+ aio_cmd_filename,
+ 0,
+ 0,
+
+ },
+#ifdef O_NDELAY
+ { "ndelay",
+ "?0|1?",
+ aio_cmd_ndelay,
+ 0,
+ 1,
+
+ },
+#endif
+#ifdef HAVE_FSYNC
+ { "sync",
+ NULL,
+ aio_cmd_sync,
+ 0,
+ 0,
+
+ },
+#endif
+ { "buffering",
+ "?none|line|full? ?size?",
+ aio_cmd_buffering,
+ 0,
+ 2,
+
+ },
+ { "translation",
+ "binary|text",
+ aio_cmd_translation,
+ 1,
+ 1,
+
+ },
+ { "readsize",
+ "?size?",
+ aio_cmd_readsize,
+ 0,
+ 1,
+
+ },
+#if defined(jim_ext_file) && defined(Jim_FileStat)
+ { "stat",
+ "?var?",
+ aio_cmd_stat,
+ 0,
+ 1,
+
+ },
+#endif
+#ifdef jim_ext_eventloop
+ { "readable",
+ "?readable-script?",
+ aio_cmd_readable,
+ 0,
+ 1,
+
+ },
+ { "writable",
+ "?writable-script?",
+ aio_cmd_writable,
+ 0,
+ 1,
+
+ },
+ { "onexception",
+ "?exception-script?",
+ aio_cmd_onexception,
+ 0,
+ 1,
+
+ },
+ { "timeout",
+ "?ms?",
+ aio_cmd_timeout,
+ 0,
+ 1,
+
+ },
+#endif
+ { NULL }
+};
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
+}
+
+static int parse_posix_open_mode(Jim_Interp *interp, Jim_Obj *modeObj)
+{
+ int i;
+ int flags = 0;
+ #ifndef O_NOCTTY
+
+ #define O_NOCTTY 0
+ #endif
+ static const char * const modetypes[] = {
+ "RDONLY", "WRONLY", "RDWR", "APPEND", "BINARY", "CREAT", "EXCL", "NOCTTY", "TRUNC", NULL
+ };
+ static const int modeflags[] = {
+ O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, 0, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC,
+ };
+
+ for (i = 0; i < Jim_ListLength(interp, modeObj); i++) {
+ int opt;
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, modeObj, i);
+ if (Jim_GetEnum(interp, objPtr, modetypes, &opt, "access mode", JIM_ERRMSG) != JIM_OK) {
+ return -1;
+ }
+ flags |= modeflags[opt];
+ }
+ return flags;
+}
+
+static int parse_open_mode(Jim_Interp *interp, Jim_Obj *filenameObj, Jim_Obj *modeObj)
+{
+
+ int flags;
+ const char *mode = Jim_String(modeObj);
+ if (*mode == 'R' || *mode == 'W') {
+ return parse_posix_open_mode(interp, modeObj);
+ }
+ if (*mode == 'r') {
+ flags = O_RDONLY;
+ }
+ else if (*mode == 'w') {
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+ }
+ else if (*mode == 'a') {
+ flags = O_WRONLY | O_CREAT | O_APPEND;
+ }
+ else {
+ Jim_SetResultFormatted(interp, "%s: invalid open mode '%s'", Jim_String(filenameObj), mode);
+ return -1;
+ }
+ mode++;
+
+ if (*mode == 'b') {
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+ mode++;
+ }
+
+ if (*mode == 't') {
+#ifdef O_TEXT
+ flags |= O_TEXT;
+#endif
+ mode++;
+ }
+
+ if (*mode == '+') {
+ mode++;
+
+ flags &= ~(O_RDONLY | O_WRONLY);
+ flags |= O_RDWR;
+ }
+
+ if (*mode == 'x') {
+ mode++;
+#ifdef O_EXCL
+ flags |= O_EXCL;
+#endif
+ }
+
+ if (*mode == 'F') {
+ mode++;
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+ }
+
+ if (*mode == 'e') {
+
+ mode++;
+ }
+ return flags;
+}
+
+static int JimAioOpenCommand(Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv)
+{
+ int openflags;
+ const char *filename;
+ int fd = -1;
+ int n = 0;
+ int flags = 0;
+
+ if (argc > 2 && Jim_CompareStringImmediate(interp, argv[2], "-noclose")) {
+ flags = AIO_KEEPOPEN;
+ n++;
+ }
+ if (argc < 2 || argc > 3 + n) {
+ Jim_WrongNumArgs(interp, 1, argv, "filename ?-noclose? ?mode?");
+ return JIM_ERR;
+ }
+
+ filename = Jim_String(argv[1]);
+
+#ifdef jim_ext_tclcompat
+ {
+
+
+ if (*filename == '|') {
+ Jim_Obj *evalObj[3];
+ int i = 0;
+
+ evalObj[i++] = Jim_NewStringObj(interp, "::popen", -1);
+ evalObj[i++] = Jim_NewStringObj(interp, filename + 1, -1);
+ if (argc == 3 + n) {
+ evalObj[i++] = argv[2 + n];
+ }
+
+ return Jim_EvalObjVector(interp, i, evalObj);
+ }
+ }
+#endif
+ if (argc == 3 + n) {
+ openflags = parse_open_mode(interp, argv[1], argv[2 + n]);
+ if (openflags == -1) {
+ return JIM_ERR;
+ }
+ }
+ else {
+ openflags = O_RDONLY;
+ }
+ fd = open(filename, openflags, 0666);
+ if (fd < 0) {
+ JimAioSetError(interp, argv[1]);
+ return JIM_ERR;
+ }
+
+ return JimMakeChannel(interp, fd, argv[1], "aio.handle%ld", 0, flags) ? JIM_OK : JIM_ERR;
+}
+
+
+static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
+ const char *hdlfmt, int family, int flags)
+{
+ AioFile *af;
+ char buf[AIO_CMD_LEN];
+ Jim_Obj *cmdname;
+
+ snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
+ cmdname = Jim_NewStringObj(interp, buf, -1);
+ if (!filename) {
+ filename = cmdname;
+ }
+ Jim_IncrRefCount(filename);
+
+
+ af = Jim_Alloc(sizeof(*af));
+ memset(af, 0, sizeof(*af));
+ af->filename = filename;
+ af->fd = fd;
+ af->addr_family = family;
+ af->fops = &stdio_fops;
+ af->ssl = NULL;
+ if (flags & AIO_WBUF_NONE) {
+ af->wbuft = WBUF_OPT_NONE;
+ }
+ else {
+#ifdef HAVE_ISATTY
+ af->wbuft = isatty(af->fd) ? WBUF_OPT_LINE : WBUF_OPT_FULL;
+#else
+ af->wbuft = WBUF_OPT_FULL;
+#endif
+ }
+
+#ifdef FD_CLOEXEC
+ if ((flags & AIO_KEEPOPEN) == 0) {
+ (void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
+ }
+#endif
+ aio_set_nonblocking(af, !!(flags & AIO_NONBLOCK));
+
+ af->flags |= flags;
+
+ af->writebuf = Jim_NewStringObj(interp, NULL, 0);
+ Jim_IncrRefCount(af->writebuf);
+ af->wbuf_limit = AIO_DEFAULT_WBUF_LIMIT;
+ af->rbuf_len = AIO_DEFAULT_RBUF_LEN;
+
+
+ Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
+
+ Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, cmdname));
+
+ return af;
+}
+
+#if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && UNIX_SOCKETS) || defined(HAVE_OPENPTY)
+static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename,
+ const char *hdlfmt, int family, int flags)
+{
+ if (JimMakeChannel(interp, p[0], filename, hdlfmt, family, flags)) {
+ Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
+ if (JimMakeChannel(interp, p[1], filename, hdlfmt, family, flags)) {
+ Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ }
+
+
+ close(p[0]);
+ close(p[1]);
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+}
+#endif
+
+#ifdef HAVE_PIPE
+static int JimCreatePipe(Jim_Interp *interp, Jim_Obj *filenameObj, int flags)
+{
+ int p[2];
+
+ if (pipe(p) != 0) {
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+ }
+
+ return JimMakeChannelPair(interp, p, filenameObj, "aio.pipe%ld", 0, flags);
+}
+
+
+static int JimAioPipeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+ return JimCreatePipe(interp, argv[0], 0);
+}
+#endif
+
+#ifdef HAVE_OPENPTY
+static int JimAioOpenPtyCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int p[2];
+ char path[MAXPATHLEN];
+
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+
+ if (openpty(&p[0], &p[1], path, NULL, NULL) != 0) {
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+ }
+
+
+ return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
+ return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
+}
+#endif
+
+
+
+int Jim_aioInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+#if defined(JIM_SSL)
+ Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL);
+#endif
+
+ Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
+#ifdef HAVE_SOCKETS
+ Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
+#endif
+#ifdef HAVE_PIPE
+ Jim_CreateCommand(interp, "pipe", JimAioPipeCommand, NULL, NULL);
+#endif
+
+
+ JimMakeChannel(interp, fileno(stdin), NULL, "stdin", 0, AIO_KEEPOPEN);
+ JimMakeChannel(interp, fileno(stdout), NULL, "stdout", 0, AIO_KEEPOPEN);
+ JimMakeChannel(interp, fileno(stderr), NULL, "stderr", 0, AIO_KEEPOPEN | AIO_WBUF_NONE);
+
+ return JIM_OK;
+}
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *dirPath;
+ DIR *dirPtr;
+ struct dirent *entryPtr;
+ int nocomplain = 0;
+
+ if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) {
+ nocomplain = 1;
+ }
+ if (argc != 2 && !nocomplain) {
+ Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath");
+ return JIM_ERR;
+ }
+
+ dirPath = Jim_String(argv[1 + nocomplain]);
+
+ dirPtr = opendir(dirPath);
+ if (dirPtr == NULL) {
+ if (nocomplain) {
+ return JIM_OK;
+ }
+ Jim_SetResultString(interp, strerror(errno), -1);
+ return JIM_ERR;
+ }
+ else {
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+ while ((entryPtr = readdir(dirPtr)) != NULL) {
+ if (entryPtr->d_name[0] == '.') {
+ if (entryPtr->d_name[1] == '\0') {
+ continue;
+ }
+ if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0'))
+ continue;
+ }
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, entryPtr->d_name, -1));
+ }
+ closedir(dirPtr);
+
+ Jim_SetResult(interp, listObj);
+
+ return JIM_OK;
+ }
+}
+
+int Jim_readdirInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "readdir");
+ Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
+ return JIM_OK;
+}
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(JIM_REGEXP)
+#else
+ #include <regex.h>
+ #define jim_regcomp regcomp
+ #define jim_regexec regexec
+ #define jim_regerror regerror
+ #define jim_regfree regfree
+#endif
+
+static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ jim_regfree(objPtr->internalRep.ptrIntValue.ptr);
+ Jim_Free(objPtr->internalRep.ptrIntValue.ptr);
+}
+
+static const Jim_ObjType regexpObjType = {
+ "regexp",
+ FreeRegexpInternalRep,
+ NULL,
+ NULL,
+ JIM_TYPE_NONE
+};
+
+static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags)
+{
+ regex_t *compre;
+ const char *pattern;
+ int ret;
+
+
+ if (objPtr->typePtr == &regexpObjType &&
+ objPtr->internalRep.ptrIntValue.ptr && objPtr->internalRep.ptrIntValue.int1 == flags) {
+
+ return objPtr->internalRep.ptrIntValue.ptr;
+ }
+
+
+
+
+ pattern = Jim_String(objPtr);
+ compre = Jim_Alloc(sizeof(regex_t));
+
+ if ((ret = jim_regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
+ char buf[100];
+
+ jim_regerror(ret, compre, buf, sizeof(buf));
+ Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
+ jim_regfree(compre);
+ Jim_Free(compre);
+ return NULL;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ objPtr->typePtr = &regexpObjType;
+ objPtr->internalRep.ptrIntValue.int1 = flags;
+ objPtr->internalRep.ptrIntValue.ptr = compre;
+
+ return compre;
+}
+
+int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int opt_indices = 0;
+ int opt_all = 0;
+ int opt_inline = 0;
+ regex_t *regex;
+ int match, i, j;
+ int offset = 0;
+ regmatch_t *pmatch = NULL;
+ int source_len;
+ int result = JIM_OK;
+ const char *pattern;
+ const char *source_str;
+ int num_matches = 0;
+ int num_vars;
+ Jim_Obj *resultListObj = NULL;
+ int regcomp_flags = 0;
+ int eflags = 0;
+ int option;
+ enum {
+ OPT_INDICES, OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END
+ };
+ static const char * const options[] = {
+ "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
+ };
+
+ if (argc < 3) {
+ wrongNumArgs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-switch ...? exp string ?matchVar? ?subMatchVar ...?");
+ return JIM_ERR;
+ }
+
+ for (i = 1; i < argc; i++) {
+ const char *opt = Jim_String(argv[i]);
+
+ if (*opt != '-') {
+ break;
+ }
+ if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (option == OPT_END) {
+ i++;
+ break;
+ }
+ switch (option) {
+ case OPT_INDICES:
+ opt_indices = 1;
+ break;
+
+ case OPT_NOCASE:
+ regcomp_flags |= REG_ICASE;
+ break;
+
+ case OPT_LINE:
+ regcomp_flags |= REG_NEWLINE;
+ break;
+
+ case OPT_ALL:
+ opt_all = 1;
+ break;
+
+ case OPT_INLINE:
+ opt_inline = 1;
+ break;
+
+ case OPT_START:
+ if (++i == argc) {
+ goto wrongNumArgs;
+ }
+ if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+ return JIM_ERR;
+ }
+ break;
+ }
+ }
+ if (argc - i < 2) {
+ goto wrongNumArgs;
+ }
+
+ regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
+ if (!regex) {
+ return JIM_ERR;
+ }
+
+ pattern = Jim_String(argv[i]);
+ source_str = Jim_GetString(argv[i + 1], &source_len);
+
+ num_vars = argc - i - 2;
+
+ if (opt_inline) {
+ if (num_vars) {
+ Jim_SetResultString(interp, "regexp match variables not allowed when using -inline",
+ -1);
+ result = JIM_ERR;
+ goto done;
+ }
+ num_vars = regex->re_nsub + 1;
+ }
+
+ pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch));
+
+ if (offset) {
+ if (offset < 0) {
+ offset += source_len + 1;
+ }
+ if (offset > source_len) {
+ source_str += source_len;
+ }
+ else if (offset > 0) {
+ source_str += utf8_index(source_str, offset);
+ }
+ eflags |= REG_NOTBOL;
+ }
+
+ if (opt_inline) {
+ resultListObj = Jim_NewListObj(interp, NULL, 0);
+ }
+
+ next_match:
+ match = jim_regexec(regex, source_str, num_vars + 1, pmatch, eflags);
+ if (match >= REG_BADPAT) {
+ char buf[100];
+
+ jim_regerror(match, regex, buf, sizeof(buf));
+ Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+ result = JIM_ERR;
+ goto done;
+ }
+
+ if (match == REG_NOMATCH) {
+ goto done;
+ }
+
+ num_matches++;
+
+ if (opt_all && !opt_inline) {
+
+ goto try_next_match;
+ }
+
+
+ j = 0;
+ for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) {
+ Jim_Obj *resultObj;
+
+ if (opt_indices) {
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ }
+ else {
+ resultObj = Jim_NewStringObj(interp, "", 0);
+ }
+
+ if (pmatch[j].rm_so == -1) {
+ if (opt_indices) {
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+ }
+ }
+ else {
+ if (opt_indices) {
+
+ int so = utf8_strlen(source_str, pmatch[j].rm_so);
+ int eo = utf8_strlen(source_str, pmatch[j].rm_eo);
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + so));
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + eo - 1));
+ }
+ else {
+ Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
+ }
+ }
+
+ if (opt_inline) {
+ Jim_ListAppendElement(interp, resultListObj, resultObj);
+ }
+ else {
+
+ result = Jim_SetVariable(interp, argv[i], resultObj);
+
+ if (result != JIM_OK) {
+ Jim_FreeObj(interp, resultObj);
+ break;
+ }
+ }
+ }
+
+ try_next_match:
+ if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) {
+ if (pmatch[0].rm_eo) {
+ offset += utf8_strlen(source_str, pmatch[0].rm_eo);
+ source_str += pmatch[0].rm_eo;
+ }
+ else {
+ source_str++;
+ offset++;
+ }
+ if (*source_str) {
+ eflags = REG_NOTBOL;
+ goto next_match;
+ }
+ }
+
+ done:
+ if (result == JIM_OK) {
+ if (opt_inline) {
+ Jim_SetResult(interp, resultListObj);
+ }
+ else {
+ Jim_SetResultInt(interp, num_matches);
+ }
+ }
+
+ Jim_Free(pmatch);
+ return result;
+}
+
+#define MAX_SUB_MATCHES 50
+
+int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int regcomp_flags = 0;
+ int regexec_flags = 0;
+ int opt_all = 0;
+ int opt_command = 0;
+ int offset = 0;
+ regex_t *regex;
+ const char *p;
+ int result = JIM_OK;
+ regmatch_t pmatch[MAX_SUB_MATCHES + 1];
+ int num_matches = 0;
+
+ int i, j, n;
+ Jim_Obj *varname;
+ Jim_Obj *resultObj;
+ Jim_Obj *cmd_prefix = NULL;
+ Jim_Obj *regcomp_obj = NULL;
+ const char *source_str;
+ int source_len;
+ const char *replace_str = NULL;
+ int replace_len;
+ const char *pattern;
+ int option;
+ enum {
+ OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_COMMAND, OPT_END
+ };
+ static const char * const options[] = {
+ "-nocase", "-line", "-all", "-start", "-command", "--", NULL
+ };
+
+ if (argc < 4) {
+ wrongNumArgs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-switch ...? exp string subSpec ?varName?");
+ return JIM_ERR;
+ }
+
+ for (i = 1; i < argc; i++) {
+ const char *opt = Jim_String(argv[i]);
+
+ if (*opt != '-') {
+ break;
+ }
+ if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (option == OPT_END) {
+ i++;
+ break;
+ }
+ switch (option) {
+ case OPT_NOCASE:
+ regcomp_flags |= REG_ICASE;
+ break;
+
+ case OPT_LINE:
+ regcomp_flags |= REG_NEWLINE;
+ break;
+
+ case OPT_ALL:
+ opt_all = 1;
+ break;
+
+ case OPT_START:
+ if (++i == argc) {
+ goto wrongNumArgs;
+ }
+ if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+ return JIM_ERR;
+ }
+ break;
+
+ case OPT_COMMAND:
+ opt_command = 1;
+ break;
+ }
+ }
+ if (argc - i != 3 && argc - i != 4) {
+ goto wrongNumArgs;
+ }
+
+
+ regcomp_obj = Jim_DuplicateObj(interp, argv[i]);
+ Jim_IncrRefCount(regcomp_obj);
+ regex = SetRegexpFromAny(interp, regcomp_obj, regcomp_flags);
+ if (!regex) {
+ Jim_DecrRefCount(interp, regcomp_obj);
+ return JIM_ERR;
+ }
+ pattern = Jim_String(argv[i]);
+
+ source_str = Jim_GetString(argv[i + 1], &source_len);
+ if (opt_command) {
+ cmd_prefix = argv[i + 2];
+ if (Jim_ListLength(interp, cmd_prefix) == 0) {
+ Jim_SetResultString(interp, "command prefix must be a list of at least one element", -1);
+ Jim_DecrRefCount(interp, regcomp_obj);
+ return JIM_ERR;
+ }
+ Jim_IncrRefCount(cmd_prefix);
+ }
+ else {
+ replace_str = Jim_GetString(argv[i + 2], &replace_len);
+ }
+ varname = argv[i + 3];
+
+
+ resultObj = Jim_NewStringObj(interp, "", 0);
+
+ if (offset) {
+ if (offset < 0) {
+ offset += source_len + 1;
+ }
+ if (offset > source_len) {
+ offset = source_len;
+ }
+ else if (offset < 0) {
+ offset = 0;
+ }
+ }
+
+ offset = utf8_index(source_str, offset);
+
+
+ Jim_AppendString(interp, resultObj, source_str, offset);
+
+
+ n = source_len - offset;
+ p = source_str + offset;
+ do {
+ int match = jim_regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
+
+ if (match >= REG_BADPAT) {
+ char buf[100];
+
+ jim_regerror(match, regex, buf, sizeof(buf));
+ Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+ return JIM_ERR;
+ }
+ if (match == REG_NOMATCH) {
+ break;
+ }
+
+ num_matches++;
+
+ Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
+
+ if (opt_command) {
+
+ Jim_Obj *cmdListObj = Jim_DuplicateObj(interp, cmd_prefix);
+ for (j = 0; j < MAX_SUB_MATCHES; j++) {
+ if (pmatch[j].rm_so == -1) {
+ break;
+ }
+ else {
+ Jim_Obj *srcObj = Jim_NewStringObj(interp, p + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
+ Jim_ListAppendElement(interp, cmdListObj, srcObj);
+ }
+ }
+ Jim_IncrRefCount(cmdListObj);
+
+ result = Jim_EvalObj(interp, cmdListObj);
+ Jim_DecrRefCount(interp, cmdListObj);
+ if (result != JIM_OK) {
+ goto cmd_error;
+ }
+ Jim_AppendString(interp, resultObj, Jim_String(Jim_GetResult(interp)), -1);
+ }
+ else {
+
+ for (j = 0; j < replace_len; j++) {
+ int idx;
+ int c = replace_str[j];
+
+ if (c == '&') {
+ idx = 0;
+ }
+ else if (c == '\\' && j < replace_len) {
+ c = replace_str[++j];
+ if ((c >= '0') && (c <= '9')) {
+ idx = c - '0';
+ }
+ else if ((c == '\\') || (c == '&')) {
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
+ continue;
+ }
+ else {
+ Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
+ continue;
+ }
+ }
+ else {
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
+ continue;
+ }
+ if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
+ Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
+ pmatch[idx].rm_eo - pmatch[idx].rm_so);
+ }
+ }
+ }
+
+ p += pmatch[0].rm_eo;
+ n -= pmatch[0].rm_eo;
+
+
+ if (!opt_all || n == 0) {
+ break;
+ }
+
+
+ if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
+ break;
+ }
+
+
+ if (pattern[0] == '\0' && n) {
+
+ Jim_AppendString(interp, resultObj, p, 1);
+ p++;
+ n--;
+ }
+
+ if (pmatch[0].rm_eo == pmatch[0].rm_so) {
+
+ regexec_flags = REG_NOTBOL;
+ }
+ else {
+ regexec_flags = 0;
+ }
+
+ } while (n);
+
+ Jim_AppendString(interp, resultObj, p, -1);
+
+cmd_error:
+ if (result == JIM_OK) {
+
+ if (argc - i == 4) {
+ result = Jim_SetVariable(interp, varname, resultObj);
+
+ if (result == JIM_OK) {
+ Jim_SetResultInt(interp, num_matches);
+ }
+ else {
+ Jim_FreeObj(interp, resultObj);
+ }
+ }
+ else {
+ Jim_SetResult(interp, resultObj);
+ result = JIM_OK;
+ }
+ }
+ else {
+ Jim_FreeObj(interp, resultObj);
+ }
+
+ if (opt_command) {
+ Jim_DecrRefCount(interp, cmd_prefix);
+ }
+
+ Jim_DecrRefCount(interp, regcomp_obj);
+
+ return result;
+}
+
+int Jim_regexpInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "regexp");
+ Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
+ Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
+ return JIM_OK;
+}
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+#ifdef HAVE_UTIMES
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#elif defined(_MSC_VER)
+#include <direct.h>
+#define F_OK 0
+#define W_OK 2
+#define R_OK 4
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
+#define ISWINDOWS 1
+
+#undef HAVE_SYMLINK
+#else
+#define ISWINDOWS 0
+#endif
+
+
+#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
+ #define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000)
+#elif defined(HAVE_STRUCT_STAT_ST_MTIM)
+ #define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000)
+#endif
+
+
+static void JimFixPath(char *path)
+{
+ if (ISWINDOWS) {
+
+ char *p = path;
+ while ((p = strchr(p, '\\')) != NULL) {
+ *p++ = '/';
+ }
+ }
+}
+
+
+static const char *JimGetFileType(int mode)
+{
+ if (S_ISREG(mode)) {
+ return "file";
+ }
+ else if (S_ISDIR(mode)) {
+ return "directory";
+ }
+#ifdef S_ISCHR
+ else if (S_ISCHR(mode)) {
+ return "characterSpecial";
+ }
+#endif
+#ifdef S_ISBLK
+ else if (S_ISBLK(mode)) {
+ return "blockSpecial";
+ }
+#endif
+#ifdef S_ISFIFO
+ else if (S_ISFIFO(mode)) {
+ return "fifo";
+ }
+#endif
+#ifdef S_ISLNK
+ else if (S_ISLNK(mode)) {
+ return "link";
+ }
+#endif
+#ifdef S_ISSOCK
+ else if (S_ISSOCK(mode)) {
+ return "socket";
+ }
+#endif
+ return "unknown";
+}
+
+static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *key, jim_wide value)
+{
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
+}
+
+int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb)
+{
+
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+ AppendStatElement(interp, listObj, "dev", sb->st_dev);
+ AppendStatElement(interp, listObj, "ino", sb->st_ino);
+ AppendStatElement(interp, listObj, "mode", sb->st_mode);
+ AppendStatElement(interp, listObj, "nlink", sb->st_nlink);
+ AppendStatElement(interp, listObj, "uid", sb->st_uid);
+ AppendStatElement(interp, listObj, "gid", sb->st_gid);
+ AppendStatElement(interp, listObj, "size", sb->st_size);
+ AppendStatElement(interp, listObj, "atime", sb->st_atime);
+ AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
+ AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
+#ifdef STAT_MTIME_US
+ AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb));
+#endif
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));
+
+
+ if (varName) {
+ Jim_Obj *objPtr;
+ objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
+
+ if (objPtr) {
+ Jim_Obj *objv[2];
+
+ objv[0] = objPtr;
+ objv[1] = listObj;
+
+ objPtr = Jim_DictMerge(interp, 2, objv);
+ if (objPtr == NULL) {
+
+ Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
+ Jim_FreeNewObj(interp, listObj);
+ return JIM_ERR;
+ }
+
+ Jim_InvalidateStringRep(objPtr);
+
+ Jim_FreeNewObj(interp, listObj);
+ listObj = objPtr;
+ }
+ Jim_SetVariable(interp, varName, listObj);
+ }
+
+
+ Jim_SetResult(interp, listObj);
+
+ return JIM_OK;
+}
+
+static int JimPathLenNoTrailingSlashes(const char *path, int len)
+{
+ int i;
+ for (i = len; i > 1 && path[i - 1] == '/'; i--) {
+
+ if (ISWINDOWS && path[i - 2] == ':') {
+
+ break;
+ }
+ }
+ return i;
+}
+
+static Jim_Obj *JimStripTrailingSlashes(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int len = Jim_Length(objPtr);
+ const char *path = Jim_String(objPtr);
+ int i = JimPathLenNoTrailingSlashes(path, len);
+ if (i != len) {
+ objPtr = Jim_NewStringObj(interp, path, i);
+ }
+ Jim_IncrRefCount(objPtr);
+ return objPtr;
+}
+
+static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
+ const char *path = Jim_String(objPtr);
+ const char *p = strrchr(path, '/');
+
+ if (!p) {
+ Jim_SetResultString(interp, ".", -1);
+ }
+ else if (p[1] == 0) {
+
+ Jim_SetResult(interp, objPtr);
+ }
+ else if (p == path) {
+ Jim_SetResultString(interp, "/", -1);
+ }
+ else if (ISWINDOWS && p[-1] == ':') {
+
+ Jim_SetResultString(interp, path, p - path + 1);
+ }
+ else {
+
+ int len = JimPathLenNoTrailingSlashes(path, p - path);
+ Jim_SetResultString(interp, path, len);
+ }
+ Jim_DecrRefCount(interp, objPtr);
+ return JIM_OK;
+}
+
+static int file_cmd_split(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+ const char *path = Jim_String(argv[0]);
+
+ if (*path == '/') {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "/", 1));
+ }
+
+ while (1) {
+
+ while (*path == '/') {
+ path++;
+ }
+ if (*path) {
+ const char *pt = strchr(path, '/');
+ if (pt) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, pt - path));
+ path = pt;
+ continue;
+ }
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, -1));
+ }
+ break;
+ }
+ Jim_SetResult(interp, listObj);
+ return JIM_OK;
+}
+
+static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ const char *lastSlash = strrchr(path, '/');
+ const char *p = strrchr(path, '.');
+
+ if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
+ Jim_SetResult(interp, argv[0]);
+ }
+ else {
+ Jim_SetResultString(interp, path, p - path);
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
+ const char *path = Jim_String(objPtr);
+ const char *lastSlash = strrchr(path, '/');
+ const char *p = strrchr(path, '.');
+
+ if (p == NULL || (lastSlash != NULL && lastSlash >= p)) {
+ p = "";
+ }
+ Jim_SetResultString(interp, p, -1);
+ Jim_DecrRefCount(interp, objPtr);
+ return JIM_OK;
+}
+
+static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
+ const char *path = Jim_String(objPtr);
+ const char *lastSlash = strrchr(path, '/');
+
+ if (lastSlash) {
+ Jim_SetResultString(interp, lastSlash + 1, -1);
+ }
+ else {
+ Jim_SetResult(interp, objPtr);
+ }
+ Jim_DecrRefCount(interp, objPtr);
+ return JIM_OK;
+}
+
+#ifndef HAVE_RESTRICT
+#define restrict
+#endif
+
+static char *JimRealPath(const char *restrict path, char *restrict resolved_path, size_t len)
+{
+#if defined(HAVE__FULLPATH)
+ return _fullpath(resolved_path, path, len);
+#elif defined(HAVE_REALPATH)
+ return realpath(path, resolved_path);
+#else
+ return NULL;
+#endif
+}
+
+static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ char *newname = Jim_Alloc(MAXPATHLEN);
+
+ if (JimRealPath(path, newname, MAXPATHLEN)) {
+ JimFixPath(newname);
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
+ return JIM_OK;
+ }
+ Jim_Free(newname);
+ Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno));
+ return JIM_ERR;
+}
+
+static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ char *newname = Jim_Alloc(MAXPATHLEN + 1);
+ char *last = newname;
+
+ *newname = 0;
+
+
+ for (i = 0; i < argc; i++) {
+ int len;
+ const char *part = Jim_GetString(argv[i], &len);
+
+ if (*part == '/') {
+
+ last = newname;
+ }
+ else if (ISWINDOWS && strchr(part, ':')) {
+
+ last = newname;
+ }
+ else if (part[0] == '.') {
+ if (part[1] == '/') {
+ part += 2;
+ len -= 2;
+ }
+ else if (part[1] == 0 && last != newname) {
+
+ continue;
+ }
+ }
+
+
+ if (last != newname && last[-1] != '/') {
+ *last++ = '/';
+ }
+
+ if (len) {
+ if (last + len - newname >= MAXPATHLEN) {
+ Jim_Free(newname);
+ Jim_SetResultString(interp, "Path too long", -1);
+ return JIM_ERR;
+ }
+ memcpy(last, part, len);
+ last += len;
+ }
+
+
+ if (last > newname + 1 && last[-1] == '/') {
+
+ if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) {
+ *--last = 0;
+ }
+ }
+ }
+
+ *last = 0;
+
+
+
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
+
+ return JIM_OK;
+}
+
+static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
+{
+ Jim_SetResultBool(interp, access(Jim_String(filename), mode) != -1);
+
+ return JIM_OK;
+}
+
+static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], R_OK);
+}
+
+static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], W_OK);
+}
+
+static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef X_OK
+ return file_access(interp, argv[0], X_OK);
+#else
+
+ Jim_SetResultBool(interp, 1);
+ return JIM_OK;
+#endif
+}
+
+static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], F_OK);
+}
+
+static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int force = Jim_CompareStringImmediate(interp, argv[0], "-force");
+
+ if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) {
+ argc--;
+ argv++;
+ }
+
+ while (argc--) {
+ const char *path = Jim_String(argv[0]);
+
+ if (unlink(path) == -1 && errno != ENOENT) {
+ if (rmdir(path) == -1) {
+
+ if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
+ strerror(errno));
+ return JIM_ERR;
+ }
+ }
+ }
+ argv++;
+ }
+ return JIM_OK;
+}
+
+#ifdef HAVE_MKDIR_ONE_ARG
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
+#else
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
+#endif
+
+static int mkdir_all(char *path)
+{
+ int ok = 1;
+
+
+ goto first;
+
+ while (ok--) {
+
+ {
+ char *slash = strrchr(path, '/');
+
+ if (slash && slash != path) {
+ *slash = 0;
+ if (mkdir_all(path) != 0) {
+ return -1;
+ }
+ *slash = '/';
+ }
+ }
+ first:
+ if (MKDIR_DEFAULT(path) == 0) {
+ return 0;
+ }
+ if (errno == ENOENT) {
+
+ continue;
+ }
+
+ if (errno == EEXIST) {
+ jim_stat_t sb;
+
+ if (Jim_Stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ return 0;
+ }
+
+ errno = EEXIST;
+ }
+
+ break;
+ }
+ return -1;
+}
+
+static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ while (argc--) {
+ char *path = Jim_StrDup(Jim_String(argv[0]));
+ int rc = mkdir_all(path);
+
+ Jim_Free(path);
+ if (rc != 0) {
+ Jim_SetResultFormatted(interp, "can't create directory \"%#s\": %s", argv[0],
+ strerror(errno));
+ return JIM_ERR;
+ }
+ argv++;
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL, 0);
+
+ if (fd < 0) {
+ return JIM_ERR;
+ }
+ close(fd);
+
+ return JIM_OK;
+}
+
+static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *source;
+ const char *dest;
+ int force = 0;
+
+ if (argc == 3) {
+ if (!Jim_CompareStringImmediate(interp, argv[0], "-force")) {
+ return -1;
+ }
+ force++;
+ argv++;
+ argc--;
+ }
+
+ source = Jim_String(argv[0]);
+ dest = Jim_String(argv[1]);
+
+ if (!force && access(dest, F_OK) == 0) {
+ Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": target exists", argv[0],
+ argv[1]);
+ return JIM_ERR;
+ }
+#if ISWINDOWS
+ if (access(dest, F_OK) == 0) {
+
+ remove(dest);
+ }
+#endif
+ if (rename(source, dest) != 0) {
+ Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": %s", argv[0], argv[1],
+ strerror(errno));
+ return JIM_ERR;
+ }
+
+ return JIM_OK;
+}
+
+#if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
+static int file_cmd_link(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int ret;
+ const char *source;
+ const char *dest;
+ static const char * const options[] = { "-hard", "-symbolic", NULL };
+ enum { OPT_HARD, OPT_SYMBOLIC, };
+ int option = OPT_HARD;
+
+ if (argc == 3) {
+ if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ argv++;
+ argc--;
+ }
+
+ dest = Jim_String(argv[0]);
+ source = Jim_String(argv[1]);
+
+ if (option == OPT_HARD) {
+ ret = link(source, dest);
+ }
+ else {
+ ret = symlink(source, dest);
+ }
+
+ if (ret != 0) {
+ Jim_SetResultFormatted(interp, "error linking \"%#s\" to \"%#s\": %s", argv[0], argv[1],
+ strerror(errno));
+ return JIM_ERR;
+ }
+
+ return JIM_OK;
+}
+#endif
+
+static int file_stat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
+{
+ const char *path = Jim_String(filename);
+
+ if (Jim_Stat(path, sb) == -1) {
+ Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+#ifdef Jim_LinkStat
+static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
+{
+ const char *path = Jim_String(filename);
+
+ if (Jim_LinkStat(path, sb) == -1) {
+ Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+#else
+#define file_lstat file_stat
+#endif
+
+static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, sb.st_atime);
+ return JIM_OK;
+}
+
+static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us)
+{
+#ifdef HAVE_UTIMES
+ struct timeval times[2];
+
+ times[1].tv_sec = times[0].tv_sec = us / 1000000;
+ times[1].tv_usec = times[0].tv_usec = us % 1000000;
+
+ if (utimes(filename, times) != 0) {
+ Jim_SetResultFormatted(interp, "can't set time on \"%s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+#else
+ Jim_SetResultString(interp, "Not implemented", -1);
+ return JIM_ERR;
+#endif
+}
+
+static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (argc == 2) {
+ jim_wide secs;
+ if (Jim_GetWide(interp, argv[1], &secs) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return JimSetFileTimes(interp, Jim_String(argv[0]), secs * 1000000);
+ }
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, sb.st_mtime);
+ return JIM_OK;
+}
+
+#ifdef STAT_MTIME_US
+static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (argc == 2) {
+ jim_wide us;
+ if (Jim_GetWide(interp, argv[1], &us) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return JimSetFileTimes(interp, Jim_String(argv[0]), us);
+ }
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, STAT_MTIME_US(sb));
+ return JIM_OK;
+}
+#endif
+
+static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_EvalPrefix(interp, "file copy", argc, argv);
+}
+
+static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, sb.st_size);
+ return JIM_OK;
+}
+
+static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = S_ISDIR(sb.st_mode);
+ }
+ Jim_SetResultInt(interp, ret);
+ return JIM_OK;
+}
+
+static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = S_ISREG(sb.st_mode);
+ }
+ Jim_SetResultInt(interp, ret);
+ return JIM_OK;
+}
+
+#ifdef HAVE_GETEUID
+static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = (geteuid() == sb.st_uid);
+ }
+ Jim_SetResultInt(interp, ret);
+ return JIM_OK;
+}
+#endif
+
+#if defined(HAVE_READLINK)
+static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ char *linkValue = Jim_Alloc(MAXPATHLEN + 1);
+
+ int linkLength = readlink(path, linkValue, MAXPATHLEN);
+
+ if (linkLength == -1) {
+ Jim_Free(linkValue);
+ Jim_SetResultFormatted(interp, "could not read link \"%#s\": %s", argv[0], strerror(errno));
+ return JIM_ERR;
+ }
+ linkValue[linkLength] = 0;
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength));
+ return JIM_OK;
+}
+#endif
+
+static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1);
+ return JIM_OK;
+}
+
+#ifdef Jim_LinkStat
+static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
+}
+#else
+#define file_cmd_lstat file_cmd_stat
+#endif
+
+static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
+}
+
+static const jim_subcmd_type file_command_table[] = {
+ { "atime",
+ "name",
+ file_cmd_atime,
+ 1,
+ 1,
+
+ },
+ { "mtime",
+ "name ?time?",
+ file_cmd_mtime,
+ 1,
+ 2,
+
+ },
+#ifdef STAT_MTIME_US
+ { "mtimeus",
+ "name ?time?",
+ file_cmd_mtimeus,
+ 1,
+ 2,
+
+ },
+#endif
+ { "copy",
+ "?-force? source dest",
+ file_cmd_copy,
+ 2,
+ 3,
+
+ },
+ { "dirname",
+ "name",
+ file_cmd_dirname,
+ 1,
+ 1,
+
+ },
+ { "rootname",
+ "name",
+ file_cmd_rootname,
+ 1,
+ 1,
+
+ },
+ { "extension",
+ "name",
+ file_cmd_extension,
+ 1,
+ 1,
+
+ },
+ { "tail",
+ "name",
+ file_cmd_tail,
+ 1,
+ 1,
+
+ },
+ { "split",
+ "name",
+ file_cmd_split,
+ 1,
+ 1,
+
+ },
+ { "normalize",
+ "name",
+ file_cmd_normalize,
+ 1,
+ 1,
+
+ },
+ { "join",
+ "name ?name ...?",
+ file_cmd_join,
+ 1,
+ -1,
+
+ },
+ { "readable",
+ "name",
+ file_cmd_readable,
+ 1,
+ 1,
+
+ },
+ { "writable",
+ "name",
+ file_cmd_writable,
+ 1,
+ 1,
+
+ },
+ { "executable",
+ "name",
+ file_cmd_executable,
+ 1,
+ 1,
+
+ },
+ { "exists",
+ "name",
+ file_cmd_exists,
+ 1,
+ 1,
+
+ },
+ { "delete",
+ "?-force|--? name ...",
+ file_cmd_delete,
+ 1,
+ -1,
+
+ },
+ { "mkdir",
+ "dir ...",
+ file_cmd_mkdir,
+ 1,
+ -1,
+
+ },
+ { "tempfile",
+ "?template?",
+ file_cmd_tempfile,
+ 0,
+ 1,
+
+ },
+ { "rename",
+ "?-force? source dest",
+ file_cmd_rename,
+ 2,
+ 3,
+
+ },
+#if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
+ { "link",
+ "?-symbolic|-hard? newname target",
+ file_cmd_link,
+ 2,
+ 3,
+
+ },
+#endif
+#if defined(HAVE_READLINK)
+ { "readlink",
+ "name",
+ file_cmd_readlink,
+ 1,
+ 1,
+
+ },
+#endif
+ { "size",
+ "name",
+ file_cmd_size,
+ 1,
+ 1,
+
+ },
+ { "stat",
+ "name ?var?",
+ file_cmd_stat,
+ 1,
+ 2,
+
+ },
+ { "lstat",
+ "name ?var?",
+ file_cmd_lstat,
+ 1,
+ 2,
+
+ },
+ { "type",
+ "name",
+ file_cmd_type,
+ 1,
+ 1,
+
+ },
+#ifdef HAVE_GETEUID
+ { "owned",
+ "name",
+ file_cmd_owned,
+ 1,
+ 1,
+
+ },
+#endif
+ { "isdirectory",
+ "name",
+ file_cmd_isdirectory,
+ 1,
+ 1,
+
+ },
+ { "isfile",
+ "name",
+ file_cmd_isfile,
+ 1,
+ 1,
+
+ },
+ {
+ NULL
+ }
+};
+
+static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "dirname");
+ return JIM_ERR;
+ }
+
+ path = Jim_String(argv[1]);
+
+ if (chdir(path) != 0) {
+ Jim_SetResultFormatted(interp, "couldn't change working directory to \"%s\": %s", path,
+ strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ char *cwd = Jim_Alloc(MAXPATHLEN);
+
+ if (getcwd(cwd, MAXPATHLEN) == NULL) {
+ Jim_SetResultString(interp, "Failed to get pwd", -1);
+ Jim_Free(cwd);
+ return JIM_ERR;
+ }
+ JimFixPath(cwd);
+ Jim_SetResultString(interp, cwd, -1);
+
+ Jim_Free(cwd);
+ return JIM_OK;
+}
+
+int Jim_fileInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "file");
+ Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL);
+ Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
+ Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
+ return JIM_OK;
+}
+
+#include <string.h>
+#include <ctype.h>
+
+
+#if (!(defined(HAVE_VFORK) || defined(HAVE_FORK)) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
+ int i, j;
+ int rc;
+
+
+ for (i = 1; i < argc; i++) {
+ int len;
+ const char *arg = Jim_GetString(argv[i], &len);
+
+ if (i > 1) {
+ Jim_AppendString(interp, cmdlineObj, " ", 1);
+ }
+ if (strpbrk(arg, "\\\" ") == NULL) {
+
+ Jim_AppendString(interp, cmdlineObj, arg, len);
+ continue;
+ }
+
+ Jim_AppendString(interp, cmdlineObj, "\"", 1);
+ for (j = 0; j < len; j++) {
+ if (arg[j] == '\\' || arg[j] == '"') {
+ Jim_AppendString(interp, cmdlineObj, "\\", 1);
+ }
+ Jim_AppendString(interp, cmdlineObj, &arg[j], 1);
+ }
+ Jim_AppendString(interp, cmdlineObj, "\"", 1);
+ }
+ rc = system(Jim_String(cmdlineObj));
+
+ Jim_FreeNewObj(interp, cmdlineObj);
+
+ if (rc) {
+ Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc));
+ Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
+ return JIM_ERR;
+ }
+
+ return JIM_OK;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "exec");
+ Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
+ return JIM_OK;
+}
+#else
+
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+struct WaitInfoTable;
+
+static char **JimOriginalEnviron(void);
+static char **JimSaveEnv(char **env);
+static void JimRestoreEnv(char **env);
+static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
+ phandle_t **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
+static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr);
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj);
+static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+#if defined(__MINGW32__)
+static phandle_t JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId);
+#endif
+
+static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
+{
+ int len;
+ const char *s = Jim_GetString(objPtr, &len);
+
+ if (len > 0 && s[len - 1] == '\n') {
+ objPtr->length--;
+ objPtr->bytes[objPtr->length] = '\0';
+ }
+}
+
+static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj)
+{
+ char buf[256];
+ int ret = 0;
+
+ while (1) {
+ int retval = read(fd, buf, sizeof(buf));
+ if (retval > 0) {
+ ret = 1;
+ Jim_AppendString(interp, strObj, buf, retval);
+ }
+ if (retval <= 0) {
+ break;
+ }
+ }
+ close(fd);
+ return ret;
+}
+
+static char **JimBuildEnv(Jim_Interp *interp)
+{
+ int i;
+ int size;
+ int num;
+ int n;
+ char **envptr;
+ char *envdata;
+
+ Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
+
+ if (!objPtr) {
+ return JimOriginalEnviron();
+ }
+
+
+
+ num = Jim_ListLength(interp, objPtr);
+ if (num % 2) {
+
+ num--;
+ }
+ size = Jim_Length(objPtr) + 2;
+
+ envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
+ envdata = (char *)&envptr[num / 2 + 1];
+
+ n = 0;
+ for (i = 0; i < num; i += 2) {
+ const char *s1, *s2;
+ Jim_Obj *elemObj;
+
+ Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE);
+ s1 = Jim_String(elemObj);
+ Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE);
+ s2 = Jim_String(elemObj);
+
+ envptr[n] = envdata;
+ envdata += sprintf(envdata, "%s=%s", s1, s2);
+ envdata++;
+ n++;
+ }
+ envptr[n] = NULL;
+ *envdata = 0;
+
+ return envptr;
+}
+
+static void JimFreeEnv(char **env, char **original_environ)
+{
+ if (env != original_environ) {
+ Jim_Free(env);
+ }
+}
+
+static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
+{
+ Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+
+ if (pid <= 0) {
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, -1));
+ }
+ else if (WIFEXITED(waitStatus)) {
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
+ }
+ else {
+ const char *type;
+ const char *action;
+ const char *signame;
+
+ if (WIFSIGNALED(waitStatus)) {
+ type = "CHILDKILLED";
+ action = "killed";
+ signame = Jim_SignalId(WTERMSIG(waitStatus));
+ }
+ else {
+ type = "CHILDSUSP";
+ action = "suspended";
+ signame = "none";
+ }
+
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
+
+ if (errStrObj) {
+ Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL);
+ }
+
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, signame, -1));
+ }
+ return errorCode;
+}
+
+static int JimCheckWaitStatus(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
+{
+ if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) {
+ return JIM_OK;
+ }
+ Jim_SetGlobalVariableStr(interp, "errorCode", JimMakeErrorCode(interp, pid, waitStatus, errStrObj));
+
+ return JIM_ERR;
+}
+
+
+struct WaitInfo
+{
+ phandle_t phandle;
+ int status;
+ int flags;
+};
+
+
+struct WaitInfoTable {
+ struct WaitInfo *info;
+ int size;
+ int used;
+ int refcount;
+};
+
+
+#define WI_DETACHED 2
+
+#define WAIT_TABLE_GROW_BY 4
+
+static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
+{
+ struct WaitInfoTable *table = privData;
+
+ if (--table->refcount == 0) {
+ Jim_Free(table->info);
+ Jim_Free(table);
+ }
+}
+
+static struct WaitInfoTable *JimAllocWaitInfoTable(void)
+{
+ struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
+ table->info = NULL;
+ table->size = table->used = 0;
+ table->refcount = 1;
+
+ return table;
+}
+
+static int JimWaitRemove(struct WaitInfoTable *table, phandle_t phandle)
+{
+ int i;
+
+
+ for (i = 0; i < table->used; i++) {
+ if (phandle == table->info[i].phandle) {
+ if (i != table->used - 1) {
+ table->info[i] = table->info[table->used - 1];
+ }
+ table->used--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int outputId;
+ int errorId;
+ phandle_t *pidPtr;
+ int numPids, result;
+ int child_siginfo = 1;
+ Jim_Obj *childErrObj;
+ Jim_Obj *errStrObj;
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
+ Jim_Obj *listObj;
+ int i;
+
+ argc--;
+ numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
+ if (numPids < 0) {
+ return JIM_ERR;
+ }
+
+ listObj = Jim_NewListObj(interp, NULL, 0);
+ for (i = 0; i < numPids; i++) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, JimProcessPid(pidPtr[i])));
+ }
+ Jim_SetResult(interp, listObj);
+ JimDetachPids(table, numPids, pidPtr);
+ Jim_Free(pidPtr);
+ return JIM_OK;
+ }
+
+ numPids =
+ JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId);
+
+ if (numPids < 0) {
+ return JIM_ERR;
+ }
+
+ result = JIM_OK;
+
+ errStrObj = Jim_NewStringObj(interp, "", 0);
+
+
+ if (outputId != -1) {
+ if (JimAppendStreamToString(interp, outputId, errStrObj) < 0) {
+ result = JIM_ERR;
+ Jim_SetResultErrno(interp, "error reading from output pipe");
+ }
+ }
+
+
+ childErrObj = Jim_NewStringObj(interp, "", 0);
+ Jim_IncrRefCount(childErrObj);
+
+ if (JimCleanupChildren(interp, numPids, pidPtr, childErrObj) != JIM_OK) {
+ result = JIM_ERR;
+ }
+
+ if (errorId != -1) {
+ int ret;
+ Jim_Lseek(errorId, 0, SEEK_SET);
+ ret = JimAppendStreamToString(interp, errorId, errStrObj);
+ if (ret < 0) {
+ Jim_SetResultErrno(interp, "error reading from error pipe");
+ result = JIM_ERR;
+ }
+ else if (ret > 0) {
+
+ child_siginfo = 0;
+ }
+ }
+
+ if (child_siginfo) {
+
+ Jim_AppendObj(interp, errStrObj, childErrObj);
+ }
+ Jim_DecrRefCount(interp, childErrObj);
+
+
+ Jim_RemoveTrailingNewline(errStrObj);
+
+
+ Jim_SetResult(interp, errStrObj);
+
+ return result;
+}
+
+static long JimWaitForProcess(struct WaitInfoTable *table, phandle_t phandle, int *statusPtr)
+{
+ if (JimWaitRemove(table, phandle) == 0) {
+
+ return waitpid(phandle, statusPtr, 0);
+ }
+
+
+ return -1;
+}
+
+static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr)
+{
+ int j;
+
+ for (j = 0; j < numPids; j++) {
+
+ int i;
+ for (i = 0; i < table->used; i++) {
+ if (pidPtr[j] == table->info[i].phandle) {
+ table->info[i].flags |= WI_DETACHED;
+ break;
+ }
+ }
+ }
+}
+
+static int JimGetChannelFd(Jim_Interp *interp, const char *name)
+{
+ Jim_Obj *objv[2];
+
+ objv[0] = Jim_NewStringObj(interp, name, -1);
+ objv[1] = Jim_NewStringObj(interp, "getfd", -1);
+
+ if (Jim_EvalObjVector(interp, 2, objv) == JIM_OK) {
+ jim_wide fd;
+ if (Jim_GetWide(interp, Jim_GetResult(interp), &fd) == JIM_OK) {
+ return fd;
+ }
+ }
+ return -1;
+}
+
+static void JimReapDetachedPids(struct WaitInfoTable *table)
+{
+ struct WaitInfo *waitPtr;
+ int count;
+ int dest;
+
+ if (!table) {
+ return;
+ }
+
+ waitPtr = table->info;
+ dest = 0;
+ for (count = table->used; count > 0; waitPtr++, count--) {
+ if (waitPtr->flags & WI_DETACHED) {
+ int status;
+ long pid = waitpid(waitPtr->phandle, &status, WNOHANG);
+ if (pid > 0) {
+
+ table->used--;
+ continue;
+ }
+ }
+ if (waitPtr != &table->info[dest]) {
+ table->info[dest] = *waitPtr;
+ }
+ dest++;
+ }
+}
+
+static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+ int nohang = 0;
+ long pid;
+ phandle_t phandle;
+ int status;
+ Jim_Obj *errCodeObj;
+
+
+ if (argc == 1) {
+ JimReapDetachedPids(table);
+ return JIM_OK;
+ }
+
+ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) {
+ nohang = 1;
+ }
+ if (argc != nohang + 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?-nohang? ?pid?");
+ return JIM_ERR;
+ }
+ if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+
+ phandle = JimWaitPid(pid, &status, nohang ? WNOHANG : 0);
+ if (phandle == JIM_BAD_PHANDLE) {
+ pid = -1;
+ }
+#ifndef __MINGW32__
+ else if (pid < 0) {
+ pid = phandle;
+ }
+#endif
+
+ errCodeObj = JimMakeErrorCode(interp, pid, status, NULL);
+
+ if (phandle != JIM_BAD_PHANDLE && (WIFEXITED(status) || WIFSIGNALED(status))) {
+
+ JimWaitRemove(table, phandle);
+ }
+ Jim_SetResult(interp, errCodeObj);
+ return JIM_OK;
+}
+
+static int Jim_PidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+
+ Jim_SetResultInt(interp, (jim_wide)getpid());
+ return JIM_OK;
+}
+
+static int
+JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, phandle_t **pidArrayPtr,
+ int *inPipePtr, int *outPipePtr, int *errFilePtr)
+{
+ phandle_t *pidPtr = NULL; /* Points to alloc-ed array holding all
+ * the pids of child processes. */
+ int numPids = 0; /* Actual number of processes that exist
+ * at *pidPtr right now. */
+ int cmdCount; /* Count of number of distinct commands
+ * found in argc/argv. */
+ const char *input = NULL; /* Describes input for pipeline, depending
+ * on "inputFile". NULL means take input
+ * from stdin/pipe. */
+ int input_len = 0;
+
+#define FILE_NAME 0
+#define FILE_APPEND 1
+#define FILE_HANDLE 2
+#define FILE_TEXT 3
+
+ int inputFile = FILE_NAME; /* 1 means input is name of input file.
+ * 2 means input is filehandle name.
+ * 0 means input holds actual
+ * text to be input to command. */
+
+ int outputFile = FILE_NAME; /* 0 means output is the name of output file.
+ * 1 means output is the name of output file, and append.
+ * 2 means output is filehandle name.
+ * All this is ignored if output is NULL
+ */
+ int errorFile = FILE_NAME; /* 0 means error is the name of error file.
+ * 1 means error is the name of error file, and append.
+ * 2 means error is filehandle name.
+ * All this is ignored if error is NULL
+ */
+ const char *output = NULL; /* Holds name of output file to pipe to,
+ * or NULL if output goes to stdout/pipe. */
+ const char *error = NULL; /* Holds name of stderr file to pipe to,
+ * or NULL if stderr goes to stderr/pipe. */
+ int inputId = -1;
+ int outputId = -1;
+ int errorId = -1;
+ int lastOutputId = -1;
+ int pipeIds[2];
+ int firstArg, lastArg; /* Indexes of first and last arguments in
+ * current command. */
+ int lastBar;
+ int i;
+ phandle_t phandle;
+ char **save_environ;
+#if defined(HAVE_EXECVPE) && !defined(__MINGW32__)
+ char **child_environ;
+#endif
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+
+ char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
+ int arg_count = 0;
+
+ if (inPipePtr != NULL) {
+ *inPipePtr = -1;
+ }
+ if (outPipePtr != NULL) {
+ *outPipePtr = -1;
+ }
+ if (errFilePtr != NULL) {
+ *errFilePtr = -1;
+ }
+ pipeIds[0] = pipeIds[1] = -1;
+
+ cmdCount = 1;
+ lastBar = -1;
+ for (i = 0; i < argc; i++) {
+ const char *arg = Jim_String(argv[i]);
+
+ if (arg[0] == '<') {
+ inputFile = FILE_NAME;
+ input = arg + 1;
+ if (*input == '<') {
+ inputFile = FILE_TEXT;
+ input_len = Jim_Length(argv[i]) - 2;
+ input++;
+ }
+ else if (*input == '@') {
+ inputFile = FILE_HANDLE;
+ input++;
+ }
+
+ if (!*input && ++i < argc) {
+ input = Jim_GetString(argv[i], &input_len);
+ }
+ }
+ else if (arg[0] == '>') {
+ int dup_error = 0;
+
+ outputFile = FILE_NAME;
+
+ output = arg + 1;
+ if (*output == '>') {
+ outputFile = FILE_APPEND;
+ output++;
+ }
+ if (*output == '&') {
+
+ output++;
+ dup_error = 1;
+ }
+ if (*output == '@') {
+ outputFile = FILE_HANDLE;
+ output++;
+ }
+ if (!*output && ++i < argc) {
+ output = Jim_String(argv[i]);
+ }
+ if (dup_error) {
+ errorFile = outputFile;
+ error = output;
+ }
+ }
+ else if (arg[0] == '2' && arg[1] == '>') {
+ error = arg + 2;
+ errorFile = FILE_NAME;
+
+ if (*error == '@') {
+ errorFile = FILE_HANDLE;
+ error++;
+ }
+ else if (*error == '>') {
+ errorFile = FILE_APPEND;
+ error++;
+ }
+ if (!*error && ++i < argc) {
+ error = Jim_String(argv[i]);
+ }
+ }
+ else {
+ if (strcmp(arg, "|") == 0 || strcmp(arg, "|&") == 0) {
+ if (i == lastBar + 1 || i == argc - 1) {
+ Jim_SetResultString(interp, "illegal use of | or |& in command", -1);
+ goto badargs;
+ }
+ lastBar = i;
+ cmdCount++;
+ }
+
+ arg_array[arg_count++] = (char *)arg;
+ continue;
+ }
+
+ if (i >= argc) {
+ Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg);
+ goto badargs;
+ }
+ }
+
+ if (arg_count == 0) {
+ Jim_SetResultString(interp, "didn't specify command to execute", -1);
+badargs:
+ Jim_Free(arg_array);
+ return -1;
+ }
+
+
+ save_environ = JimSaveEnv(JimBuildEnv(interp));
+
+ if (input != NULL) {
+ if (inputFile == FILE_TEXT) {
+ inputId = Jim_MakeTempFile(interp, NULL, 1);
+ if (inputId == -1) {
+ goto error;
+ }
+ if (write(inputId, input, input_len) != input_len) {
+ Jim_SetResultErrno(interp, "couldn't write temp file");
+ close(inputId);
+ goto error;
+ }
+ Jim_Lseek(inputId, 0L, SEEK_SET);
+ }
+ else if (inputFile == FILE_HANDLE) {
+ int fd = JimGetChannelFd(interp, input);
+
+ if (fd < 0) {
+ goto error;
+ }
+ inputId = dup(fd);
+ }
+ else {
+ inputId = Jim_OpenForRead(input);
+ if (inputId == -1) {
+ Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, strerror(Jim_Errno()));
+ goto error;
+ }
+ }
+ }
+ else if (inPipePtr != NULL) {
+ if (pipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create input pipe for command");
+ goto error;
+ }
+ inputId = pipeIds[0];
+ *inPipePtr = pipeIds[1];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+
+ if (output != NULL) {
+ if (outputFile == FILE_HANDLE) {
+ int fd = JimGetChannelFd(interp, output);
+ if (fd < 0) {
+ goto error;
+ }
+ lastOutputId = dup(fd);
+ }
+ else {
+ lastOutputId = Jim_OpenForWrite(output, outputFile == FILE_APPEND);
+ if (lastOutputId == -1) {
+ Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, strerror(Jim_Errno()));
+ goto error;
+ }
+ }
+ }
+ else if (outPipePtr != NULL) {
+ if (pipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create output pipe");
+ goto error;
+ }
+ lastOutputId = pipeIds[1];
+ *outPipePtr = pipeIds[0];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+
+ if (error != NULL) {
+ if (errorFile == FILE_HANDLE) {
+ if (strcmp(error, "1") == 0) {
+
+ if (lastOutputId != -1) {
+ errorId = dup(lastOutputId);
+ }
+ else {
+
+ error = "stdout";
+ }
+ }
+ if (errorId == -1) {
+ int fd = JimGetChannelFd(interp, error);
+ if (fd < 0) {
+ goto error;
+ }
+ errorId = dup(fd);
+ }
+ }
+ else {
+ errorId = Jim_OpenForWrite(error, errorFile == FILE_APPEND);
+ if (errorId == -1) {
+ Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, strerror(Jim_Errno()));
+ goto error;
+ }
+ }
+ }
+ else if (errFilePtr != NULL) {
+ errorId = Jim_MakeTempFile(interp, NULL, 1);
+ if (errorId == -1) {
+ goto error;
+ }
+ *errFilePtr = dup(errorId);
+ }
+
+
+ pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
+ for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
+ int pipe_dup_err = 0;
+ int origErrorId = errorId;
+
+ for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
+ if (strcmp(arg_array[lastArg], "|") == 0) {
+ break;
+ }
+ if (strcmp(arg_array[lastArg], "|&") == 0) {
+ pipe_dup_err = 1;
+ break;
+ }
+ }
+
+ if (lastArg == firstArg) {
+ Jim_SetResultString(interp, "missing command to exec", -1);
+ goto error;
+ }
+
+
+ arg_array[lastArg] = NULL;
+ if (lastArg == arg_count) {
+ outputId = lastOutputId;
+ lastOutputId = -1;
+ }
+ else {
+ if (pipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create pipe");
+ goto error;
+ }
+ outputId = pipeIds[1];
+ }
+
+
+ if (pipe_dup_err) {
+ errorId = outputId;
+ }
+
+
+
+#ifdef __MINGW32__
+ phandle = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId);
+ if (phandle == JIM_BAD_PHANDLE) {
+ Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
+ goto error;
+ }
+#else
+ i = strlen(arg_array[firstArg]);
+
+#ifdef HAVE_EXECVPE
+ child_environ = Jim_GetEnviron();
+#endif
+#ifdef HAVE_VFORK
+ phandle = vfork();
+#else
+ phandle = fork();
+#endif
+ if (phandle < 0) {
+ Jim_SetResultErrno(interp, "couldn't fork child process");
+ goto error;
+ }
+ if (phandle == 0) {
+
+
+ if (inputId != -1 && inputId != fileno(stdin)) {
+ dup2(inputId, fileno(stdin));
+ close(inputId);
+ }
+ if (outputId != -1 && outputId != fileno(stdout)) {
+ dup2(outputId, fileno(stdout));
+ if (outputId != errorId) {
+ close(outputId);
+ }
+ }
+ if (errorId != -1 && errorId != fileno(stderr)) {
+ dup2(errorId, fileno(stderr));
+ close(errorId);
+ }
+
+ if (outPipePtr && *outPipePtr != -1) {
+ close(*outPipePtr);
+ }
+ if (errFilePtr && *errFilePtr != -1) {
+ close(*errFilePtr);
+ }
+ if (pipeIds[0] != -1) {
+ close(pipeIds[0]);
+ }
+ if (lastOutputId != -1) {
+ close(lastOutputId);
+ }
+
+ execvpe(arg_array[firstArg], &arg_array[firstArg], child_environ);
+
+ if (write(fileno(stderr), "couldn't exec \"", 15) &&
+ write(fileno(stderr), arg_array[firstArg], i) &&
+ write(fileno(stderr), "\"\n", 2)) {
+
+ }
+#ifdef JIM_MAINTAINER
+ {
+
+ static char *const false_argv[2] = {"false", NULL};
+ execvp(false_argv[0],false_argv);
+ }
+#endif
+ _exit(127);
+ }
+#endif
+
+
+
+ if (table->used == table->size) {
+ table->size += WAIT_TABLE_GROW_BY;
+ table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
+ }
+
+ table->info[table->used].phandle = phandle;
+ table->info[table->used].flags = 0;
+ table->used++;
+
+ pidPtr[numPids] = phandle;
+
+
+ errorId = origErrorId;
+
+
+ if (inputId != -1) {
+ close(inputId);
+ }
+ if (outputId != -1) {
+ close(outputId);
+ }
+ inputId = pipeIds[0];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+ *pidArrayPtr = pidPtr;
+
+
+ cleanup:
+ if (inputId != -1) {
+ close(inputId);
+ }
+ if (lastOutputId != -1) {
+ close(lastOutputId);
+ }
+ if (errorId != -1) {
+ close(errorId);
+ }
+ Jim_Free(arg_array);
+
+ JimRestoreEnv(save_environ);
+
+ return numPids;
+
+
+ error:
+ if ((inPipePtr != NULL) && (*inPipePtr != -1)) {
+ close(*inPipePtr);
+ *inPipePtr = -1;
+ }
+ if ((outPipePtr != NULL) && (*outPipePtr != -1)) {
+ close(*outPipePtr);
+ *outPipePtr = -1;
+ }
+ if ((errFilePtr != NULL) && (*errFilePtr != -1)) {
+ close(*errFilePtr);
+ *errFilePtr = -1;
+ }
+ if (pipeIds[0] != -1) {
+ close(pipeIds[0]);
+ }
+ if (pipeIds[1] != -1) {
+ close(pipeIds[1]);
+ }
+ if (pidPtr != NULL) {
+ for (i = 0; i < numPids; i++) {
+ if (pidPtr[i] != JIM_BAD_PHANDLE) {
+ JimDetachPids(table, 1, &pidPtr[i]);
+ }
+ }
+ Jim_Free(pidPtr);
+ }
+ numPids = -1;
+ goto cleanup;
+}
+
+
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj)
+{
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+ int result = JIM_OK;
+ int i;
+
+
+ for (i = 0; i < numPids; i++) {
+ int waitStatus = 0;
+ long pid = JimWaitForProcess(table, pidPtr[i], &waitStatus);
+ if (pid > 0) {
+ if (JimCheckWaitStatus(interp, pid, waitStatus, errStrObj) != JIM_OK) {
+ result = JIM_ERR;
+ }
+ }
+ }
+ Jim_Free(pidPtr);
+
+ return result;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+ struct WaitInfoTable *waitinfo;
+
+ Jim_PackageProvideCheck(interp, "exec");
+
+ waitinfo = JimAllocWaitInfoTable();
+ Jim_CreateCommand(interp, "exec", Jim_ExecCmd, waitinfo, JimFreeWaitInfoTable);
+ waitinfo->refcount++;
+ Jim_CreateCommand(interp, "wait", Jim_WaitCommand, waitinfo, JimFreeWaitInfoTable);
+ Jim_CreateCommand(interp, "pid", Jim_PidCommand, 0, 0);
+
+ return JIM_OK;
+}
+
+#if defined(__MINGW32__)
+
+
+static int
+JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
+{
+ int i;
+ static char extensions[][5] = {".exe", "", ".bat"};
+
+ for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
+ snprintf(fullPath, MAX_PATH, "%s%s", originalName, extensions[i]);
+
+ if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) {
+ continue;
+ }
+ if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) {
+ continue;
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+static char **JimSaveEnv(char **env)
+{
+ return env;
+}
+
+static void JimRestoreEnv(char **env)
+{
+ JimFreeEnv(env, Jim_GetEnviron());
+}
+
+static char **JimOriginalEnviron(void)
+{
+ return NULL;
+}
+
+static Jim_Obj *
+JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
+{
+ char *start, *special;
+ int quote, i;
+
+ Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0);
+
+ for (i = 0; argv[i]; i++) {
+ if (i > 0) {
+ Jim_AppendString(interp, strObj, " ", 1);
+ }
+
+ if (argv[i][0] == '\0') {
+ quote = 1;
+ }
+ else {
+ quote = 0;
+ for (start = argv[i]; *start != '\0'; start++) {
+ if (isspace(UCHAR(*start))) {
+ quote = 1;
+ break;
+ }
+ }
+ }
+ if (quote) {
+ Jim_AppendString(interp, strObj, "\"" , 1);
+ }
+
+ start = argv[i];
+ for (special = argv[i]; ; ) {
+ if ((*special == '\\') && (special[1] == '\\' ||
+ special[1] == '"' || (quote && special[1] == '\0'))) {
+ Jim_AppendString(interp, strObj, start, special - start);
+ start = special;
+ while (1) {
+ special++;
+ if (*special == '"' || (quote && *special == '\0')) {
+
+ Jim_AppendString(interp, strObj, start, special - start);
+ break;
+ }
+ if (*special != '\\') {
+ break;
+ }
+ }
+ Jim_AppendString(interp, strObj, start, special - start);
+ start = special;
+ }
+ if (*special == '"') {
+ if (special == start) {
+ Jim_AppendString(interp, strObj, "\"", 1);
+ }
+ else {
+ Jim_AppendString(interp, strObj, start, special - start);
+ }
+ Jim_AppendString(interp, strObj, "\\\"", 2);
+ start = special + 1;
+ }
+ if (*special == '\0') {
+ break;
+ }
+ special++;
+ }
+ Jim_AppendString(interp, strObj, start, special - start);
+ if (quote) {
+ Jim_AppendString(interp, strObj, "\"", 1);
+ }
+ }
+ return strObj;
+}
+
+static phandle_t
+JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId)
+{
+ STARTUPINFO startInfo;
+ PROCESS_INFORMATION procInfo;
+ HANDLE hProcess;
+ char execPath[MAX_PATH];
+ phandle_t phandle = INVALID_HANDLE_VALUE;
+ Jim_Obj *cmdLineObj;
+ char *winenv;
+
+ if (JimWinFindExecutable(argv[0], execPath) < 0) {
+ return phandle;
+ }
+ argv[0] = execPath;
+
+ hProcess = GetCurrentProcess();
+ cmdLineObj = JimWinBuildCommandLine(interp, argv);
+
+
+ ZeroMemory(&startInfo, sizeof(startInfo));
+ startInfo.cb = sizeof(startInfo);
+ startInfo.dwFlags = STARTF_USESTDHANDLES;
+ startInfo.hStdInput = INVALID_HANDLE_VALUE;
+ startInfo.hStdOutput= INVALID_HANDLE_VALUE;
+ startInfo.hStdError = INVALID_HANDLE_VALUE;
+
+ if (inputId == -1) {
+ inputId = _fileno(stdin);
+ }
+ DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(inputId), hProcess, &startInfo.hStdInput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (startInfo.hStdInput == INVALID_HANDLE_VALUE) {
+ goto end;
+ }
+
+ if (outputId == -1) {
+ outputId = _fileno(stdout);
+ }
+ DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(outputId), hProcess, &startInfo.hStdOutput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) {
+ goto end;
+ }
+
+
+ if (errorId == -1) {
+ errorId = _fileno(stderr);
+ }
+ DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(errorId), hProcess, &startInfo.hStdError,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (startInfo.hStdError == INVALID_HANDLE_VALUE) {
+ goto end;
+ }
+
+ if (env == NULL) {
+
+ winenv = NULL;
+ }
+ else if (env[0] == NULL) {
+ winenv = (char *)"\0";
+ }
+ else {
+ winenv = env[0];
+ }
+
+ if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
+ 0, winenv, NULL, &startInfo, &procInfo)) {
+ goto end;
+ }
+
+
+ WaitForInputIdle(procInfo.hProcess, 5000);
+ CloseHandle(procInfo.hThread);
+
+ phandle = procInfo.hProcess;
+
+ end:
+ Jim_FreeNewObj(interp, cmdLineObj);
+ if (startInfo.hStdInput != INVALID_HANDLE_VALUE) {
+ CloseHandle(startInfo.hStdInput);
+ }
+ if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) {
+ CloseHandle(startInfo.hStdOutput);
+ }
+ if (startInfo.hStdError != INVALID_HANDLE_VALUE) {
+ CloseHandle(startInfo.hStdError);
+ }
+ return phandle;
+}
+
+#else
+
+static char **JimOriginalEnviron(void)
+{
+ return Jim_GetEnviron();
+}
+
+static char **JimSaveEnv(char **env)
+{
+ char **saveenv = Jim_GetEnviron();
+ Jim_SetEnviron(env);
+ return saveenv;
+}
+
+static void JimRestoreEnv(char **env)
+{
+ JimFreeEnv(Jim_GetEnviron(), env);
+ Jim_SetEnviron(env);
+}
+#endif
+#endif
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+struct clock_options {
+ int gmt;
+ const char *format;
+};
+
+static int parse_clock_options(Jim_Interp *interp, int argc, Jim_Obj *const *argv, struct clock_options *opts)
+{
+ static const char * const options[] = { "-gmt", "-format", NULL };
+ enum { OPT_GMT, OPT_FORMAT, };
+ int i;
+
+ for (i = 0; i < argc; i += 2) {
+ int option;
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_GMT:
+ if (Jim_GetBoolean(interp, argv[i + 1], &opts->gmt) != JIM_OK) {
+ return JIM_ERR;
+ }
+ break;
+ case OPT_FORMAT:
+ opts->format = Jim_String(argv[i + 1]);
+ break;
+ }
+ }
+ return JIM_OK;
+}
+
+static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+
+ char buf[100];
+ time_t t;
+ jim_wide seconds;
+ struct clock_options options = { 0, "%a %b %d %H:%M:%S %Z %Y" };
+ struct tm *tm;
+
+ if (Jim_GetWide(interp, argv[0], &seconds) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (argc % 2 == 0) {
+ return -1;
+ }
+ if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
+ return JIM_ERR;
+ }
+
+ t = seconds;
+ tm = options.gmt ? gmtime(&t) : localtime(&t);
+
+ if (tm == NULL || strftime(buf, sizeof(buf), options.format, tm) == 0) {
+ Jim_SetResultString(interp, "format string too long or invalid time", -1);
+ return JIM_ERR;
+ }
+
+ Jim_SetResultString(interp, buf, -1);
+
+ return JIM_OK;
+}
+
+#ifdef HAVE_STRPTIME
+static time_t jim_timegm(const struct tm *tm)
+{
+ int m = tm->tm_mon + 1;
+ int y = 1900 + tm->tm_year - (m <= 2);
+ int era = (y >= 0 ? y : y - 399) / 400;
+ unsigned yoe = (unsigned)(y - era * 400);
+ unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + tm->tm_mday - 1;
+ unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
+ long days = (era * 146097 + (int)doe - 719468);
+ int secs = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
+
+ return days * 24 * 60 * 60 + secs;
+}
+
+static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ char *pt;
+ struct tm tm;
+ time_t now = time(NULL);
+
+ struct clock_options options = { 0, NULL };
+
+ if (argc % 2 == 0) {
+ return -1;
+ }
+
+ if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
+ return JIM_ERR;
+ }
+ if (options.format == NULL) {
+ return -1;
+ }
+
+ localtime_r(&now, &tm);
+
+ pt = strptime(Jim_String(argv[0]), options.format, &tm);
+ if (pt == 0 || *pt != 0) {
+ Jim_SetResultString(interp, "Failed to parse time according to format", -1);
+ return JIM_ERR;
+ }
+
+
+ tm.tm_isdst = options.gmt ? 0 : -1;
+ Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
+
+ return JIM_OK;
+}
+#endif
+
+static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000);
+ return JIM_OK;
+}
+
+static int clock_cmd_clicks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW));
+ return JIM_OK;
+}
+
+static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME));
+ return JIM_OK;
+}
+
+static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000);
+ return JIM_OK;
+}
+
+static const jim_subcmd_type clock_command_table[] = {
+ { "clicks",
+ NULL,
+ clock_cmd_clicks,
+ 0,
+ 0,
+
+ },
+ { "format",
+ "seconds ?-format string? ?-gmt boolean?",
+ clock_cmd_format,
+ 1,
+ 5,
+
+ },
+ { "microseconds",
+ NULL,
+ clock_cmd_micros,
+ 0,
+ 0,
+
+ },
+ { "milliseconds",
+ NULL,
+ clock_cmd_millis,
+ 0,
+ 0,
+
+ },
+#ifdef HAVE_STRPTIME
+ { "scan",
+ "str -format format ?-gmt boolean?",
+ clock_cmd_scan,
+ 3,
+ 5,
+
+ },
+#endif
+ { "seconds",
+ NULL,
+ clock_cmd_seconds,
+ 0,
+ 0,
+
+ },
+ { NULL }
+};
+
+int Jim_clockInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "clock");
+ Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
+ return JIM_OK;
+}
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+
+ Jim_Obj *dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
+ Jim_SetResultInt(interp, dictObj && Jim_DictSize(interp, dictObj) != -1);
+ return JIM_OK;
+}
+
+static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+ Jim_Obj *patternObj;
+
+ if (!objPtr) {
+ return JIM_OK;
+ }
+
+ patternObj = (argc == 1) ? NULL : argv[1];
+
+
+ if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) {
+ if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) {
+
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ }
+
+ return Jim_DictMatchTypes(interp, objPtr, patternObj, JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS | JIM_DICTMATCH_VALUES);
+}
+
+static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+ if (!objPtr) {
+ return JIM_OK;
+ }
+
+ return Jim_DictMatchTypes(interp, objPtr, argc == 1 ? NULL : argv[1], JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS);
+}
+
+static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ int len;
+ Jim_Obj *resultObj;
+ Jim_Obj *objPtr;
+ Jim_Obj **dictValuesObj;
+
+ if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
+
+ Jim_UnsetVariable(interp, argv[0], JIM_NONE);
+ return JIM_OK;
+ }
+
+ objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+ if (objPtr == NULL) {
+
+ return JIM_OK;
+ }
+
+ dictValuesObj = Jim_DictPairs(interp, objPtr, &len);
+ if (dictValuesObj == NULL) {
+
+ Jim_SetResultString(interp, "", -1);
+ return JIM_OK;
+ }
+
+
+ resultObj = Jim_NewDictObj(interp, NULL, 0);
+
+ for (i = 0; i < len; i += 2) {
+ if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
+ Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
+ }
+ }
+
+ Jim_SetVariable(interp, argv[0], resultObj);
+ return JIM_OK;
+}
+
+static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int len = 0;
+
+
+ objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+ if (objPtr) {
+ len = Jim_DictSize(interp, objPtr);
+ if (len < 0) {
+
+ Jim_SetResultInt(interp, 0);
+ return JIM_OK;
+ }
+ }
+
+ Jim_SetResultInt(interp, len);
+
+ return JIM_OK;
+}
+
+static int array_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+ if (objPtr) {
+ return Jim_DictInfo(interp, objPtr);
+ }
+ Jim_SetResultFormatted(interp, "\"%#s\" isn't an array", argv[0], NULL);
+ return JIM_ERR;
+}
+
+static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ int len;
+ Jim_Obj *listObj = argv[1];
+ Jim_Obj *dictObj;
+
+ len = Jim_ListLength(interp, listObj);
+ if (len % 2) {
+ Jim_SetResultString(interp, "list must have an even number of elements", -1);
+ return JIM_ERR;
+ }
+
+ dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
+ if (!dictObj) {
+
+ return Jim_SetVariable(interp, argv[0], listObj);
+ }
+ else if (Jim_DictSize(interp, dictObj) < 0) {
+ return JIM_ERR;
+ }
+
+ if (Jim_IsShared(dictObj)) {
+ dictObj = Jim_DuplicateObj(interp, dictObj);
+ }
+
+ for (i = 0; i < len; i += 2) {
+ Jim_Obj *nameObj;
+ Jim_Obj *valueObj;
+
+ Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE);
+ Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE);
+
+ Jim_DictAddElement(interp, dictObj, nameObj, valueObj);
+ }
+ return Jim_SetVariable(interp, argv[0], dictObj);
+}
+
+static const jim_subcmd_type array_command_table[] = {
+ { "exists",
+ "arrayName",
+ array_cmd_exists,
+ 1,
+ 1,
+
+ },
+ { "get",
+ "arrayName ?pattern?",
+ array_cmd_get,
+ 1,
+ 2,
+
+ },
+ { "names",
+ "arrayName ?pattern?",
+ array_cmd_names,
+ 1,
+ 2,
+
+ },
+ { "set",
+ "arrayName list",
+ array_cmd_set,
+ 2,
+ 2,
+
+ },
+ { "size",
+ "arrayName",
+ array_cmd_size,
+ 1,
+ 1,
+
+ },
+ { "stat",
+ "arrayName",
+ array_cmd_stat,
+ 1,
+ 1,
+
+ },
+ { "unset",
+ "arrayName ?pattern?",
+ array_cmd_unset,
+ 1,
+ 2,
+
+ },
+ { NULL
+ }
+};
+
+int Jim_arrayInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "array");
+ Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
+ return JIM_OK;
+}
+int Jim_InitStaticExtensions(Jim_Interp *interp)
+{
+extern int Jim_bootstrapInit(Jim_Interp *);
+extern int Jim_aioInit(Jim_Interp *);
+extern int Jim_readdirInit(Jim_Interp *);
+extern int Jim_regexpInit(Jim_Interp *);
+extern int Jim_fileInit(Jim_Interp *);
+extern int Jim_globInit(Jim_Interp *);
+extern int Jim_execInit(Jim_Interp *);
+extern int Jim_clockInit(Jim_Interp *);
+extern int Jim_arrayInit(Jim_Interp *);
+extern int Jim_stdlibInit(Jim_Interp *);
+extern int Jim_tclcompatInit(Jim_Interp *);
+Jim_bootstrapInit(interp);
+Jim_aioInit(interp);
+Jim_readdirInit(interp);
+Jim_regexpInit(interp);
+Jim_fileInit(interp);
+Jim_globInit(interp);
+Jim_execInit(interp);
+Jim_clockInit(interp);
+Jim_arrayInit(interp);
+Jim_stdlibInit(interp);
+Jim_tclcompatInit(interp);
+return JIM_OK;
+}
+#ifndef JIM_TINY
+#define JIM_OPTIMIZATION
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <limits.h>
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+#include <setjmp.h>
+
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+#ifdef HAVE_CRT_EXTERNS_H
+#include <crt_externs.h>
+#endif
+
+
+#include <math.h>
+
+
+
+
+
+#ifndef TCL_LIBRARY
+#define TCL_LIBRARY "."
+#endif
+#ifndef TCL_PLATFORM_OS
+#define TCL_PLATFORM_OS "unknown"
+#endif
+#ifndef TCL_PLATFORM_PLATFORM
+#define TCL_PLATFORM_PLATFORM "unknown"
+#endif
+#ifndef TCL_PLATFORM_PATH_SEPARATOR
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#endif
+
+
+
+
+
+
+
+#ifdef JIM_MAINTAINER
+#define JIM_DEBUG_COMMAND
+#define JIM_DEBUG_PANIC
+#endif
+
+
+
+#define JIM_INTEGER_SPACE 24
+
+#if defined(DEBUG_SHOW_SCRIPT) || defined(DEBUG_SHOW_SCRIPT_TOKENS) || defined(JIM_DEBUG_COMMAND) || defined(DEBUG_SHOW_SUBST)
+static const char *jim_tt_name(int type);
+#endif
+
+#ifdef JIM_DEBUG_PANIC
+static void JimPanicDump(int fail_condition, const char *fmt, ...);
+#define JimPanic(X) JimPanicDump X
+#else
+#define JimPanic(X)
+#endif
+
+#ifdef JIM_OPTIMIZATION
+static int JimIsWide(Jim_Obj *objPtr);
+#define JIM_IF_OPTIM(X) X
+#else
+#define JIM_IF_OPTIM(X)
+#endif
+
+
+static char JimEmptyStringRep[] = "";
+
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action);
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
+ int flags);
+static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *const *indexv, int indexc,
+ Jim_Obj **resultObj, int flags);
+static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+ const char *prefix, const char *const *tablePtr, const char *name);
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
+static int JimSign(jim_wide w);
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
+static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv);
+static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+#define JIM_DICT_SUGAR 100
+
+
+
+
+#define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
+
+#define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
+
+static int utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+ int l = utf8_tounicode(s, uc);
+ if (upper) {
+ *uc = utf8_upper(*uc);
+ }
+ return l;
+}
+
+static Jim_Obj *JimPushInterpObjImpl(Jim_Obj **iop, Jim_Obj *no)
+{
+ Jim_Obj *io = *iop;
+ Jim_IncrRefCount(no);
+ *iop = no;
+ return io;
+}
+
+#define JimPushInterpObj(IO, NO) JimPushInterpObjImpl(&(IO), NO)
+#define JimPopInterpObj(I, IO, SO) do { Jim_DecrRefCount(I, IO); IO = SO; } while (0)
+
+
+#define JIM_CHARSET_SCAN 2
+#define JIM_CHARSET_GLOB 0
+
+static const char *JimCharsetMatch(const char *pattern, int plen, int c, int flags)
+{
+ int not = 0;
+ int pchar;
+ int match = 0;
+ int nocase = 0;
+ int n;
+
+ if (flags & JIM_NOCASE) {
+ nocase++;
+ c = utf8_upper(c);
+ }
+
+ if (flags & JIM_CHARSET_SCAN) {
+ if (*pattern == '^') {
+ not++;
+ pattern++;
+ plen--;
+ }
+
+
+ if (*pattern == ']') {
+ goto first;
+ }
+ }
+
+ while (plen && *pattern != ']') {
+
+ if (pattern[0] == '\\') {
+first:
+ n = utf8_tounicode_case(pattern, &pchar, nocase);
+ pattern += n;
+ plen -= n;
+ }
+ else {
+
+ int start;
+ int end;
+
+ n = utf8_tounicode_case(pattern, &start, nocase);
+ pattern += n;
+ plen -= n;
+ if (pattern[0] == '-' && plen > 1) {
+
+ n = 1 + utf8_tounicode_case(pattern + 1, &end, nocase);
+ pattern += n;
+ plen -= n;
+
+
+ if ((c >= start && c <= end) || (c >= end && c <= start)) {
+ match = 1;
+ }
+ continue;
+ }
+ pchar = start;
+ }
+
+ if (pchar == c) {
+ match = 1;
+ }
+ }
+ if (not) {
+ match = !match;
+ }
+
+ return match ? pattern : NULL;
+}
+
+
+
+static int JimGlobMatch(const char *pattern, int plen, const char *string, int slen, int nocase)
+{
+ int c;
+ int pchar;
+ int n;
+ const char *p;
+ while (plen) {
+ switch (pattern[0]) {
+ case '*':
+ while (pattern[1] == '*' && plen) {
+ pattern++;
+ plen--;
+ }
+ pattern++;
+ plen--;
+ if (!plen) {
+ return 1;
+ }
+ while (slen) {
+
+ if (JimGlobMatch(pattern, plen, string, slen, nocase))
+ return 1;
+ n = utf8_tounicode(string, &c);
+ string += n;
+ slen -= n;
+ }
+ return 0;
+
+ case '?':
+ n = utf8_tounicode(string, &c);
+ string += n;
+ slen -= n;
+ break;
+
+ case '[': {
+ n = utf8_tounicode(string, &c);
+ string += n;
+ slen -= n;
+ p = JimCharsetMatch(pattern + 1, plen - 1, c, nocase ? JIM_NOCASE : 0);
+ if (!p) {
+ return 0;
+ }
+ plen -= p - pattern;
+ pattern = p;
+
+ if (!plen) {
+
+ continue;
+ }
+ break;
+ }
+ case '\\':
+ if (pattern[1]) {
+ pattern++;
+ plen--;
+ }
+
+ default:
+ n = utf8_tounicode_case(string, &c, nocase);
+ string += n;
+ slen -= n;
+ utf8_tounicode_case(pattern, &pchar, nocase);
+ if (pchar != c) {
+ return 0;
+ }
+ break;
+ }
+ n = utf8_tounicode_case(pattern, &pchar, nocase);
+ pattern += n;
+ plen -= n;
+ if (!slen) {
+ while (*pattern == '*' && plen) {
+ pattern++;
+ plen--;
+ }
+ break;
+ }
+ }
+ if (!plen && !slen) {
+ return 1;
+ }
+ return 0;
+}
+
+static int JimStringCompareUtf8(const char *s1, int l1, const char *s2, int l2, int nocase)
+{
+ int minlen = l1;
+ if (l2 < l1) {
+ minlen = l2;
+ }
+ while (minlen) {
+ int c1, c2;
+ s1 += utf8_tounicode_case(s1, &c1, nocase);
+ s2 += utf8_tounicode_case(s2, &c2, nocase);
+ if (c1 != c2) {
+ return JimSign(c1 - c2);
+ }
+ minlen--;
+ }
+
+ if (l1 < l2) {
+ return -1;
+ }
+ if (l1 > l2) {
+ return 1;
+ }
+ return 0;
+}
+
+static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
+{
+ int i;
+ int l1bytelen;
+
+ if (!l1 || !l2 || l1 > l2) {
+ return -1;
+ }
+ if (idx < 0)
+ idx = 0;
+ s2 += utf8_index(s2, idx);
+
+ l1bytelen = utf8_index(s1, l1);
+
+ for (i = idx; i <= l2 - l1; i++) {
+ int c;
+ if (memcmp(s2, s1, l1bytelen) == 0) {
+ return i;
+ }
+ s2 += utf8_tounicode(s2, &c);
+ }
+ return -1;
+}
+
+static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
+{
+ const char *p;
+
+ if (!l1 || !l2 || l1 > l2)
+ return -1;
+
+
+ for (p = s2 + l2 - 1; p != s2 - 1; p--) {
+ if (*p == *s1 && memcmp(s1, p, l1) == 0) {
+ return p - s2;
+ }
+ }
+ return -1;
+}
+
+#ifdef JIM_UTF8
+static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
+{
+ int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
+ if (n > 0) {
+ n = utf8_strlen(s2, n);
+ }
+ return n;
+}
+#endif
+
+static int JimCheckConversion(const char *str, const char *endptr)
+{
+ if (str[0] == '\0' || str == endptr) {
+ return JIM_ERR;
+ }
+
+ if (endptr[0] != '\0') {
+ while (*endptr) {
+ if (!isspace(UCHAR(*endptr))) {
+ return JIM_ERR;
+ }
+ endptr++;
+ }
+ }
+ return JIM_OK;
+}
+
+static int JimNumberBase(const char *str, int *base, int *sign)
+{
+ int i = 0;
+
+ *base = 0;
+
+ while (isspace(UCHAR(str[i]))) {
+ i++;
+ }
+
+ if (str[i] == '-') {
+ *sign = -1;
+ i++;
+ }
+ else {
+ if (str[i] == '+') {
+ i++;
+ }
+ *sign = 1;
+ }
+
+ if (str[i] != '0') {
+
+ return 0;
+ }
+
+
+ switch (str[i + 1]) {
+ case 'x': case 'X': *base = 16; break;
+ case 'o': case 'O': *base = 8; break;
+ case 'b': case 'B': *base = 2; break;
+ case 'd': case 'D': *base = 10; break;
+ default: return 0;
+ }
+ i += 2;
+
+ if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) {
+
+ return i;
+ }
+
+ *base = 0;
+ return 0;
+}
+
+static long jim_strtol(const char *str, char **endptr)
+{
+ int sign;
+ int base;
+ int i = JimNumberBase(str, &base, &sign);
+
+ if (base != 0) {
+ long value = strtol(str + i, endptr, base);
+ if (endptr == NULL || *endptr != str + i) {
+ return value * sign;
+ }
+ }
+
+
+ return strtol(str, endptr, 10);
+}
+
+
+static jim_wide jim_strtoull(const char *str, char **endptr)
+{
+#ifdef HAVE_LONG_LONG
+ int sign;
+ int base;
+ int i = JimNumberBase(str, &base, &sign);
+
+ if (base != 0) {
+ jim_wide value = strtoull(str + i, endptr, base);
+ if (endptr == NULL || *endptr != str + i) {
+ return value * sign;
+ }
+ }
+
+
+ return strtoull(str, endptr, 10);
+#else
+ return (unsigned long)jim_strtol(str, endptr);
+#endif
+}
+
+int Jim_StringToWide(const char *str, jim_wide * widePtr, int base)
+{
+ char *endptr;
+
+ if (base) {
+ *widePtr = strtoull(str, &endptr, base);
+ }
+ else {
+ *widePtr = jim_strtoull(str, &endptr);
+ }
+
+ return JimCheckConversion(str, endptr);
+}
+
+int Jim_StringToDouble(const char *str, double *doublePtr)
+{
+ char *endptr;
+
+
+ errno = 0;
+
+ *doublePtr = strtod(str, &endptr);
+
+ return JimCheckConversion(str, endptr);
+}
+
+static jim_wide JimPowWide(jim_wide b, jim_wide e)
+{
+ jim_wide res = 1;
+
+
+ if (b == 1) {
+
+ return 1;
+ }
+ if (e < 0) {
+ if (b != -1) {
+ return 0;
+ }
+ e = -e;
+ }
+ while (e)
+ {
+ if (e & 1) {
+ res *= b;
+ }
+ e >>= 1;
+ b *= b;
+ }
+ return res;
+}
+
+#ifdef JIM_DEBUG_PANIC
+static void JimPanicDump(int condition, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!condition) {
+ return;
+ }
+
+ va_start(ap, fmt);
+
+ fprintf(stderr, "\nJIM INTERPRETER PANIC: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n\n");
+ va_end(ap);
+
+#if defined(HAVE_BACKTRACE)
+ {
+ void *array[40];
+ int size, i;
+ char **strings;
+
+ size = backtrace(array, 40);
+ strings = backtrace_symbols(array, size);
+ for (i = 0; i < size; i++)
+ fprintf(stderr, "[backtrace] %s\n", strings[i]);
+ fprintf(stderr, "[backtrace] Include the above lines and the output\n");
+ fprintf(stderr, "[backtrace] of 'nm <executable>' in the bug report.\n");
+ }
+#endif
+
+ exit(1);
+}
+#endif
+
+
+void *JimDefaultAllocator(void *ptr, size_t size)
+{
+ if (size == 0) {
+ free(ptr);
+ return NULL;
+ }
+ else if (ptr) {
+ return realloc(ptr, size);
+ }
+ else {
+ return malloc(size);
+ }
+}
+
+void *(*Jim_Allocator)(void *ptr, size_t size) = JimDefaultAllocator;
+
+char *Jim_StrDup(const char *s)
+{
+ return Jim_StrDupLen(s, strlen(s));
+}
+
+char *Jim_StrDupLen(const char *s, int l)
+{
+ char *copy = Jim_Alloc(l + 1);
+
+ memcpy(copy, s, l);
+ copy[l] = 0;
+ return copy;
+}
+
+
+jim_wide Jim_GetTimeUsec(unsigned type)
+{
+ long long now;
+ struct timeval tv;
+
+#if defined(HAVE_CLOCK_GETTIME)
+ struct timespec ts;
+
+ if (clock_gettime(type, &ts) == 0) {
+ now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
+ }
+ else
+#endif
+ {
+ gettimeofday(&tv, NULL);
+
+ now = tv.tv_sec * 1000000LL + tv.tv_usec;
+ }
+
+ return now;
+}
+
+
+
+
+
+static void JimExpandHashTableIfNeeded(Jim_HashTable *ht);
+static unsigned int JimHashTableNextPower(unsigned int size);
+static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace);
+
+
+
+
+unsigned int Jim_IntHashFunction(unsigned int key)
+{
+ key += ~(key << 15);
+ key ^= (key >> 10);
+ key += (key << 3);
+ key ^= (key >> 6);
+ key += ~(key << 11);
+ key ^= (key >> 16);
+ return key;
+}
+
+
+unsigned int Jim_GenHashFunction(const unsigned char *string, int length)
+{
+ unsigned result = 0;
+ string += length;
+ while (length--) {
+ result += (result << 3) + (unsigned char)(*--string);
+ }
+ return result;
+}
+
+
+
+static void JimResetHashTable(Jim_HashTable *ht)
+{
+ ht->table = NULL;
+ ht->size = 0;
+ ht->sizemask = 0;
+ ht->used = 0;
+ ht->collisions = 0;
+#ifdef JIM_RANDOMISE_HASH
+ ht->uniq = (rand() ^ time(NULL) ^ clock());
+#else
+ ht->uniq = 0;
+#endif
+}
+
+static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter)
+{
+ iter->ht = ht;
+ iter->index = -1;
+ iter->entry = NULL;
+ iter->nextEntry = NULL;
+}
+
+
+int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
+{
+ JimResetHashTable(ht);
+ ht->type = type;
+ ht->privdata = privDataPtr;
+ return JIM_OK;
+}
+
+
+void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
+{
+ Jim_HashTable n;
+ unsigned int realsize = JimHashTableNextPower(size), i;
+
+ if (size <= ht->used)
+ return;
+
+ Jim_InitHashTable(&n, ht->type, ht->privdata);
+ n.size = realsize;
+ n.sizemask = realsize - 1;
+ n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
+
+ n.uniq = ht->uniq;
+
+
+ memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
+
+ n.used = ht->used;
+ for (i = 0; ht->used > 0; i++) {
+ Jim_HashEntry *he, *nextHe;
+
+ if (ht->table[i] == NULL)
+ continue;
+
+
+ he = ht->table[i];
+ while (he) {
+ unsigned int h;
+
+ nextHe = he->next;
+
+ h = Jim_HashKey(ht, he->key) & n.sizemask;
+ he->next = n.table[h];
+ n.table[h] = he;
+ ht->used--;
+
+ he = nextHe;
+ }
+ }
+ assert(ht->used == 0);
+ Jim_Free(ht->table);
+
+
+ *ht = n;
+}
+
+int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+ Jim_HashEntry *entry = JimInsertHashEntry(ht, key, 0);;
+ if (entry == NULL)
+ return JIM_ERR;
+
+
+ Jim_SetHashKey(ht, entry, key);
+ Jim_SetHashVal(ht, entry, val);
+ return JIM_OK;
+}
+
+
+int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+ int existed;
+ Jim_HashEntry *entry;
+
+ entry = JimInsertHashEntry(ht, key, 1);
+ if (entry->key) {
+ if (ht->type->valDestructor && ht->type->valDup) {
+ void *newval = ht->type->valDup(ht->privdata, val);
+ ht->type->valDestructor(ht->privdata, entry->u.val);
+ entry->u.val = newval;
+ }
+ else {
+ Jim_FreeEntryVal(ht, entry);
+ Jim_SetHashVal(ht, entry, val);
+ }
+ existed = 1;
+ }
+ else {
+
+ Jim_SetHashKey(ht, entry, key);
+ Jim_SetHashVal(ht, entry, val);
+ existed = 0;
+ }
+
+ return existed;
+}
+
+int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
+{
+ if (ht->used) {
+ unsigned int h = Jim_HashKey(ht, key) & ht->sizemask;
+ Jim_HashEntry *prevHe = NULL;
+ Jim_HashEntry *he = ht->table[h];
+
+ while (he) {
+ if (Jim_CompareHashKeys(ht, key, he->key)) {
+
+ if (prevHe)
+ prevHe->next = he->next;
+ else
+ ht->table[h] = he->next;
+ ht->used--;
+ Jim_FreeEntryKey(ht, he);
+ Jim_FreeEntryVal(ht, he);
+ Jim_Free(he);
+ return JIM_OK;
+ }
+ prevHe = he;
+ he = he->next;
+ }
+ }
+
+ return JIM_ERR;
+}
+
+void Jim_ClearHashTable(Jim_HashTable *ht)
+{
+ unsigned int i;
+
+
+ for (i = 0; ht->used > 0; i++) {
+ Jim_HashEntry *he, *nextHe;
+
+ he = ht->table[i];
+ while (he) {
+ nextHe = he->next;
+ Jim_FreeEntryKey(ht, he);
+ Jim_FreeEntryVal(ht, he);
+ Jim_Free(he);
+ ht->used--;
+ he = nextHe;
+ }
+ ht->table[i] = NULL;
+ }
+}
+
+int Jim_FreeHashTable(Jim_HashTable *ht)
+{
+ Jim_ClearHashTable(ht);
+
+ Jim_Free(ht->table);
+
+ JimResetHashTable(ht);
+ return JIM_OK;
+}
+
+Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
+{
+ Jim_HashEntry *he;
+ unsigned int h;
+
+ if (ht->used == 0)
+ return NULL;
+ h = Jim_HashKey(ht, key) & ht->sizemask;
+ he = ht->table[h];
+ while (he) {
+ if (Jim_CompareHashKeys(ht, key, he->key))
+ return he;
+ he = he->next;
+ }
+ return NULL;
+}
+
+Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
+{
+ Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
+ JimInitHashTableIterator(ht, iter);
+ return iter;
+}
+
+Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
+{
+ while (1) {
+ if (iter->entry == NULL) {
+ iter->index++;
+ if (iter->index >= (signed)iter->ht->size)
+ break;
+ iter->entry = iter->ht->table[iter->index];
+ }
+ else {
+ iter->entry = iter->nextEntry;
+ }
+ if (iter->entry) {
+ iter->nextEntry = iter->entry->next;
+ return iter->entry;
+ }
+ }
+ return NULL;
+}
+
+
+
+
+static void JimExpandHashTableIfNeeded(Jim_HashTable *ht)
+{
+ if (ht->size == 0)
+ Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
+ if (ht->size == ht->used)
+ Jim_ExpandHashTable(ht, ht->size * 2);
+}
+
+
+static unsigned int JimHashTableNextPower(unsigned int size)
+{
+ unsigned int i = JIM_HT_INITIAL_SIZE;
+
+ if (size >= 2147483648U)
+ return 2147483648U;
+ while (1) {
+ if (i >= size)
+ return i;
+ i *= 2;
+ }
+}
+
+static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace)
+{
+ unsigned int h;
+ Jim_HashEntry *he;
+
+
+ JimExpandHashTableIfNeeded(ht);
+
+
+ h = Jim_HashKey(ht, key) & ht->sizemask;
+
+ he = ht->table[h];
+ while (he) {
+ if (Jim_CompareHashKeys(ht, key, he->key))
+ return replace ? he : NULL;
+ he = he->next;
+ }
+
+
+ he = Jim_Alloc(sizeof(*he));
+ he->next = ht->table[h];
+ ht->table[h] = he;
+ ht->used++;
+ he->key = NULL;
+
+ return he;
+}
+
+
+
+static unsigned int JimStringCopyHTHashFunction(const void *key)
+{
+ return Jim_GenHashFunction(key, strlen(key));
+}
+
+static void *JimStringCopyHTDup(void *privdata, const void *key)
+{
+ return Jim_StrDup(key);
+}
+
+static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+ return strcmp(key1, key2) == 0;
+}
+
+static void JimStringCopyHTKeyDestructor(void *privdata, void *key)
+{
+ Jim_Free(key);
+}
+
+static const Jim_HashTableType JimPackageHashTableType = {
+ JimStringCopyHTHashFunction,
+ JimStringCopyHTDup,
+ NULL,
+ JimStringCopyHTKeyCompare,
+ JimStringCopyHTKeyDestructor,
+ NULL
+};
+
+typedef struct AssocDataValue
+{
+ Jim_InterpDeleteProc *delProc;
+ void *data;
+} AssocDataValue;
+
+static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
+{
+ AssocDataValue *assocPtr = (AssocDataValue *) data;
+
+ if (assocPtr->delProc != NULL)
+ assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
+ Jim_Free(data);
+}
+
+static const Jim_HashTableType JimAssocDataHashTableType = {
+ JimStringCopyHTHashFunction,
+ JimStringCopyHTDup,
+ NULL,
+ JimStringCopyHTKeyCompare,
+ JimStringCopyHTKeyDestructor,
+ JimAssocDataHashTableValueDestructor
+};
+
+void Jim_InitStack(Jim_Stack *stack)
+{
+ stack->len = 0;
+ stack->maxlen = 0;
+ stack->vector = NULL;
+}
+
+void Jim_FreeStack(Jim_Stack *stack)
+{
+ Jim_Free(stack->vector);
+}
+
+int Jim_StackLen(Jim_Stack *stack)
+{
+ return stack->len;
+}
+
+void Jim_StackPush(Jim_Stack *stack, void *element)
+{
+ int neededLen = stack->len + 1;
+
+ if (neededLen > stack->maxlen) {
+ stack->maxlen = neededLen < 20 ? 20 : neededLen * 2;
+ stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen);
+ }
+ stack->vector[stack->len] = element;
+ stack->len++;
+}
+
+void *Jim_StackPop(Jim_Stack *stack)
+{
+ if (stack->len == 0)
+ return NULL;
+ stack->len--;
+ return stack->vector[stack->len];
+}
+
+void *Jim_StackPeek(Jim_Stack *stack)
+{
+ if (stack->len == 0)
+ return NULL;
+ return stack->vector[stack->len - 1];
+}
+
+void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr))
+{
+ int i;
+
+ for (i = 0; i < stack->len; i++)
+ freeFunc(stack->vector[i]);
+}
+
+
+
+#define JIM_TT_NONE 0
+#define JIM_TT_STR 1
+#define JIM_TT_ESC 2
+#define JIM_TT_VAR 3
+#define JIM_TT_DICTSUGAR 4
+#define JIM_TT_CMD 5
+
+#define JIM_TT_SEP 6
+#define JIM_TT_EOL 7
+#define JIM_TT_EOF 8
+
+#define JIM_TT_LINE 9
+#define JIM_TT_WORD 10
+
+
+#define JIM_TT_SUBEXPR_START 11
+#define JIM_TT_SUBEXPR_END 12
+#define JIM_TT_SUBEXPR_COMMA 13
+#define JIM_TT_EXPR_INT 14
+#define JIM_TT_EXPR_DOUBLE 15
+#define JIM_TT_EXPR_BOOLEAN 16
+
+#define JIM_TT_EXPRSUGAR 17
+
+
+#define JIM_TT_EXPR_OP 20
+
+#define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
+
+#define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA)
+
+#define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)
+
+struct JimParseMissing {
+ int ch;
+ int line;
+};
+
+struct JimParserCtx
+{
+ const char *p;
+ int len;
+ int linenr;
+ const char *tstart;
+ const char *tend;
+ int tline;
+ int tt;
+ int eof;
+ int inquote;
+ int comment;
+ struct JimParseMissing missing;
+ const char *errmsg;
+};
+
+static int JimParseScript(struct JimParserCtx *pc);
+static int JimParseSep(struct JimParserCtx *pc);
+static int JimParseEol(struct JimParserCtx *pc);
+static int JimParseCmd(struct JimParserCtx *pc);
+static int JimParseQuote(struct JimParserCtx *pc);
+static int JimParseVar(struct JimParserCtx *pc);
+static int JimParseBrace(struct JimParserCtx *pc);
+static int JimParseStr(struct JimParserCtx *pc);
+static int JimParseComment(struct JimParserCtx *pc);
+static void JimParseSubCmd(struct JimParserCtx *pc);
+static int JimParseSubQuote(struct JimParserCtx *pc);
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
+
+static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
+{
+ pc->p = prg;
+ pc->len = len;
+ pc->tstart = NULL;
+ pc->tend = NULL;
+ pc->tline = 0;
+ pc->tt = JIM_TT_NONE;
+ pc->eof = 0;
+ pc->inquote = 0;
+ pc->linenr = linenr;
+ pc->comment = 1;
+ pc->missing.ch = ' ';
+ pc->missing.line = linenr;
+}
+
+static int JimParseScript(struct JimParserCtx *pc)
+{
+ while (1) {
+ if (!pc->len) {
+ pc->tstart = pc->p;
+ pc->tend = pc->p - 1;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_EOL;
+ if (pc->inquote) {
+ pc->missing.ch = '"';
+ }
+ pc->eof = 1;
+ return JIM_OK;
+ }
+ switch (*(pc->p)) {
+ case '\\':
+ if (*(pc->p + 1) == '\n' && !pc->inquote) {
+ return JimParseSep(pc);
+ }
+ pc->comment = 0;
+ return JimParseStr(pc);
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\f':
+ if (!pc->inquote)
+ return JimParseSep(pc);
+ pc->comment = 0;
+ return JimParseStr(pc);
+ case '\n':
+ case ';':
+ pc->comment = 1;
+ if (!pc->inquote)
+ return JimParseEol(pc);
+ return JimParseStr(pc);
+ case '[':
+ pc->comment = 0;
+ return JimParseCmd(pc);
+ case '$':
+ pc->comment = 0;
+ if (JimParseVar(pc) == JIM_ERR) {
+
+ pc->tstart = pc->tend = pc->p++;
+ pc->len--;
+ pc->tt = JIM_TT_ESC;
+ }
+ return JIM_OK;
+ case '#':
+ if (pc->comment) {
+ JimParseComment(pc);
+ continue;
+ }
+ return JimParseStr(pc);
+ default:
+ pc->comment = 0;
+ return JimParseStr(pc);
+ }
+ return JIM_OK;
+ }
+}
+
+static int JimParseSep(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (isspace(UCHAR(*pc->p)) || (*pc->p == '\\' && *(pc->p + 1) == '\n')) {
+ if (*pc->p == '\n') {
+ break;
+ }
+ if (*pc->p == '\\') {
+ pc->p++;
+ pc->len--;
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_SEP;
+ return JIM_OK;
+}
+
+static int JimParseEol(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (isspace(UCHAR(*pc->p)) || *pc->p == ';') {
+ if (*pc->p == '\n')
+ pc->linenr++;
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_EOL;
+ return JIM_OK;
+}
+
+
+static void JimParseSubBrace(struct JimParserCtx *pc)
+{
+ int level = 1;
+
+
+ pc->p++;
+ pc->len--;
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ if (pc->len > 1) {
+ if (*++pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->len--;
+ }
+ break;
+
+ case '{':
+ level++;
+ break;
+
+ case '}':
+ if (--level == 0) {
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return;
+ }
+ break;
+
+ case '\n':
+ pc->linenr++;
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->missing.ch = '{';
+ pc->missing.line = pc->tline;
+ pc->tend = pc->p - 1;
+}
+
+static int JimParseSubQuote(struct JimParserCtx *pc)
+{
+ int tt = JIM_TT_STR;
+ int line = pc->tline;
+
+
+ pc->p++;
+ pc->len--;
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ if (pc->len > 1) {
+ if (*++pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->len--;
+ tt = JIM_TT_ESC;
+ }
+ break;
+
+ case '"':
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return tt;
+
+ case '[':
+ JimParseSubCmd(pc);
+ tt = JIM_TT_ESC;
+ continue;
+
+ case '\n':
+ pc->linenr++;
+ break;
+
+ case '$':
+ tt = JIM_TT_ESC;
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->missing.ch = '"';
+ pc->missing.line = line;
+ pc->tend = pc->p - 1;
+ return tt;
+}
+
+static void JimParseSubCmd(struct JimParserCtx *pc)
+{
+ int level = 1;
+ int startofword = 1;
+ int line = pc->tline;
+
+
+ pc->p++;
+ pc->len--;
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ if (pc->len > 1) {
+ if (*++pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->len--;
+ }
+ break;
+
+ case '[':
+ level++;
+ break;
+
+ case ']':
+ if (--level == 0) {
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return;
+ }
+ break;
+
+ case '"':
+ if (startofword) {
+ JimParseSubQuote(pc);
+ if (pc->missing.ch == '"') {
+ return;
+ }
+ continue;
+ }
+ break;
+
+ case '{':
+ JimParseSubBrace(pc);
+ startofword = 0;
+ continue;
+
+ case '\n':
+ pc->linenr++;
+ break;
+ }
+ startofword = isspace(UCHAR(*pc->p));
+ pc->p++;
+ pc->len--;
+ }
+ pc->missing.ch = '[';
+ pc->missing.line = line;
+ pc->tend = pc->p - 1;
+}
+
+static int JimParseBrace(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p + 1;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_STR;
+ JimParseSubBrace(pc);
+ return JIM_OK;
+}
+
+static int JimParseCmd(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p + 1;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_CMD;
+ JimParseSubCmd(pc);
+ return JIM_OK;
+}
+
+static int JimParseQuote(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p + 1;
+ pc->tline = pc->linenr;
+ pc->tt = JimParseSubQuote(pc);
+ return JIM_OK;
+}
+
+static int JimParseVar(struct JimParserCtx *pc)
+{
+
+ pc->p++;
+ pc->len--;
+
+#ifdef EXPRSUGAR_BRACKET
+ if (*pc->p == '[') {
+
+ JimParseCmd(pc);
+ pc->tt = JIM_TT_EXPRSUGAR;
+ return JIM_OK;
+ }
+#endif
+
+ pc->tstart = pc->p;
+ pc->tt = JIM_TT_VAR;
+ pc->tline = pc->linenr;
+
+ if (*pc->p == '{') {
+ pc->tstart = ++pc->p;
+ pc->len--;
+
+ while (pc->len && *pc->p != '}') {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ if (pc->len) {
+ pc->p++;
+ pc->len--;
+ }
+ }
+ else {
+ while (1) {
+
+ if (pc->p[0] == ':' && pc->p[1] == ':') {
+ while (*pc->p == ':') {
+ pc->p++;
+ pc->len--;
+ }
+ continue;
+ }
+ if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) {
+ pc->p++;
+ pc->len--;
+ continue;
+ }
+ break;
+ }
+
+ if (*pc->p == '(') {
+ int count = 1;
+ const char *paren = NULL;
+
+ pc->tt = JIM_TT_DICTSUGAR;
+
+ while (count && pc->len) {
+ pc->p++;
+ pc->len--;
+ if (*pc->p == '\\' && pc->len >= 1) {
+ pc->p++;
+ pc->len--;
+ }
+ else if (*pc->p == '(') {
+ count++;
+ }
+ else if (*pc->p == ')') {
+ paren = pc->p;
+ count--;
+ }
+ }
+ if (count == 0) {
+ pc->p++;
+ pc->len--;
+ }
+ else if (paren) {
+
+ paren++;
+ pc->len += (pc->p - paren);
+ pc->p = paren;
+ }
+#ifndef EXPRSUGAR_BRACKET
+ if (*pc->tstart == '(') {
+ pc->tt = JIM_TT_EXPRSUGAR;
+ }
+#endif
+ }
+ pc->tend = pc->p - 1;
+ }
+ if (pc->tstart == pc->p) {
+ pc->p--;
+ pc->len++;
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int JimParseStr(struct JimParserCtx *pc)
+{
+ if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
+ pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) {
+
+ if (*pc->p == '{') {
+ return JimParseBrace(pc);
+ }
+ if (*pc->p == '"') {
+ pc->inquote = 1;
+ pc->p++;
+ pc->len--;
+
+ pc->missing.line = pc->tline;
+ }
+ }
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (1) {
+ if (pc->len == 0) {
+ if (pc->inquote) {
+ pc->missing.ch = '"';
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ switch (*pc->p) {
+ case '\\':
+ if (!pc->inquote && *(pc->p + 1) == '\n') {
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ if (pc->len >= 2) {
+ if (*(pc->p + 1) == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ else if (pc->len == 1) {
+
+ pc->missing.ch = '\\';
+ }
+ break;
+ case '(':
+
+ if (pc->len > 1 && pc->p[1] != '$') {
+ break;
+ }
+
+ case ')':
+
+ if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
+ if (pc->p == pc->tstart) {
+
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ break;
+
+ case '$':
+ case '[':
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\f':
+ case ';':
+ if (!pc->inquote) {
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ else if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ break;
+ case '"':
+ if (pc->inquote) {
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ pc->p++;
+ pc->len--;
+ pc->inquote = 0;
+ return JIM_OK;
+ }
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ return JIM_OK;
+}
+
+static int JimParseComment(struct JimParserCtx *pc)
+{
+ while (*pc->p) {
+ if (*pc->p == '\\') {
+ pc->p++;
+ pc->len--;
+ if (pc->len == 0) {
+ pc->missing.ch = '\\';
+ return JIM_OK;
+ }
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ }
+ else if (*pc->p == '\n') {
+ pc->p++;
+ pc->len--;
+ pc->linenr++;
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ return JIM_OK;
+}
+
+
+static int xdigitval(int 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;
+}
+
+static int odigitval(int c)
+{
+ if (c >= '0' && c <= '7')
+ return c - '0';
+ return -1;
+}
+
+static int JimEscape(char *dest, const char *s, int slen)
+{
+ char *p = dest;
+ int i, len;
+
+ for (i = 0; i < slen; i++) {
+ switch (s[i]) {
+ case '\\':
+ switch (s[i + 1]) {
+ case 'a':
+ *p++ = 0x7;
+ i++;
+ break;
+ case 'b':
+ *p++ = 0x8;
+ i++;
+ break;
+ case 'f':
+ *p++ = 0xc;
+ i++;
+ break;
+ case 'n':
+ *p++ = 0xa;
+ i++;
+ break;
+ case 'r':
+ *p++ = 0xd;
+ i++;
+ break;
+ case 't':
+ *p++ = 0x9;
+ i++;
+ break;
+ case 'u':
+ case 'U':
+ case 'x':
+ {
+ unsigned val = 0;
+ int k;
+ int maxchars = 2;
+
+ i++;
+
+ if (s[i] == 'U') {
+ maxchars = 8;
+ }
+ else if (s[i] == 'u') {
+ if (s[i + 1] == '{') {
+ maxchars = 6;
+ i++;
+ }
+ else {
+ maxchars = 4;
+ }
+ }
+
+ for (k = 0; k < maxchars; k++) {
+ int c = xdigitval(s[i + k + 1]);
+ if (c == -1) {
+ break;
+ }
+ val = (val << 4) | c;
+ }
+
+ if (s[i] == '{') {
+ if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') {
+
+ i--;
+ k = 0;
+ }
+ else {
+
+ k++;
+ }
+ }
+ if (k) {
+
+ if (s[i] == 'x') {
+ *p++ = val;
+ }
+ else {
+ p += utf8_fromunicode(p, val);
+ }
+ i += k;
+ break;
+ }
+
+ *p++ = s[i];
+ }
+ break;
+ case 'v':
+ *p++ = 0xb;
+ i++;
+ break;
+ case '\0':
+ *p++ = '\\';
+ i++;
+ break;
+ case '\n':
+
+ *p++ = ' ';
+ do {
+ i++;
+ } while (s[i + 1] == ' ' || s[i + 1] == '\t');
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+
+ {
+ int val = 0;
+ int c = odigitval(s[i + 1]);
+
+ val = c;
+ c = odigitval(s[i + 2]);
+ if (c == -1) {
+ *p++ = val;
+ i++;
+ break;
+ }
+ val = (val * 8) + c;
+ c = odigitval(s[i + 3]);
+ if (c == -1) {
+ *p++ = val;
+ i += 2;
+ break;
+ }
+ val = (val * 8) + c;
+ *p++ = val;
+ i += 3;
+ }
+ break;
+ default:
+ *p++ = s[i + 1];
+ i++;
+ break;
+ }
+ break;
+ default:
+ *p++ = s[i];
+ break;
+ }
+ }
+ len = p - dest;
+ *p = '\0';
+ return len;
+}
+
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc)
+{
+ const char *start, *end;
+ char *token;
+ int len;
+
+ start = pc->tstart;
+ end = pc->tend;
+ len = (end - start) + 1;
+ if (len < 0) {
+ len = 0;
+ }
+ token = Jim_Alloc(len + 1);
+ if (pc->tt != JIM_TT_ESC) {
+
+ memcpy(token, start, len);
+ token[len] = '\0';
+ }
+ else {
+
+ len = JimEscape(token, start, len);
+ }
+
+ return Jim_NewStringObjNoAlloc(interp, token, len);
+}
+
+static int JimParseListSep(struct JimParserCtx *pc);
+static int JimParseListStr(struct JimParserCtx *pc);
+static int JimParseListQuote(struct JimParserCtx *pc);
+
+static int JimParseList(struct JimParserCtx *pc)
+{
+ if (isspace(UCHAR(*pc->p))) {
+ return JimParseListSep(pc);
+ }
+ switch (*pc->p) {
+ case '"':
+ return JimParseListQuote(pc);
+
+ case '{':
+ return JimParseBrace(pc);
+
+ default:
+ if (pc->len) {
+ return JimParseListStr(pc);
+ }
+ break;
+ }
+
+ pc->tstart = pc->tend = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return JIM_OK;
+}
+
+static int JimParseListSep(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (isspace(UCHAR(*pc->p))) {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_SEP;
+ return JIM_OK;
+}
+
+static int JimParseListQuote(struct JimParserCtx *pc)
+{
+ pc->p++;
+ pc->len--;
+
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_STR;
+
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ pc->tt = JIM_TT_ESC;
+ if (--pc->len == 0) {
+
+ pc->tend = pc->p;
+ return JIM_OK;
+ }
+ pc->p++;
+ break;
+ case '\n':
+ pc->linenr++;
+ break;
+ case '"':
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return JIM_OK;
+ }
+ pc->p++;
+ pc->len--;
+ }
+
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+}
+
+static int JimParseListStr(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_STR;
+
+ while (pc->len) {
+ if (isspace(UCHAR(*pc->p))) {
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+ }
+ if (*pc->p == '\\') {
+ if (--pc->len == 0) {
+
+ pc->tend = pc->p;
+ return JIM_OK;
+ }
+ pc->tt = JIM_TT_ESC;
+ pc->p++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+}
+
+
+
+Jim_Obj *Jim_NewObj(Jim_Interp *interp)
+{
+ Jim_Obj *objPtr;
+
+
+ if (interp->freeList != NULL) {
+
+ objPtr = interp->freeList;
+ interp->freeList = objPtr->nextObjPtr;
+ }
+ else {
+
+ objPtr = Jim_Alloc(sizeof(*objPtr));
+ }
+
+ objPtr->refCount = 0;
+
+
+ objPtr->prevObjPtr = NULL;
+ objPtr->nextObjPtr = interp->liveList;
+ if (interp->liveList)
+ interp->liveList->prevObjPtr = objPtr;
+ interp->liveList = objPtr;
+
+ return objPtr;
+}
+
+void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+
+ JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
+ objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
+
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ if (objPtr->bytes != NULL) {
+ if (objPtr->bytes != JimEmptyStringRep)
+ Jim_Free(objPtr->bytes);
+ }
+
+ if (objPtr->prevObjPtr)
+ objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
+ if (objPtr->nextObjPtr)
+ objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
+ if (interp->liveList == objPtr)
+ interp->liveList = objPtr->nextObjPtr;
+#ifdef JIM_DISABLE_OBJECT_POOL
+ Jim_Free(objPtr);
+#else
+
+ objPtr->prevObjPtr = NULL;
+ objPtr->nextObjPtr = interp->freeList;
+ if (interp->freeList)
+ interp->freeList->prevObjPtr = objPtr;
+ interp->freeList = objPtr;
+ objPtr->refCount = -1;
+#endif
+}
+
+
+void Jim_InvalidateStringRep(Jim_Obj *objPtr)
+{
+ if (objPtr->bytes != NULL) {
+ if (objPtr->bytes != JimEmptyStringRep)
+ Jim_Free(objPtr->bytes);
+ }
+ objPtr->bytes = NULL;
+}
+
+
+Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_Obj *dupPtr;
+
+ dupPtr = Jim_NewObj(interp);
+ if (objPtr->bytes == NULL) {
+
+ dupPtr->bytes = NULL;
+ }
+ else if (objPtr->length == 0) {
+ dupPtr->bytes = JimEmptyStringRep;
+ dupPtr->length = 0;
+ dupPtr->typePtr = NULL;
+ return dupPtr;
+ }
+ else {
+ dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
+ dupPtr->length = objPtr->length;
+
+ memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1);
+ }
+
+
+ dupPtr->typePtr = objPtr->typePtr;
+ if (objPtr->typePtr != NULL) {
+ if (objPtr->typePtr->dupIntRepProc == NULL) {
+ dupPtr->internalRep = objPtr->internalRep;
+ }
+ else {
+
+ objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
+ }
+ }
+ return dupPtr;
+}
+
+const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
+{
+ if (objPtr->bytes == NULL) {
+
+ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+ objPtr->typePtr->updateStringProc(objPtr);
+ }
+ if (lenPtr)
+ *lenPtr = objPtr->length;
+ return objPtr->bytes;
+}
+
+
+int Jim_Length(Jim_Obj *objPtr)
+{
+ if (objPtr->bytes == NULL) {
+
+ Jim_GetString(objPtr, NULL);
+ }
+ return objPtr->length;
+}
+
+
+const char *Jim_String(Jim_Obj *objPtr)
+{
+ if (objPtr->bytes == NULL) {
+
+ Jim_GetString(objPtr, NULL);
+ }
+ return objPtr->bytes;
+}
+
+static void JimSetStringBytes(Jim_Obj *objPtr, const char *str)
+{
+ objPtr->bytes = Jim_StrDup(str);
+ objPtr->length = strlen(str);
+}
+
+static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType dictSubstObjType = {
+ "dict-substitution",
+ FreeDictSubstInternalRep,
+ DupDictSubstInternalRep,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType interpolatedObjType = {
+ "interpolated",
+ FreeInterpolatedInternalRep,
+ DupInterpolatedInternalRep,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+
+ dupPtr->internalRep = srcPtr->internalRep;
+
+ Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType stringObjType = {
+ "string",
+ NULL,
+ DupStringInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+
+ dupPtr->internalRep.strValue.maxLength = srcPtr->length;
+ dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
+}
+
+static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &stringObjType) {
+
+ if (objPtr->bytes == NULL) {
+
+ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+ objPtr->typePtr->updateStringProc(objPtr);
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ objPtr->typePtr = &stringObjType;
+ objPtr->internalRep.strValue.maxLength = objPtr->length;
+
+ objPtr->internalRep.strValue.charLength = -1;
+ }
+ return JIM_OK;
+}
+
+int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+#ifdef JIM_UTF8
+ SetStringFromAny(interp, objPtr);
+
+ if (objPtr->internalRep.strValue.charLength < 0) {
+ objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length);
+ }
+ return objPtr->internalRep.strValue.charLength;
+#else
+ return Jim_Length(objPtr);
+#endif
+}
+
+
+Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
+{
+ Jim_Obj *objPtr = Jim_NewObj(interp);
+
+
+ if (len == -1)
+ len = strlen(s);
+
+ if (len == 0) {
+ objPtr->bytes = JimEmptyStringRep;
+ }
+ else {
+ objPtr->bytes = Jim_StrDupLen(s, len);
+ }
+ objPtr->length = len;
+
+
+ objPtr->typePtr = NULL;
+ return objPtr;
+}
+
+
+Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
+{
+#ifdef JIM_UTF8
+
+ int bytelen = utf8_index(s, charlen);
+
+ Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
+
+
+ objPtr->typePtr = &stringObjType;
+ objPtr->internalRep.strValue.maxLength = bytelen;
+ objPtr->internalRep.strValue.charLength = charlen;
+
+ return objPtr;
+#else
+ return Jim_NewStringObj(interp, s, charlen);
+#endif
+}
+
+Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
+{
+ Jim_Obj *objPtr = Jim_NewObj(interp);
+
+ objPtr->bytes = s;
+ objPtr->length = (len == -1) ? strlen(s) : len;
+ objPtr->typePtr = NULL;
+ return objPtr;
+}
+
+static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
+{
+ int needlen;
+
+ if (len == -1)
+ len = strlen(str);
+ needlen = objPtr->length + len;
+ if (objPtr->internalRep.strValue.maxLength < needlen ||
+ objPtr->internalRep.strValue.maxLength == 0) {
+ needlen *= 2;
+
+ if (needlen < 7) {
+ needlen = 7;
+ }
+ if (objPtr->bytes == JimEmptyStringRep) {
+ objPtr->bytes = Jim_Alloc(needlen + 1);
+ }
+ else {
+ objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
+ }
+ objPtr->internalRep.strValue.maxLength = needlen;
+ }
+ memcpy(objPtr->bytes + objPtr->length, str, len);
+ objPtr->bytes[objPtr->length + len] = '\0';
+
+ if (objPtr->internalRep.strValue.charLength >= 0) {
+
+ objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
+ }
+ objPtr->length += len;
+}
+
+void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
+{
+ JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
+ SetStringFromAny(interp, objPtr);
+ StringAppendString(objPtr, str, len);
+}
+
+void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
+{
+ int len;
+ const char *str = Jim_GetString(appendObjPtr, &len);
+ Jim_AppendString(interp, objPtr, str, len);
+}
+
+void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
+{
+ va_list ap;
+
+ SetStringFromAny(interp, objPtr);
+ va_start(ap, objPtr);
+ while (1) {
+ const char *s = va_arg(ap, const char *);
+
+ if (s == NULL)
+ break;
+ Jim_AppendString(interp, objPtr, s, -1);
+ }
+ va_end(ap);
+}
+
+int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
+{
+ if (aObjPtr == bObjPtr) {
+ return 1;
+ }
+ else {
+ int Alen, Blen;
+ const char *sA = Jim_GetString(aObjPtr, &Alen);
+ const char *sB = Jim_GetString(bObjPtr, &Blen);
+
+ return Alen == Blen && *sA == *sB && memcmp(sA, sB, Alen) == 0;
+ }
+}
+
+int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
+{
+ int plen, slen;
+ const char *pattern = Jim_GetString(patternObjPtr, &plen);
+ const char *string = Jim_GetString(objPtr, &slen);
+ return JimGlobMatch(pattern, plen, string, slen, nocase);
+}
+
+int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
+{
+ const char *s1 = Jim_String(firstObjPtr);
+ int l1 = Jim_Utf8Length(interp, firstObjPtr);
+ const char *s2 = Jim_String(secondObjPtr);
+ int l2 = Jim_Utf8Length(interp, secondObjPtr);
+ return JimStringCompareUtf8(s1, l1, s2, l2, nocase);
+}
+
+static int JimRelToAbsIndex(int len, int idx)
+{
+ if (idx < 0 && idx > -INT_MAX)
+ return len + idx;
+ return idx;
+}
+
+static void JimRelToAbsRange(int len, int *firstPtr, int *lastPtr, int *rangeLenPtr)
+{
+ int rangeLen;
+
+ if (*firstPtr > *lastPtr) {
+ rangeLen = 0;
+ }
+ else {
+ rangeLen = *lastPtr - *firstPtr + 1;
+ if (rangeLen) {
+ if (*firstPtr < 0) {
+ rangeLen += *firstPtr;
+ *firstPtr = 0;
+ }
+ if (*lastPtr >= len) {
+ rangeLen -= (*lastPtr - (len - 1));
+ *lastPtr = len - 1;
+ }
+ }
+ }
+ if (rangeLen < 0)
+ rangeLen = 0;
+
+ *rangeLenPtr = rangeLen;
+}
+
+static int JimStringGetRange(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr,
+ int len, int *first, int *last, int *range)
+{
+ if (Jim_GetIndex(interp, firstObjPtr, first) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (Jim_GetIndex(interp, lastObjPtr, last) != JIM_OK) {
+ return JIM_ERR;
+ }
+ *first = JimRelToAbsIndex(len, *first);
+ *last = JimRelToAbsIndex(len, *last);
+ JimRelToAbsRange(len, first, last, range);
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+ int first, last;
+ const char *str;
+ int rangeLen;
+ int bytelen;
+
+ str = Jim_GetString(strObjPtr, &bytelen);
+
+ if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, bytelen, &first, &last, &rangeLen) != JIM_OK) {
+ return NULL;
+ }
+
+ if (first == 0 && rangeLen == bytelen) {
+ return strObjPtr;
+ }
+ return Jim_NewStringObj(interp, str + first, rangeLen);
+}
+
+Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+#ifdef JIM_UTF8
+ int first, last;
+ const char *str;
+ int len, rangeLen;
+ int bytelen;
+
+ str = Jim_GetString(strObjPtr, &bytelen);
+ len = Jim_Utf8Length(interp, strObjPtr);
+
+ if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
+ return NULL;
+ }
+
+ if (first == 0 && rangeLen == len) {
+ return strObjPtr;
+ }
+ if (len == bytelen) {
+
+ return Jim_NewStringObj(interp, str + first, rangeLen);
+ }
+ return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
+#else
+ return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
+#endif
+}
+
+Jim_Obj *JimStringReplaceObj(Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, Jim_Obj *newStrObj)
+{
+ int first, last;
+ const char *str;
+ int len, rangeLen;
+ Jim_Obj *objPtr;
+
+ len = Jim_Utf8Length(interp, strObjPtr);
+
+ if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
+ return NULL;
+ }
+
+ if (last < first) {
+ return strObjPtr;
+ }
+
+ str = Jim_String(strObjPtr);
+
+
+ objPtr = Jim_NewStringObjUtf8(interp, str, first);
+
+
+ if (newStrObj) {
+ Jim_AppendObj(interp, objPtr, newStrObj);
+ }
+
+
+ Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1);
+
+ return objPtr;
+}
+
+static void JimStrCopyUpperLower(char *dest, const char *str, int uc)
+{
+ while (*str) {
+ int c;
+ str += utf8_tounicode(str, &c);
+ dest += utf8_getchars(dest, uc ? utf8_upper(c) : utf8_lower(c));
+ }
+ *dest = 0;
+}
+
+static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+ char *buf;
+ int len;
+ const char *str;
+
+ str = Jim_GetString(strObjPtr, &len);
+
+#ifdef JIM_UTF8
+ len *= 2;
+#endif
+ buf = Jim_Alloc(len + 1);
+ JimStrCopyUpperLower(buf, str, 0);
+ return Jim_NewStringObjNoAlloc(interp, buf, -1);
+}
+
+static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+ char *buf;
+ const char *str;
+ int len;
+
+ str = Jim_GetString(strObjPtr, &len);
+
+#ifdef JIM_UTF8
+ len *= 2;
+#endif
+ buf = Jim_Alloc(len + 1);
+ JimStrCopyUpperLower(buf, str, 1);
+ return Jim_NewStringObjNoAlloc(interp, buf, -1);
+}
+
+static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+ char *buf, *p;
+ int len;
+ int c;
+ const char *str;
+
+ str = Jim_GetString(strObjPtr, &len);
+
+#ifdef JIM_UTF8
+ len *= 2;
+#endif
+ buf = p = Jim_Alloc(len + 1);
+
+ str += utf8_tounicode(str, &c);
+ p += utf8_getchars(p, utf8_title(c));
+
+ JimStrCopyUpperLower(p, str, 0);
+
+ return Jim_NewStringObjNoAlloc(interp, buf, -1);
+}
+
+static const char *utf8_memchr(const char *str, int len, int c)
+{
+#ifdef JIM_UTF8
+ while (len) {
+ int sc;
+ int n = utf8_tounicode(str, &sc);
+ if (sc == c) {
+ return str;
+ }
+ str += n;
+ len -= n;
+ }
+ return NULL;
+#else
+ return memchr(str, c, len);
+#endif
+}
+
+static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen)
+{
+ while (len) {
+ int c;
+ int n = utf8_tounicode(str, &c);
+
+ if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+
+ break;
+ }
+ str += n;
+ len -= n;
+ }
+ return str;
+}
+
+static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen)
+{
+ str += len;
+
+ while (len) {
+ int c;
+ int n = utf8_prev_len(str, len);
+
+ len -= n;
+ str -= n;
+
+ n = utf8_tounicode(str, &c);
+
+ if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+ return str + n;
+ }
+ }
+
+ return NULL;
+}
+
+static const char default_trim_chars[] = " \t\n\r";
+
+static int default_trim_chars_len = sizeof(default_trim_chars);
+
+static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+ int len;
+ const char *str = Jim_GetString(strObjPtr, &len);
+ const char *trimchars = default_trim_chars;
+ int trimcharslen = default_trim_chars_len;
+ const char *newstr;
+
+ if (trimcharsObjPtr) {
+ trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+ }
+
+ newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen);
+ if (newstr == str) {
+ return strObjPtr;
+ }
+
+ return Jim_NewStringObj(interp, newstr, len - (newstr - str));
+}
+
+static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+ int len;
+ const char *trimchars = default_trim_chars;
+ int trimcharslen = default_trim_chars_len;
+ const char *nontrim;
+
+ if (trimcharsObjPtr) {
+ trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+ }
+
+ SetStringFromAny(interp, strObjPtr);
+
+ len = Jim_Length(strObjPtr);
+ nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
+
+ if (nontrim == NULL) {
+
+ return Jim_NewEmptyStringObj(interp);
+ }
+ if (nontrim == strObjPtr->bytes + len) {
+
+ return strObjPtr;
+ }
+
+ if (Jim_IsShared(strObjPtr)) {
+ strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
+ }
+ else {
+
+ strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
+ strObjPtr->length = (nontrim - strObjPtr->bytes);
+ }
+
+ return strObjPtr;
+}
+
+static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+
+ Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
+
+
+ strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
+
+
+ if (objPtr != strObjPtr && objPtr->refCount == 0) {
+
+ Jim_FreeNewObj(interp, objPtr);
+ }
+
+ return strObjPtr;
+}
+
+
+#ifdef HAVE_ISASCII
+#define jim_isascii isascii
+#else
+static int jim_isascii(int c)
+{
+ return !(c & ~0x7f);
+}
+#endif
+
+static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
+{
+ static const char * const strclassnames[] = {
+ "integer", "alpha", "alnum", "ascii", "digit",
+ "double", "lower", "upper", "space", "xdigit",
+ "control", "print", "graph", "punct", "boolean",
+ NULL
+ };
+ enum {
+ STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
+ STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
+ STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT, STR_IS_BOOLEAN,
+ };
+ int strclass;
+ int len;
+ int i;
+ const char *str;
+ int (*isclassfunc)(int c) = NULL;
+
+ if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ str = Jim_GetString(strObjPtr, &len);
+ if (len == 0) {
+ Jim_SetResultBool(interp, !strict);
+ return JIM_OK;
+ }
+
+ switch (strclass) {
+ case STR_IS_INTEGER:
+ {
+ jim_wide w;
+ Jim_SetResultBool(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK);
+ return JIM_OK;
+ }
+
+ case STR_IS_DOUBLE:
+ {
+ double d;
+ Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
+ return JIM_OK;
+ }
+
+ case STR_IS_BOOLEAN:
+ {
+ int b;
+ Jim_SetResultBool(interp, Jim_GetBoolean(interp, strObjPtr, &b) == JIM_OK);
+ return JIM_OK;
+ }
+
+ case STR_IS_ALPHA: isclassfunc = isalpha; break;
+ case STR_IS_ALNUM: isclassfunc = isalnum; break;
+ case STR_IS_ASCII: isclassfunc = jim_isascii; break;
+ case STR_IS_DIGIT: isclassfunc = isdigit; break;
+ case STR_IS_LOWER: isclassfunc = islower; break;
+ case STR_IS_UPPER: isclassfunc = isupper; break;
+ case STR_IS_SPACE: isclassfunc = isspace; break;
+ case STR_IS_XDIGIT: isclassfunc = isxdigit; break;
+ case STR_IS_CONTROL: isclassfunc = iscntrl; break;
+ case STR_IS_PRINT: isclassfunc = isprint; break;
+ case STR_IS_GRAPH: isclassfunc = isgraph; break;
+ case STR_IS_PUNCT: isclassfunc = ispunct; break;
+ default:
+ return JIM_ERR;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (!isclassfunc(UCHAR(str[i]))) {
+ Jim_SetResultBool(interp, 0);
+ return JIM_OK;
+ }
+ }
+ Jim_SetResultBool(interp, 1);
+ return JIM_OK;
+}
+
+
+
+static const Jim_ObjType comparedStringObjType = {
+ "compared-string",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
+{
+ if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
+ return 1;
+ }
+ else {
+ if (strcmp(str, Jim_String(objPtr)) != 0)
+ return 0;
+
+ if (objPtr->typePtr != &comparedStringObjType) {
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &comparedStringObjType;
+ }
+ objPtr->internalRep.ptr = (char *)str;
+ return 1;
+ }
+}
+
+static int qsortCompareStringPointers(const void *a, const void *b)
+{
+ char *const *sa = (char *const *)a;
+ char *const *sb = (char *const *)b;
+
+ return strcmp(*sa, *sb);
+}
+
+
+
+static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType sourceObjType = {
+ "source",
+ FreeSourceInternalRep,
+ DupSourceInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj);
+}
+
+void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue;
+ Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
+}
+
+static const Jim_ObjType scriptLineObjType = {
+ "scriptline",
+ NULL,
+ NULL,
+ NULL,
+ JIM_NONE,
+};
+
+static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line)
+{
+ Jim_Obj *objPtr;
+
+#ifdef DEBUG_SHOW_SCRIPT
+ char buf[100];
+ snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc);
+ objPtr = Jim_NewStringObj(interp, buf, -1);
+#else
+ objPtr = Jim_NewEmptyStringObj(interp);
+#endif
+ objPtr->typePtr = &scriptLineObjType;
+ objPtr->internalRep.scriptLineValue.argc = argc;
+ objPtr->internalRep.scriptLineValue.line = line;
+
+ return objPtr;
+}
+
+static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType scriptObjType = {
+ "script",
+ FreeScriptInternalRep,
+ DupScriptInternalRep,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+typedef struct ScriptToken
+{
+ Jim_Obj *objPtr;
+ int type;
+} ScriptToken;
+
+typedef struct ScriptObj
+{
+ ScriptToken *token;
+ Jim_Obj *fileNameObj;
+ int len;
+ int substFlags;
+ int inUse; /* Used to share a ScriptObj. Currently
+ only used by Jim_EvalObj() as protection against
+ shimmering of the currently evaluated object. */
+ int firstline;
+ int linenr;
+ int missing;
+} ScriptObj;
+
+static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+static int JimParseCheckMissing(Jim_Interp *interp, int ch);
+static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
+static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script);
+
+void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int i;
+ struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
+
+ if (--script->inUse != 0)
+ return;
+ for (i = 0; i < script->len; i++) {
+ Jim_DecrRefCount(interp, script->token[i].objPtr);
+ }
+ Jim_Free(script->token);
+ Jim_DecrRefCount(interp, script->fileNameObj);
+ Jim_Free(script);
+}
+
+void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+ JIM_NOTUSED(srcPtr);
+
+ dupPtr->typePtr = NULL;
+}
+
+typedef struct
+{
+ const char *token;
+ int len;
+ int type;
+ int line;
+} ParseToken;
+
+typedef struct
+{
+
+ ParseToken *list;
+ int size;
+ int count;
+ ParseToken static_list[20];
+} ParseTokenList;
+
+static void ScriptTokenListInit(ParseTokenList *tokenlist)
+{
+ tokenlist->list = tokenlist->static_list;
+ tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken);
+ tokenlist->count = 0;
+}
+
+static void ScriptTokenListFree(ParseTokenList *tokenlist)
+{
+ if (tokenlist->list != tokenlist->static_list) {
+ Jim_Free(tokenlist->list);
+ }
+}
+
+static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type,
+ int line)
+{
+ ParseToken *t;
+
+ if (tokenlist->count == tokenlist->size) {
+
+ tokenlist->size *= 2;
+ if (tokenlist->list != tokenlist->static_list) {
+ tokenlist->list =
+ Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
+ }
+ else {
+
+ tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
+ memcpy(tokenlist->list, tokenlist->static_list,
+ tokenlist->count * sizeof(*tokenlist->list));
+ }
+ }
+ t = &tokenlist->list[tokenlist->count++];
+ t->token = token;
+ t->len = len;
+ t->type = type;
+ t->line = line;
+}
+
+static int JimCountWordTokens(struct ScriptObj *script, ParseToken *t)
+{
+ int expand = 1;
+ int count = 0;
+
+
+ if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
+ if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
+
+ expand = -1;
+ t++;
+ }
+ else {
+ if (script->missing == ' ') {
+
+ script->missing = '}';
+ script->linenr = t[1].line;
+ }
+ }
+ }
+
+
+ while (!TOKEN_IS_SEP(t->type)) {
+ t++;
+ count++;
+ }
+
+ return count * expand;
+}
+
+static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
+{
+ Jim_Obj *objPtr;
+
+ if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
+
+ int len = t->len;
+ char *str = Jim_Alloc(len + 1);
+ len = JimEscape(str, t->token, len);
+ objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
+ }
+ else {
+ objPtr = Jim_NewStringObj(interp, t->token, t->len);
+ }
+ return objPtr;
+}
+
+static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+ ParseTokenList *tokenlist)
+{
+ int i;
+ struct ScriptToken *token;
+
+ int lineargs = 0;
+
+ ScriptToken *linefirst;
+ int count;
+ int linenr;
+
+#ifdef DEBUG_SHOW_SCRIPT_TOKENS
+ printf("==== Tokens ====\n");
+ for (i = 0; i < tokenlist->count; i++) {
+ printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
+ tokenlist->list[i].len, tokenlist->list[i].token);
+ }
+#endif
+
+
+ count = tokenlist->count;
+ for (i = 0; i < tokenlist->count; i++) {
+ if (tokenlist->list[i].type == JIM_TT_EOL) {
+ count++;
+ }
+ }
+ linenr = script->firstline = tokenlist->list[0].line;
+
+ token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
+
+
+ linefirst = token++;
+
+ for (i = 0; i < tokenlist->count; ) {
+
+ int wordtokens;
+
+
+ while (tokenlist->list[i].type == JIM_TT_SEP) {
+ i++;
+ }
+
+ wordtokens = JimCountWordTokens(script, tokenlist->list + i);
+
+ if (wordtokens == 0) {
+
+ if (lineargs) {
+ linefirst->type = JIM_TT_LINE;
+ linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
+ Jim_IncrRefCount(linefirst->objPtr);
+
+
+ lineargs = 0;
+ linefirst = token++;
+ }
+ i++;
+ continue;
+ }
+ else if (wordtokens != 1) {
+
+ token->type = JIM_TT_WORD;
+ token->objPtr = Jim_NewIntObj(interp, wordtokens);
+ Jim_IncrRefCount(token->objPtr);
+ token++;
+ if (wordtokens < 0) {
+
+ i++;
+ wordtokens = -wordtokens - 1;
+ lineargs--;
+ }
+ }
+
+ if (lineargs == 0) {
+
+ linenr = tokenlist->list[i].line;
+ }
+ lineargs++;
+
+
+ while (wordtokens--) {
+ const ParseToken *t = &tokenlist->list[i++];
+
+ token->type = t->type;
+ token->objPtr = JimMakeScriptObj(interp, t);
+ Jim_IncrRefCount(token->objPtr);
+
+ Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
+ token++;
+ }
+ }
+
+ if (lineargs == 0) {
+ token--;
+ }
+
+ script->len = token - script->token;
+
+ JimPanic((script->len >= count, "allocated script array is too short"));
+
+#ifdef DEBUG_SHOW_SCRIPT
+ printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
+ for (i = 0; i < script->len; i++) {
+ const ScriptToken *t = &script->token[i];
+ printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
+ }
+#endif
+
+}
+
+int Jim_ScriptIsComplete(Jim_Interp *interp, Jim_Obj *scriptObj, char *stateCharPtr)
+{
+ ScriptObj *script = JimGetScript(interp, scriptObj);
+ if (stateCharPtr) {
+ *stateCharPtr = script->missing;
+ }
+ return script->missing == ' ' || script->missing == '}';
+}
+
+static int JimParseCheckMissing(Jim_Interp *interp, int ch)
+{
+ const char *msg;
+
+ switch (ch) {
+ case '\\':
+ case ' ':
+ return JIM_OK;
+
+ case '[':
+ msg = "unmatched \"[\"";
+ break;
+ case '{':
+ msg = "missing close-brace";
+ break;
+ case '}':
+ msg = "extra characters after close-brace";
+ break;
+ case '"':
+ default:
+ msg = "missing quote";
+ break;
+ }
+
+ Jim_SetResultString(interp, msg, -1);
+ return JIM_ERR;
+}
+
+Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr)
+{
+ int line;
+ Jim_Obj *fileNameObj;
+
+ if (objPtr->typePtr == &sourceObjType) {
+ fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+ line = objPtr->internalRep.sourceValue.lineNumber;
+ }
+ else if (objPtr->typePtr == &scriptObjType) {
+ ScriptObj *script = JimGetScript(interp, objPtr);
+ fileNameObj = script->fileNameObj;
+ line = script->firstline;
+ }
+ else {
+ fileNameObj = interp->emptyObj;
+ line = 1;
+ }
+ *lineptr = line;
+ return fileNameObj;
+}
+
+void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *fileNameObj, int lineNumber)
+{
+ JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object"));
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_IncrRefCount(fileNameObj);
+ objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
+ objPtr->internalRep.sourceValue.lineNumber = lineNumber;
+ objPtr->typePtr = &sourceObjType;
+}
+
+static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+ ParseTokenList *tokenlist)
+{
+ int i;
+ struct ScriptToken *token;
+
+ token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
+
+ for (i = 0; i < tokenlist->count; i++) {
+ const ParseToken *t = &tokenlist->list[i];
+
+
+ token->type = t->type;
+ token->objPtr = JimMakeScriptObj(interp, t);
+ Jim_IncrRefCount(token->objPtr);
+ token++;
+ }
+
+ script->len = i;
+}
+
+static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ int scriptTextLen;
+ const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+ struct JimParserCtx parser;
+ struct ScriptObj *script;
+ ParseTokenList tokenlist;
+ Jim_Obj *fileNameObj;
+ int line;
+
+
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
+
+
+ ScriptTokenListInit(&tokenlist);
+
+ JimParserInit(&parser, scriptText, scriptTextLen, line);
+ while (!parser.eof) {
+ JimParseScript(&parser);
+ ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+ parser.tline);
+ }
+
+
+ ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
+
+
+ script = Jim_Alloc(sizeof(*script));
+ memset(script, 0, sizeof(*script));
+ script->inUse = 1;
+ script->fileNameObj = fileNameObj;
+ Jim_IncrRefCount(script->fileNameObj);
+ script->missing = parser.missing.ch;
+ script->linenr = parser.missing.line;
+
+ ScriptObjAddTokens(interp, script, &tokenlist);
+
+
+ ScriptTokenListFree(&tokenlist);
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_SetIntRepPtr(objPtr, script);
+ objPtr->typePtr = &scriptObjType;
+}
+
+static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr == interp->emptyObj) {
+
+ objPtr = interp->nullScriptObj;
+ }
+
+ if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
+ JimSetScriptFromAny(interp, objPtr);
+ }
+
+ return (ScriptObj *)Jim_GetIntRepPtr(objPtr);
+}
+
+void Jim_InterpIncrProcEpoch(Jim_Interp *interp)
+{
+ interp->procEpoch++;
+
+
+ while (interp->oldCmdCache) {
+ Jim_Cmd *next = interp->oldCmdCache->prevCmd;
+ Jim_Free(interp->oldCmdCache);
+ interp->oldCmdCache = next;
+ }
+ interp->oldCmdCacheSize = 0;
+}
+
+static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
+{
+ cmdPtr->inUse++;
+}
+
+static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
+{
+ if (--cmdPtr->inUse == 0) {
+ if (cmdPtr->isproc) {
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr);
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr);
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
+ if (cmdPtr->u.proc.staticVars) {
+ Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
+ Jim_Free(cmdPtr->u.proc.staticVars);
+ }
+ }
+ else {
+
+ if (cmdPtr->u.native.delProc) {
+ cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
+ }
+ }
+ if (cmdPtr->prevCmd) {
+
+ JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
+ }
+
+ cmdPtr->prevCmd = interp->oldCmdCache;
+ interp->oldCmdCache = cmdPtr;
+ if (!interp->quitting && ++interp->oldCmdCacheSize >= 1000) {
+ Jim_InterpIncrProcEpoch(interp);
+ }
+ }
+}
+
+static void JimIncrVarRef(Jim_VarVal *vv)
+{
+ vv->refCount++;
+}
+
+static void JimDecrVarRef(Jim_Interp *interp, Jim_VarVal *vv)
+{
+ assert(vv->refCount > 0);
+ if (--vv->refCount == 0) {
+ if (vv->objPtr) {
+ Jim_DecrRefCount(interp, vv->objPtr);
+ }
+ Jim_Free(vv);
+ }
+}
+
+static void JimVariablesHTValDestructor(void *interp, void *val)
+{
+ JimDecrVarRef(interp, val);
+}
+
+static unsigned int JimObjectHTHashFunction(const void *key)
+{
+ Jim_Obj *keyObj = (Jim_Obj *)key;
+ int length;
+ const char *string;
+
+#ifdef JIM_OPTIMIZATION
+ if (JimIsWide(keyObj) && keyObj->bytes == NULL) {
+
+ jim_wide objValue = JimWideValue(keyObj);
+ if (objValue > INT_MIN && objValue < INT_MAX) {
+ unsigned result = 0;
+ unsigned value = (unsigned)objValue;
+
+ if (objValue < 0) {
+ value = (unsigned)-objValue;
+ }
+
+
+ do {
+ result += (result << 3) + (value % 10 + '0');
+ value /= 10;
+ } while (value);
+
+ if (objValue < 0) {
+ result += (result << 3) + '-';
+ }
+ return result;
+ }
+ }
+#endif
+ string = Jim_GetString(keyObj, &length);
+ return Jim_GenHashFunction((const unsigned char *)string, length);
+}
+
+static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+ return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
+}
+
+static void *JimObjectHTKeyValDup(void *privdata, const void *val)
+{
+ Jim_IncrRefCount((Jim_Obj *)val);
+ return (void *)val;
+}
+
+static void JimObjectHTKeyValDestructor(void *interp, void *val)
+{
+ Jim_DecrRefCount(interp, (Jim_Obj *)val);
+}
+
+
+static void *JimVariablesHTValDup(void *privdata, const void *val)
+{
+ JimIncrVarRef((Jim_VarVal *)val);
+ return (void *)val;
+}
+
+static const Jim_HashTableType JimVariablesHashTableType = {
+ JimObjectHTHashFunction,
+ JimObjectHTKeyValDup,
+ JimVariablesHTValDup,
+ JimObjectHTKeyCompare,
+ JimObjectHTKeyValDestructor,
+ JimVariablesHTValDestructor
+};
+
+
+static const char *Jim_GetStringNoQualifier(Jim_Obj *objPtr, int *length)
+{
+ int len;
+ const char *str = Jim_GetString(objPtr, &len);
+ if (len >= 2 && str[0] == ':' && str[1] == ':') {
+ while (len && *str == ':') {
+ len--;
+ str++;
+ }
+ }
+ *length = len;
+ return str;
+}
+
+static unsigned int JimCommandsHT_HashFunction(const void *key)
+{
+ int len;
+ const char *str = Jim_GetStringNoQualifier((Jim_Obj *)key, &len);
+ return Jim_GenHashFunction((const unsigned char *)str, len);
+}
+
+static int JimCommandsHT_KeyCompare(void *privdata, const void *key1, const void *key2)
+{
+ int len1, len2;
+ const char *str1 = Jim_GetStringNoQualifier((Jim_Obj *)key1, &len1);
+ const char *str2 = Jim_GetStringNoQualifier((Jim_Obj *)key2, &len2);
+ return len1 == len2 && *str1 == *str2 && memcmp(str1, str2, len1) == 0;
+}
+
+static void JimCommandsHT_ValDestructor(void *interp, void *val)
+{
+ JimDecrCmdRefCount(interp, val);
+}
+
+static const Jim_HashTableType JimCommandsHashTableType = {
+ JimCommandsHT_HashFunction,
+ JimObjectHTKeyValDup,
+ NULL,
+ JimCommandsHT_KeyCompare,
+ JimObjectHTKeyValDestructor,
+ JimCommandsHT_ValDestructor
+};
+
+
+
+Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
+{
+#ifdef jim_ext_namespace
+ Jim_Obj *resultObj;
+
+ const char *name = Jim_String(nameObjPtr);
+ if (name[0] == ':' && name[1] == ':') {
+ return nameObjPtr;
+ }
+ Jim_IncrRefCount(nameObjPtr);
+ resultObj = Jim_NewStringObj(interp, "::", -1);
+ Jim_AppendObj(interp, resultObj, nameObjPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+
+ return resultObj;
+#else
+ return nameObjPtr;
+#endif
+}
+
+static Jim_Obj *JimQualifyName(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+#ifdef jim_ext_namespace
+ if (Jim_Length(interp->framePtr->nsObj)) {
+ int len;
+ const char *name = Jim_GetString(objPtr, &len);
+ if (len < 2 || name[0] != ':' || name[1] != ':') {
+
+ objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
+ Jim_AppendStrings(interp, objPtr, "::", name, NULL);
+ }
+ }
+#endif
+ Jim_IncrRefCount(objPtr);
+ return objPtr;
+}
+
+static void JimCreateCommand(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Cmd *cmd)
+{
+ JimPanic((nameObjPtr->refCount == 0, "JimCreateCommand called with zero ref count name"));
+
+ if (interp->local) {
+ Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, nameObjPtr);
+ if (he) {
+
+ cmd->prevCmd = Jim_GetHashEntryVal(he);
+ Jim_SetHashVal(&interp->commands, he, cmd);
+
+ Jim_InterpIncrProcEpoch(interp);
+ return;
+ }
+ }
+
+
+
+ Jim_ReplaceHashEntry(&interp->commands, nameObjPtr, cmd);
+}
+
+int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj,
+ Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
+{
+ Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
+
+
+ memset(cmdPtr, 0, sizeof(*cmdPtr));
+ cmdPtr->inUse = 1;
+ cmdPtr->u.native.delProc = delProc;
+ cmdPtr->u.native.cmdProc = cmdProc;
+ cmdPtr->u.native.privData = privData;
+
+ Jim_IncrRefCount(cmdNameObj);
+ JimCreateCommand(interp, cmdNameObj, cmdPtr);
+ Jim_DecrRefCount(interp, cmdNameObj);
+
+ return JIM_OK;
+}
+
+
+int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
+ Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
+{
+ return Jim_CreateCommandObj(interp, Jim_NewStringObj(interp, cmdNameStr, -1), cmdProc, privData, delProc);
+}
+
+static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr)
+{
+ int len, i;
+
+ len = Jim_ListLength(interp, staticsListObjPtr);
+ if (len == 0) {
+ return JIM_OK;
+ }
+
+ cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
+ Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
+ for (i = 0; i < len; i++) {
+ Jim_Obj *initObjPtr = NULL;
+ Jim_Obj *nameObjPtr;
+ Jim_VarVal *vv = NULL;
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
+ int subLen = Jim_ListLength(interp, objPtr);
+ int byref = 0;
+
+
+ if (subLen != 1 && subLen != 2) {
+ Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
+ objPtr);
+ return JIM_ERR;
+ }
+
+ nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
+
+
+ if (subLen == 1) {
+ int len;
+ const char *pt = Jim_GetString(nameObjPtr, &len);
+ if (*pt == '&') {
+
+ nameObjPtr = Jim_NewStringObj(interp, pt + 1, len - 1);
+ byref = 1;
+ }
+ }
+ Jim_IncrRefCount(nameObjPtr);
+
+ if (subLen == 1) {
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_DICT_SUGAR:
+
+ if (byref) {
+ Jim_SetResultFormatted(interp, "Can't link to array element \"%#s\"", nameObjPtr);
+ }
+ else {
+ Jim_SetResultFormatted(interp, "Can't initialise array element \"%#s\"", nameObjPtr);
+ }
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return JIM_ERR;
+
+ case JIM_OK:
+ if (byref) {
+ vv = nameObjPtr->internalRep.varValue.vv;
+ }
+ else {
+ initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
+ }
+ break;
+
+ case JIM_ERR:
+
+ Jim_SetResultFormatted(interp,
+ "variable for initialization of static \"%#s\" not found in the local context",
+ nameObjPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return JIM_ERR;
+ }
+ }
+ else {
+ initObjPtr = Jim_ListGetIndex(interp, objPtr, 1);
+ }
+
+ if (vv == NULL) {
+ vv = Jim_Alloc(sizeof(*vv));
+ vv->objPtr = initObjPtr;
+ Jim_IncrRefCount(vv->objPtr);
+ vv->linkFramePtr = NULL;
+ vv->refCount = 0;
+ }
+
+ if (JimSetNewVariable(cmdPtr->u.proc.staticVars, nameObjPtr, vv) != JIM_OK) {
+ Jim_SetResultFormatted(interp,
+ "static variable name \"%#s\" duplicated in statics list", nameObjPtr);
+ JimIncrVarRef(vv);
+ JimDecrVarRef(interp, vv);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return JIM_ERR;
+ }
+
+ Jim_DecrRefCount(interp, nameObjPtr);
+ }
+ return JIM_OK;
+}
+
+
+#ifdef jim_ext_namespace
+static const char *Jim_memrchr(const char *p, int c, int len)
+{
+ int i;
+ for (i = len; i > 0; i--) {
+ if (p[i] == c) {
+ return p + i;
+ }
+ }
+ return NULL;
+}
+#endif
+
+static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *nameObjPtr)
+{
+#ifdef jim_ext_namespace
+ if (cmdPtr->isproc) {
+ int len;
+ const char *cmdname = Jim_GetStringNoQualifier(nameObjPtr, &len);
+
+ const char *pt = Jim_memrchr(cmdname, ':', len);
+ if (pt && pt != cmdname && pt[-1] == ':') {
+ pt++;
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
+ cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 2);
+ Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
+
+ Jim_Obj *tempObj = Jim_NewStringObj(interp, pt, len - (pt - cmdname));
+ if (Jim_FindHashEntry(&interp->commands, tempObj)) {
+
+ Jim_InterpIncrProcEpoch(interp);
+ }
+ Jim_FreeNewObj(interp, tempObj);
+ }
+ }
+#endif
+}
+
+static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr,
+ Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj)
+{
+ Jim_Cmd *cmdPtr;
+ int argListLen;
+ int i;
+
+ argListLen = Jim_ListLength(interp, argListObjPtr);
+
+
+ cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
+ assert(cmdPtr);
+ memset(cmdPtr, 0, sizeof(*cmdPtr));
+ cmdPtr->inUse = 1;
+ cmdPtr->isproc = 1;
+ cmdPtr->u.proc.argListObjPtr = argListObjPtr;
+ cmdPtr->u.proc.argListLen = argListLen;
+ cmdPtr->u.proc.bodyObjPtr = bodyObjPtr;
+ cmdPtr->u.proc.argsPos = -1;
+ cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1);
+ cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj;
+ Jim_IncrRefCount(argListObjPtr);
+ Jim_IncrRefCount(bodyObjPtr);
+ Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
+
+
+ if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) {
+ goto err;
+ }
+
+
+
+ for (i = 0; i < argListLen; i++) {
+ Jim_Obj *argPtr;
+ Jim_Obj *nameObjPtr;
+ Jim_Obj *defaultObjPtr;
+ int len;
+
+
+ argPtr = Jim_ListGetIndex(interp, argListObjPtr, i);
+ len = Jim_ListLength(interp, argPtr);
+ if (len == 0) {
+ Jim_SetResultString(interp, "argument with no name", -1);
+err:
+ JimDecrCmdRefCount(interp, cmdPtr);
+ return NULL;
+ }
+ if (len > 2) {
+ Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
+ goto err;
+ }
+
+ if (len == 2) {
+
+ nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0);
+ defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1);
+ }
+ else {
+
+ nameObjPtr = argPtr;
+ defaultObjPtr = NULL;
+ }
+
+
+ if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) {
+ if (cmdPtr->u.proc.argsPos >= 0) {
+ Jim_SetResultString(interp, "'args' specified more than once", -1);
+ goto err;
+ }
+ cmdPtr->u.proc.argsPos = i;
+ }
+ else {
+ if (len == 2) {
+ cmdPtr->u.proc.optArity++;
+ }
+ else {
+ cmdPtr->u.proc.reqArity++;
+ }
+ }
+
+ cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr;
+ cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr;
+ }
+
+ return cmdPtr;
+}
+
+int Jim_DeleteCommand(Jim_Interp *interp, Jim_Obj *nameObj)
+{
+ int ret = JIM_OK;
+
+ nameObj = JimQualifyName(interp, nameObj);
+
+ if (Jim_DeleteHashEntry(&interp->commands, nameObj) == JIM_ERR) {
+ Jim_SetResultFormatted(interp, "can't delete \"%#s\": command doesn't exist", nameObj);
+ ret = JIM_ERR;
+ }
+ Jim_DecrRefCount(interp, nameObj);
+
+ return ret;
+}
+
+int Jim_RenameCommand(Jim_Interp *interp, Jim_Obj *oldNameObj, Jim_Obj *newNameObj)
+{
+ int ret = JIM_ERR;
+ Jim_HashEntry *he;
+ Jim_Cmd *cmdPtr;
+
+ if (Jim_Length(newNameObj) == 0) {
+ return Jim_DeleteCommand(interp, oldNameObj);
+ }
+
+
+
+ oldNameObj = JimQualifyName(interp, oldNameObj);
+ newNameObj = JimQualifyName(interp, newNameObj);
+
+
+ he = Jim_FindHashEntry(&interp->commands, oldNameObj);
+ if (he == NULL) {
+ Jim_SetResultFormatted(interp, "can't rename \"%#s\": command doesn't exist", oldNameObj);
+ }
+ else if (Jim_FindHashEntry(&interp->commands, newNameObj)) {
+ Jim_SetResultFormatted(interp, "can't rename to \"%#s\": command already exists", newNameObj);
+ }
+ else {
+ cmdPtr = Jim_GetHashEntryVal(he);
+ if (cmdPtr->prevCmd) {
+ Jim_SetResultFormatted(interp, "can't rename local command \"%#s\"", oldNameObj);
+ }
+ else {
+
+ JimIncrCmdRefCount(cmdPtr);
+ JimUpdateProcNamespace(interp, cmdPtr, newNameObj);
+ Jim_AddHashEntry(&interp->commands, newNameObj, cmdPtr);
+
+
+ Jim_DeleteHashEntry(&interp->commands, oldNameObj);
+
+
+ Jim_InterpIncrProcEpoch(interp);
+
+ ret = JIM_OK;
+ }
+ }
+
+ Jim_DecrRefCount(interp, oldNameObj);
+ Jim_DecrRefCount(interp, newNameObj);
+
+ return ret;
+}
+
+
+static void FreeCommandInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.cmdValue.nsObj);
+}
+
+static void DupCommandInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ dupPtr->internalRep.cmdValue = srcPtr->internalRep.cmdValue;
+ dupPtr->typePtr = srcPtr->typePtr;
+ Jim_IncrRefCount(dupPtr->internalRep.cmdValue.nsObj);
+}
+
+static const Jim_ObjType commandObjType = {
+ "command",
+ FreeCommandInternalRep,
+ DupCommandInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ Jim_Cmd *cmd;
+
+ if (objPtr->typePtr == &commandObjType
+ && objPtr->internalRep.cmdValue.procEpoch == interp->procEpoch
+#ifdef jim_ext_namespace
+ && Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
+#endif
+ && objPtr->internalRep.cmdValue.cmdPtr->inUse) {
+
+ cmd = objPtr->internalRep.cmdValue.cmdPtr;
+ }
+ else {
+ Jim_Obj *qualifiedNameObj = JimQualifyName(interp, objPtr);
+ Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, qualifiedNameObj);
+#ifdef jim_ext_namespace
+ if (he == NULL && Jim_Length(interp->framePtr->nsObj)) {
+ he = Jim_FindHashEntry(&interp->commands, objPtr);
+ }
+#endif
+ if (he == NULL) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
+ }
+ Jim_DecrRefCount(interp, qualifiedNameObj);
+ return NULL;
+ }
+ cmd = Jim_GetHashEntryVal(he);
+
+ cmd->cmdNameObj = Jim_GetHashEntryKey(he);
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &commandObjType;
+ objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
+ objPtr->internalRep.cmdValue.cmdPtr = cmd;
+ objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
+ Jim_IncrRefCount(interp->framePtr->nsObj);
+ Jim_DecrRefCount(interp, qualifiedNameObj);
+ }
+ while (cmd->u.proc.upcall) {
+ cmd = cmd->prevCmd;
+ }
+ return cmd;
+}
+
+
+
+static const Jim_ObjType variableObjType = {
+ "variable",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ const char *varName;
+ Jim_CallFrame *framePtr;
+ int global;
+ int len;
+ Jim_VarVal *vv;
+
+
+ if (objPtr->typePtr == &variableObjType) {
+ framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr;
+ if (objPtr->internalRep.varValue.callFrameId == framePtr->id) {
+
+ return JIM_OK;
+ }
+
+ }
+ else if (objPtr->typePtr == &dictSubstObjType) {
+ return JIM_DICT_SUGAR;
+ }
+
+ varName = Jim_GetString(objPtr, &len);
+
+
+ if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) {
+ return JIM_DICT_SUGAR;
+ }
+
+ if (varName[0] == ':' && varName[1] == ':') {
+ while (*varName == ':') {
+ varName++;
+ len--;
+ }
+ global = 1;
+ framePtr = interp->topFramePtr;
+
+ Jim_Obj *tempObj = Jim_NewStringObj(interp, varName, len);
+ vv = JimFindVariable(&framePtr->vars, tempObj);
+ Jim_FreeNewObj(interp, tempObj);
+ }
+ else {
+ global = 0;
+ framePtr = interp->framePtr;
+
+ vv = JimFindVariable(&framePtr->vars, objPtr);
+ if (vv == NULL && framePtr->staticVars) {
+
+ vv = JimFindVariable(framePtr->staticVars, objPtr);
+ }
+ }
+
+ if (vv == NULL) {
+ return JIM_ERR;
+ }
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &variableObjType;
+ objPtr->internalRep.varValue.callFrameId = framePtr->id;
+ objPtr->internalRep.varValue.vv = vv;
+ objPtr->internalRep.varValue.global = global;
+ return JIM_OK;
+}
+
+
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
+
+static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv)
+{
+ return Jim_AddHashEntry(ht, nameObjPtr, vv);
+}
+
+static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
+{
+ Jim_HashEntry *he = Jim_FindHashEntry(ht, nameObjPtr);
+ if (he) {
+ return (Jim_VarVal *)Jim_GetHashEntryVal(he);
+ }
+ return NULL;
+}
+
+static int JimUnsetVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
+{
+ return Jim_DeleteHashEntry(ht, nameObjPtr);
+}
+
+static Jim_VarVal *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
+{
+ const char *name;
+ Jim_CallFrame *framePtr;
+ int global;
+ int len;
+
+
+ Jim_VarVal *vv = Jim_Alloc(sizeof(*vv));
+
+ vv->objPtr = valObjPtr;
+ Jim_IncrRefCount(valObjPtr);
+ vv->linkFramePtr = NULL;
+ vv->refCount = 0;
+
+ name = Jim_GetString(nameObjPtr, &len);
+ if (name[0] == ':' && name[1] == ':') {
+ while (*name == ':') {
+ name++;
+ len--;
+ }
+ framePtr = interp->topFramePtr;
+ global = 1;
+ JimSetNewVariable(&framePtr->vars, Jim_NewStringObj(interp, name, len), vv);
+ }
+ else {
+ framePtr = interp->framePtr;
+ global = 0;
+ JimSetNewVariable(&framePtr->vars, nameObjPtr, vv);
+ }
+
+
+ Jim_FreeIntRep(interp, nameObjPtr);
+ nameObjPtr->typePtr = &variableObjType;
+ nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
+ nameObjPtr->internalRep.varValue.vv = vv;
+ nameObjPtr->internalRep.varValue.global = global;
+
+ return vv;
+}
+
+int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
+{
+ int err;
+ Jim_VarVal *vv;
+
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_DICT_SUGAR:
+ return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
+
+ case JIM_ERR:
+ JimCreateVariable(interp, nameObjPtr, valObjPtr);
+ break;
+
+ case JIM_OK:
+ vv = nameObjPtr->internalRep.varValue.vv;
+ if (vv->linkFramePtr == NULL) {
+ Jim_IncrRefCount(valObjPtr);
+ Jim_DecrRefCount(interp, vv->objPtr);
+ vv->objPtr = valObjPtr;
+ }
+ else {
+ Jim_CallFrame *savedCallFrame;
+
+ savedCallFrame = interp->framePtr;
+ interp->framePtr = vv->linkFramePtr;
+ err = Jim_SetVariable(interp, vv->objPtr, valObjPtr);
+ interp->framePtr = savedCallFrame;
+ if (err != JIM_OK)
+ return err;
+ }
+ }
+ return JIM_OK;
+}
+
+int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+ Jim_Obj *nameObjPtr;
+ int result;
+
+ nameObjPtr = Jim_NewStringObj(interp, name, -1);
+ Jim_IncrRefCount(nameObjPtr);
+ result = Jim_SetVariable(interp, nameObjPtr, objPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return result;
+}
+
+int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+ Jim_CallFrame *savedFramePtr;
+ int result;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ result = Jim_SetVariableStr(interp, name, objPtr);
+ interp->framePtr = savedFramePtr;
+ return result;
+}
+
+int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
+{
+ Jim_Obj *valObjPtr;
+ int result;
+
+ valObjPtr = Jim_NewStringObj(interp, val, -1);
+ Jim_IncrRefCount(valObjPtr);
+ result = Jim_SetVariableStr(interp, name, valObjPtr);
+ Jim_DecrRefCount(interp, valObjPtr);
+ return result;
+}
+
+int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
+ Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
+{
+ const char *varName;
+ const char *targetName;
+ Jim_CallFrame *framePtr;
+ Jim_VarVal *vv;
+ int len;
+ int varnamelen;
+
+
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_DICT_SUGAR:
+
+ Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr);
+ return JIM_ERR;
+
+ case JIM_OK:
+ vv = nameObjPtr->internalRep.varValue.vv;
+
+ if (vv->linkFramePtr == NULL) {
+ Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
+ return JIM_ERR;
+ }
+
+
+ vv->linkFramePtr = NULL;
+ break;
+ }
+
+
+
+ varName = Jim_GetString(nameObjPtr, &varnamelen);
+
+ if (varName[0] == ':' && varName[1] == ':') {
+ while (*varName == ':') {
+ varName++;
+ varnamelen--;
+ }
+
+ framePtr = interp->topFramePtr;
+ }
+ else {
+ framePtr = interp->framePtr;
+ }
+
+ targetName = Jim_GetString(targetNameObjPtr, &len);
+ if (targetName[0] == ':' && targetName[1] == ':') {
+ while (*targetName == ':') {
+ targetName++;
+ len--;
+ }
+ targetNameObjPtr = Jim_NewStringObj(interp, targetName, len);
+ targetCallFrame = interp->topFramePtr;
+ }
+ Jim_IncrRefCount(targetNameObjPtr);
+
+ if (framePtr->level < targetCallFrame->level) {
+ Jim_SetResultFormatted(interp,
+ "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
+ nameObjPtr);
+ Jim_DecrRefCount(interp, targetNameObjPtr);
+ return JIM_ERR;
+ }
+
+
+ if (framePtr == targetCallFrame) {
+ Jim_Obj *objPtr = targetNameObjPtr;
+
+
+ while (1) {
+ if (Jim_Length(objPtr) == varnamelen && memcmp(Jim_String(objPtr), varName, varnamelen) == 0) {
+ Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
+ Jim_DecrRefCount(interp, targetNameObjPtr);
+ return JIM_ERR;
+ }
+ if (SetVariableFromAny(interp, objPtr) != JIM_OK)
+ break;
+ vv = objPtr->internalRep.varValue.vv;
+ if (vv->linkFramePtr != targetCallFrame)
+ break;
+ objPtr = vv->objPtr;
+ }
+ }
+
+
+ Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
+
+ nameObjPtr->internalRep.varValue.vv->linkFramePtr = targetCallFrame;
+ Jim_DecrRefCount(interp, targetNameObjPtr);
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+ if (interp->safeexpr) {
+ return nameObjPtr;
+ }
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_OK:{
+ Jim_VarVal *vv = nameObjPtr->internalRep.varValue.vv;
+
+ if (vv->linkFramePtr == NULL) {
+ return vv->objPtr;
+ }
+ else {
+ Jim_Obj *objPtr;
+
+
+ Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+ interp->framePtr = vv->linkFramePtr;
+ objPtr = Jim_GetVariable(interp, vv->objPtr, flags);
+ interp->framePtr = savedCallFrame;
+ if (objPtr) {
+ return objPtr;
+ }
+
+ }
+ }
+ break;
+
+ case JIM_DICT_SUGAR:
+
+ return JimDictSugarGet(interp, nameObjPtr, flags);
+ }
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
+ }
+ return NULL;
+}
+
+Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+ Jim_CallFrame *savedFramePtr;
+ Jim_Obj *objPtr;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+ interp->framePtr = savedFramePtr;
+
+ return objPtr;
+}
+
+Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+ Jim_Obj *nameObjPtr, *varObjPtr;
+
+ nameObjPtr = Jim_NewStringObj(interp, name, -1);
+ Jim_IncrRefCount(nameObjPtr);
+ varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return varObjPtr;
+}
+
+Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+ Jim_CallFrame *savedFramePtr;
+ Jim_Obj *objPtr;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ objPtr = Jim_GetVariableStr(interp, name, flags);
+ interp->framePtr = savedFramePtr;
+
+ return objPtr;
+}
+
+int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+ Jim_VarVal *vv;
+ int retval;
+ Jim_CallFrame *framePtr;
+
+ retval = SetVariableFromAny(interp, nameObjPtr);
+ if (retval == JIM_DICT_SUGAR) {
+
+ return JimDictSugarSet(interp, nameObjPtr, NULL);
+ }
+ else if (retval == JIM_OK) {
+ vv = nameObjPtr->internalRep.varValue.vv;
+
+
+ if (vv->linkFramePtr) {
+ framePtr = interp->framePtr;
+ interp->framePtr = vv->linkFramePtr;
+ retval = Jim_UnsetVariable(interp, vv->objPtr, JIM_NONE);
+ interp->framePtr = framePtr;
+ }
+ else {
+ if (nameObjPtr->internalRep.varValue.global) {
+ int len;
+ const char *name = Jim_GetString(nameObjPtr, &len);
+ while (*name == ':') {
+ name++;
+ len--;
+ }
+ framePtr = interp->topFramePtr;
+ Jim_Obj *tempObj = Jim_NewStringObj(interp, name, len);
+ retval = JimUnsetVariable(&framePtr->vars, tempObj);
+ Jim_FreeNewObj(interp, tempObj);
+ }
+ else {
+ framePtr = interp->framePtr;
+ retval = JimUnsetVariable(&framePtr->vars, nameObjPtr);
+ }
+
+ if (retval == JIM_OK) {
+
+ framePtr->id = interp->callFrameEpoch++;
+ }
+ }
+ }
+ if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
+ Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
+ }
+ return retval;
+}
+
+
+
+static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
+{
+ const char *str, *p;
+ int len, keyLen;
+ Jim_Obj *varObjPtr, *keyObjPtr;
+
+ str = Jim_GetString(objPtr, &len);
+
+ p = strchr(str, '(');
+ JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
+
+ varObjPtr = Jim_NewStringObj(interp, str, p - str);
+
+ p++;
+ keyLen = (str + len) - p;
+ if (str[len - 1] == ')') {
+ keyLen--;
+ }
+
+
+ keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
+
+ Jim_IncrRefCount(varObjPtr);
+ Jim_IncrRefCount(keyObjPtr);
+ *varPtrPtr = varObjPtr;
+ *keyPtrPtr = keyObjPtr;
+}
+
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr)
+{
+ int err;
+
+ SetDictSubstFromAny(interp, objPtr);
+
+ err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+ &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST);
+
+ if (err == JIM_OK) {
+
+ Jim_SetEmptyResult(interp);
+ }
+ else {
+ if (!valObjPtr) {
+
+ if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
+ Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
+ objPtr);
+ return err;
+ }
+ }
+
+ Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
+ (valObjPtr ? "set" : "unset"), objPtr);
+ }
+ return err;
+}
+
+static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr,
+ Jim_Obj *keyObjPtr, int flags)
+{
+ Jim_Obj *dictObjPtr;
+ Jim_Obj *resObjPtr = NULL;
+ int ret;
+
+ dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
+ if (!dictObjPtr) {
+ return NULL;
+ }
+
+ ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
+ if (ret != JIM_OK) {
+ Jim_SetResultFormatted(interp,
+ "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr,
+ ret < 0 ? "variable isn't" : "no such element in");
+ }
+ else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
+
+ Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr));
+ }
+
+ return resObjPtr;
+}
+
+
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ SetDictSubstFromAny(interp, objPtr);
+
+ return JimDictExpandArrayVariable(interp,
+ objPtr->internalRep.dictSubstValue.varNameObjPtr,
+ objPtr->internalRep.dictSubstValue.indexObjPtr, flags);
+}
+
+
+
+void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
+ Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+
+ dupPtr->internalRep = srcPtr->internalRep;
+
+ Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.varNameObjPtr);
+ Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &dictSubstObjType) {
+ Jim_Obj *varObjPtr, *keyObjPtr;
+
+ if (objPtr->typePtr == &interpolatedObjType) {
+
+
+ varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr;
+ keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr;
+
+ Jim_IncrRefCount(varObjPtr);
+ Jim_IncrRefCount(keyObjPtr);
+ }
+ else {
+ JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &dictSubstObjType;
+ objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
+ objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
+ }
+}
+
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_Obj *resObjPtr = NULL;
+ Jim_Obj *substKeyObjPtr = NULL;
+
+ if (interp->safeexpr) {
+ return objPtr;
+ }
+
+ SetDictSubstFromAny(interp, objPtr);
+
+ if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
+ &substKeyObjPtr, JIM_NONE)
+ != JIM_OK) {
+ return NULL;
+ }
+ Jim_IncrRefCount(substKeyObjPtr);
+ resObjPtr =
+ JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+ substKeyObjPtr, 0);
+ Jim_DecrRefCount(interp, substKeyObjPtr);
+
+ return resObjPtr;
+}
+
+
+static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj)
+{
+ Jim_CallFrame *cf;
+
+ if (interp->freeFramesList) {
+ cf = interp->freeFramesList;
+ interp->freeFramesList = cf->next;
+
+ cf->argv = NULL;
+ cf->argc = 0;
+ cf->procArgsObjPtr = NULL;
+ cf->procBodyObjPtr = NULL;
+ cf->next = NULL;
+ cf->staticVars = NULL;
+ cf->localCommands = NULL;
+ cf->tailcallObj = NULL;
+ cf->tailcallCmd = NULL;
+ }
+ else {
+ cf = Jim_Alloc(sizeof(*cf));
+ memset(cf, 0, sizeof(*cf));
+
+ Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
+ }
+
+ cf->id = interp->callFrameEpoch++;
+ cf->parent = parent;
+ cf->level = parent ? parent->level + 1 : 0;
+ cf->nsObj = nsObj;
+ Jim_IncrRefCount(nsObj);
+
+ return cf;
+}
+
+static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
+{
+
+ if (localCommands) {
+ Jim_Obj *cmdNameObj;
+
+ while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
+ Jim_HashTable *ht = &interp->commands;
+ Jim_HashEntry *he = Jim_FindHashEntry(ht, cmdNameObj);
+ if (he) {
+ Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
+ if (cmd->prevCmd) {
+ Jim_Cmd *prevCmd = cmd->prevCmd;
+ cmd->prevCmd = NULL;
+
+
+ JimDecrCmdRefCount(interp, cmd);
+
+
+ Jim_SetHashVal(ht, he, prevCmd);
+ }
+ else {
+ Jim_DeleteHashEntry(ht, cmdNameObj);
+ }
+ }
+ Jim_DecrRefCount(interp, cmdNameObj);
+ }
+ Jim_FreeStack(localCommands);
+ Jim_Free(localCommands);
+ }
+ return JIM_OK;
+}
+
+static int JimInvokeDefer(Jim_Interp *interp, int retcode)
+{
+ Jim_Obj *objPtr;
+
+
+ if (JimFindVariable(&interp->framePtr->vars, interp->defer) == NULL) {
+ return retcode;
+ }
+ objPtr = Jim_GetVariable(interp, interp->defer, JIM_NONE);
+
+ if (objPtr) {
+ int ret = JIM_OK;
+ int i;
+ int listLen = Jim_ListLength(interp, objPtr);
+ Jim_Obj *resultObjPtr;
+
+ Jim_IncrRefCount(objPtr);
+
+ resultObjPtr = Jim_GetResult(interp);
+ Jim_IncrRefCount(resultObjPtr);
+ Jim_SetEmptyResult(interp);
+
+
+ for (i = listLen; i > 0; i--) {
+
+ Jim_Obj *scriptObjPtr = Jim_ListGetIndex(interp, objPtr, i - 1);
+ ret = Jim_EvalObj(interp, scriptObjPtr);
+ if (ret != JIM_OK) {
+ break;
+ }
+ }
+
+ if (ret == JIM_OK || retcode == JIM_ERR) {
+
+ Jim_SetResult(interp, resultObjPtr);
+ }
+ else {
+ retcode = ret;
+ }
+
+ Jim_DecrRefCount(interp, resultObjPtr);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+ return retcode;
+}
+
+#define JIM_FCF_FULL 0
+#define JIM_FCF_REUSE 1
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
+ {
+ JimDeleteLocalProcs(interp, cf->localCommands);
+
+ if (cf->procArgsObjPtr)
+ Jim_DecrRefCount(interp, cf->procArgsObjPtr);
+ if (cf->procBodyObjPtr)
+ Jim_DecrRefCount(interp, cf->procBodyObjPtr);
+ Jim_DecrRefCount(interp, cf->nsObj);
+ if (action == JIM_FCF_FULL || cf->vars.size != JIM_HT_INITIAL_SIZE)
+ Jim_FreeHashTable(&cf->vars);
+ else {
+ Jim_ClearHashTable(&cf->vars);
+ }
+ cf->next = interp->freeFramesList;
+ interp->freeFramesList = cf;
+}
+
+
+
+int Jim_IsBigEndian(void)
+{
+ union {
+ unsigned short s;
+ unsigned char c[2];
+ } uval = {0x0102};
+
+ return uval.c[0] == 1;
+}
+
+
+Jim_Interp *Jim_CreateInterp(void)
+{
+ Jim_Interp *i = Jim_Alloc(sizeof(*i));
+
+ memset(i, 0, sizeof(*i));
+
+ i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH;
+ i->maxEvalDepth = JIM_MAX_EVAL_DEPTH;
+ i->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+
+ Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
+#ifdef JIM_REFERENCES
+ Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
+#endif
+ Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
+ Jim_InitHashTable(&i->packages, &JimPackageHashTableType, NULL);
+ i->emptyObj = Jim_NewEmptyStringObj(i);
+ i->trueObj = Jim_NewIntObj(i, 1);
+ i->falseObj = Jim_NewIntObj(i, 0);
+ i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj);
+ i->result = i->emptyObj;
+ i->stackTrace = Jim_NewListObj(i, NULL, 0);
+ i->unknown = Jim_NewStringObj(i, "unknown", -1);
+ i->defer = Jim_NewStringObj(i, "jim::defer", -1);
+ i->errorProc = i->emptyObj;
+ i->nullScriptObj = Jim_NewEmptyStringObj(i);
+ i->evalFrame = &i->topEvalFrame;
+ i->currentFilenameObj = Jim_NewEmptyStringObj(i);
+ Jim_IncrRefCount(i->emptyObj);
+ Jim_IncrRefCount(i->result);
+ Jim_IncrRefCount(i->stackTrace);
+ Jim_IncrRefCount(i->unknown);
+ Jim_IncrRefCount(i->defer);
+ Jim_IncrRefCount(i->nullScriptObj);
+ Jim_IncrRefCount(i->errorProc);
+ Jim_IncrRefCount(i->trueObj);
+ Jim_IncrRefCount(i->falseObj);
+ Jim_IncrRefCount(i->currentFilenameObj);
+
+
+ Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
+ Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
+
+ Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim");
+ Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
+ Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM);
+ Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR);
+ Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
+ Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0");
+ Jim_SetVariableStrWithStr(i, "tcl_platform(bootstrap)", "0");
+ Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
+ Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
+ Jim_SetVariableStr(i, "tcl_platform(stackFormat)", Jim_NewIntObj(i, 4));
+
+ return i;
+}
+
+void Jim_FreeInterp(Jim_Interp *i)
+{
+ Jim_CallFrame *cf, *cfx;
+
+ Jim_Obj *objPtr, *nextObjPtr;
+
+ i->quitting = 1;
+
+
+ for (cf = i->framePtr; cf; cf = cfx) {
+
+ JimInvokeDefer(i, JIM_OK);
+ cfx = cf->parent;
+ JimFreeCallFrame(i, cf, JIM_FCF_FULL);
+ }
+
+
+ Jim_FreeHashTable(&i->commands);
+
+ Jim_DecrRefCount(i, i->emptyObj);
+ Jim_DecrRefCount(i, i->trueObj);
+ Jim_DecrRefCount(i, i->falseObj);
+ Jim_DecrRefCount(i, i->result);
+ Jim_DecrRefCount(i, i->stackTrace);
+ Jim_DecrRefCount(i, i->errorProc);
+ Jim_DecrRefCount(i, i->unknown);
+ Jim_DecrRefCount(i, i->defer);
+ Jim_DecrRefCount(i, i->nullScriptObj);
+ Jim_DecrRefCount(i, i->currentFilenameObj);
+
+
+ Jim_InterpIncrProcEpoch(i);
+
+#ifdef JIM_REFERENCES
+ Jim_FreeHashTable(&i->references);
+#endif
+ Jim_FreeHashTable(&i->packages);
+ Jim_Free(i->prngState);
+ Jim_FreeHashTable(&i->assocData);
+ if (i->traceCmdObj) {
+ Jim_DecrRefCount(i, i->traceCmdObj);
+ }
+
+#ifdef JIM_MAINTAINER
+ if (i->liveList != NULL) {
+ objPtr = i->liveList;
+
+ printf("\n-------------------------------------\n");
+ printf("Objects still in the free list:\n");
+ while (objPtr) {
+ const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
+ Jim_String(objPtr);
+
+ if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
+ printf("%p (%d) %-10s: '%.20s...'\n",
+ (void *)objPtr, objPtr->refCount, type, objPtr->bytes);
+ }
+ else {
+ printf("%p (%d) %-10s: '%s'\n",
+ (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
+ }
+ if (objPtr->typePtr == &sourceObjType) {
+ printf("FILE %s LINE %d\n",
+ Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
+ objPtr->internalRep.sourceValue.lineNumber);
+ }
+ objPtr = objPtr->nextObjPtr;
+ }
+ printf("-------------------------------------\n\n");
+ JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
+ }
+#endif
+
+
+ objPtr = i->freeList;
+ while (objPtr) {
+ nextObjPtr = objPtr->nextObjPtr;
+ Jim_Free(objPtr);
+ objPtr = nextObjPtr;
+ }
+
+
+ for (cf = i->freeFramesList; cf; cf = cfx) {
+ cfx = cf->next;
+ if (cf->vars.table)
+ Jim_FreeHashTable(&cf->vars);
+ Jim_Free(cf);
+ }
+
+
+ Jim_Free(i);
+}
+
+Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
+{
+ long level;
+ const char *str;
+ Jim_CallFrame *framePtr;
+
+ if (levelObjPtr) {
+ str = Jim_String(levelObjPtr);
+ if (str[0] == '#') {
+ char *endptr;
+
+ level = jim_strtol(str + 1, &endptr);
+ if (str[1] == '\0' || endptr[0] != '\0') {
+ level = -1;
+ }
+ }
+ else {
+ if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
+ level = -1;
+ }
+ else {
+
+ level = interp->framePtr->level - level;
+ }
+ }
+ }
+ else {
+ str = "1";
+ level = interp->framePtr->level - 1;
+ }
+
+ if (level == 0) {
+ return interp->topFramePtr;
+ }
+ if (level > 0) {
+
+ for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
+ if (framePtr->level == level) {
+ return framePtr;
+ }
+ }
+ }
+
+ Jim_SetResultFormatted(interp, "bad level \"%s\"", str);
+ return NULL;
+}
+
+static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, long level)
+{
+ Jim_CallFrame *framePtr;
+
+ if (level == 0) {
+ return interp->framePtr;
+ }
+
+ if (level < 0) {
+
+ level = interp->framePtr->level + level;
+ }
+
+ if (level > 0) {
+
+ for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
+ if (framePtr->level == level) {
+ return framePtr;
+ }
+ }
+ }
+ return NULL;
+}
+
+static Jim_EvalFrame *JimGetEvalFrameByProcLevel(Jim_Interp *interp, int proclevel)
+{
+ Jim_EvalFrame *evalFrame;
+
+ if (proclevel == 0) {
+ return interp->evalFrame;
+ }
+
+ if (proclevel < 0) {
+
+ proclevel = interp->procLevel + proclevel;
+ }
+
+ if (proclevel >= 0) {
+
+ for (evalFrame = interp->evalFrame; evalFrame; evalFrame = evalFrame->parent) {
+ if (evalFrame->procLevel == proclevel) {
+ return evalFrame;
+ }
+ }
+ }
+ return NULL;
+}
+
+static Jim_Obj *JimProcForEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame)
+{
+ if (frame == interp->evalFrame || (frame->cmd && frame->cmd->cmdNameObj)) {
+ Jim_EvalFrame *e;
+ for (e = frame->parent; e; e = e->parent) {
+ if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) {
+ break;
+ }
+ }
+ if (e && e->cmd && e->cmd->cmdNameObj) {
+ return e->cmd->cmdNameObj;
+ }
+ }
+ return NULL;
+}
+
+static void JimAddStackFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *listObj)
+{
+ Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
+ Jim_Obj *fileNameObj = interp->emptyObj;
+ int linenr = 1;
+
+ if (frame->scriptObj) {
+ ScriptObj *script = JimGetScript(interp, frame->scriptObj);
+ fileNameObj = script->fileNameObj;
+ linenr = script->linenr;
+ }
+
+ Jim_ListAppendElement(interp, listObj, procNameObj ? procNameObj : interp->emptyObj);
+ Jim_ListAppendElement(interp, listObj, fileNameObj);
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr));
+ Jim_ListAppendElement(interp, listObj, Jim_NewListObj(interp, frame->argv, frame->argc));
+}
+
+static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
+{
+
+ Jim_IncrRefCount(stackTraceObj);
+ Jim_DecrRefCount(interp, interp->stackTrace);
+ interp->stackTrace = stackTraceObj;
+ interp->errorFlag = 1;
+}
+
+static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script)
+{
+ if (!interp->errorFlag) {
+ int i;
+ Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
+
+ if (interp->procLevel == 0 && script) {
+ Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
+ Jim_ListAppendElement(interp, stackTrace, script->fileNameObj);
+ Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr));
+ Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
+ }
+ else {
+ for (i = 0; i <= interp->procLevel; i++) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
+ if (frame) {
+ JimAddStackFrame(interp, frame, stackTrace);
+ }
+ }
+ }
+ JimSetStackTrace(interp, stackTrace);
+ }
+}
+
+int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
+ void *data)
+{
+ AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue));
+
+ assocEntryPtr->delProc = delProc;
+ assocEntryPtr->data = data;
+ return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
+}
+
+void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
+{
+ Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
+
+ if (entryPtr != NULL) {
+ AssocDataValue *assocEntryPtr = Jim_GetHashEntryVal(entryPtr);
+ return assocEntryPtr->data;
+ }
+ return NULL;
+}
+
+int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
+{
+ return Jim_DeleteHashEntry(&interp->assocData, key);
+}
+
+int Jim_GetExitCode(Jim_Interp *interp)
+{
+ return interp->exitCode;
+}
+
+static void UpdateStringOfInt(struct Jim_Obj *objPtr);
+static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
+
+static const Jim_ObjType intObjType = {
+ "int",
+ NULL,
+ NULL,
+ UpdateStringOfInt,
+ JIM_TYPE_NONE,
+};
+
+static const Jim_ObjType coercedDoubleObjType = {
+ "coerced-double",
+ NULL,
+ NULL,
+ UpdateStringOfInt,
+ JIM_TYPE_NONE,
+};
+
+
+static void UpdateStringOfInt(struct Jim_Obj *objPtr)
+{
+ char buf[JIM_INTEGER_SPACE + 1];
+ jim_wide wideValue = JimWideValue(objPtr);
+ int pos = 0;
+
+ if (wideValue == 0) {
+ buf[pos++] = '0';
+ }
+ else {
+ char tmp[JIM_INTEGER_SPACE];
+ int num = 0;
+ int i;
+
+ if (wideValue < 0) {
+ buf[pos++] = '-';
+ i = wideValue % 10;
+ tmp[num++] = (i > 0) ? (10 - i) : -i;
+ wideValue /= -10;
+ }
+
+ while (wideValue) {
+ tmp[num++] = wideValue % 10;
+ wideValue /= 10;
+ }
+
+ for (i = 0; i < num; i++) {
+ buf[pos++] = '0' + tmp[num - i - 1];
+ }
+ }
+ buf[pos] = 0;
+
+ JimSetStringBytes(objPtr, buf);
+}
+
+static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ jim_wide wideValue;
+ const char *str;
+
+ if (objPtr->typePtr == &coercedDoubleObjType) {
+
+ objPtr->typePtr = &intObjType;
+ return JIM_OK;
+ }
+
+
+ str = Jim_String(objPtr);
+
+ if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
+ }
+ return JIM_ERR;
+ }
+ if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
+ Jim_SetResultString(interp, "Integer value too big to be represented", -1);
+ return JIM_ERR;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &intObjType;
+ objPtr->internalRep.wideValue = wideValue;
+ return JIM_OK;
+}
+
+#ifdef JIM_OPTIMIZATION
+static int JimIsWide(Jim_Obj *objPtr)
+{
+ return objPtr->typePtr == &intObjType;
+}
+#endif
+
+int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+ if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
+ return JIM_ERR;
+ *widePtr = JimWideValue(objPtr);
+ return JIM_OK;
+}
+
+int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+ int ret = JIM_OK;
+
+ if (objPtr->typePtr == &sourceObjType || objPtr->typePtr == NULL) {
+ SetIntFromAny(interp, objPtr, 0);
+ }
+ if (objPtr->typePtr == &intObjType) {
+ *widePtr = JimWideValue(objPtr);
+ }
+ else {
+ JimPanic((interp->safeexpr, "interp->safeexpr is set"));
+ interp->safeexpr++;
+ ret = Jim_EvalExpression(interp, objPtr);
+ interp->safeexpr--;
+
+ if (ret == JIM_OK) {
+ ret = Jim_GetWide(interp, Jim_GetResult(interp), widePtr);
+ }
+ if (ret != JIM_OK) {
+ Jim_SetResultFormatted(interp, "expected integer expression but got \"%#s\"", objPtr);
+ }
+ }
+ return ret;
+}
+
+
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+ if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
+ return JIM_ERR;
+ *widePtr = JimWideValue(objPtr);
+ return JIM_OK;
+}
+
+int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
+{
+ jim_wide wideValue;
+ int retval;
+
+ retval = Jim_GetWide(interp, objPtr, &wideValue);
+ if (retval == JIM_OK) {
+ *longPtr = (long)wideValue;
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
+{
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &intObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.wideValue = wideValue;
+ return objPtr;
+}
+
+#define JIM_DOUBLE_SPACE 30
+
+static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
+static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+
+static const Jim_ObjType doubleObjType = {
+ "double",
+ NULL,
+ NULL,
+ UpdateStringOfDouble,
+ JIM_TYPE_NONE,
+};
+
+#if !HAVE_DECL_ISNAN
+#undef isnan
+#define isnan(X) ((X) != (X))
+#endif
+#if !HAVE_DECL_ISINF
+#undef isinf
+#define isinf(X) (1.0 / (X) == 0.0)
+#endif
+
+static void UpdateStringOfDouble(struct Jim_Obj *objPtr)
+{
+ double value = objPtr->internalRep.doubleValue;
+
+ if (isnan(value)) {
+ JimSetStringBytes(objPtr, "NaN");
+ return;
+ }
+ if (isinf(value)) {
+ if (value < 0) {
+ JimSetStringBytes(objPtr, "-Inf");
+ }
+ else {
+ JimSetStringBytes(objPtr, "Inf");
+ }
+ return;
+ }
+ {
+ char buf[JIM_DOUBLE_SPACE + 1];
+ int i;
+ int len = sprintf(buf, "%.12g", value);
+
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '.' || buf[i] == 'e') {
+#if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
+ char *e = strchr(buf, 'e');
+ if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
+
+ e += 2;
+ memmove(e, e + 1, len - (e - buf));
+ }
+#endif
+ break;
+ }
+ }
+ if (buf[i] == '\0') {
+ buf[i++] = '.';
+ buf[i++] = '0';
+ buf[i] = '\0';
+ }
+ JimSetStringBytes(objPtr, buf);
+ }
+}
+
+static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ double doubleValue;
+ jim_wide wideValue;
+ const char *str;
+
+#ifdef HAVE_LONG_LONG
+
+#define MIN_INT_IN_DOUBLE -(1LL << 53)
+#define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
+
+ if (objPtr->typePtr == &intObjType
+ && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
+ && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
+
+
+ objPtr->typePtr = &coercedDoubleObjType;
+ return JIM_OK;
+ }
+#endif
+ str = Jim_String(objPtr);
+
+ if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &coercedDoubleObjType;
+ objPtr->internalRep.wideValue = wideValue;
+ return JIM_OK;
+ }
+ else {
+
+ if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr);
+ return JIM_ERR;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ }
+ objPtr->typePtr = &doubleObjType;
+ objPtr->internalRep.doubleValue = doubleValue;
+ return JIM_OK;
+}
+
+int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
+{
+ if (objPtr->typePtr == &coercedDoubleObjType) {
+ *doublePtr = JimWideValue(objPtr);
+ return JIM_OK;
+ }
+ if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR)
+ return JIM_ERR;
+
+ if (objPtr->typePtr == &coercedDoubleObjType) {
+ *doublePtr = JimWideValue(objPtr);
+ }
+ else {
+ *doublePtr = objPtr->internalRep.doubleValue;
+ }
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
+{
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &doubleObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.doubleValue = doubleValue;
+ return objPtr;
+}
+
+static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
+
+int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, int * booleanPtr)
+{
+ if (objPtr->typePtr != &intObjType && SetBooleanFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
+ return JIM_ERR;
+ *booleanPtr = (int) JimWideValue(objPtr);
+ return JIM_OK;
+}
+
+static const char * const jim_true_false_strings[8] = {
+ "1", "true", "yes", "on",
+ "0", "false", "no", "off"
+};
+
+static const int jim_true_false_lens[8] = {
+ 1, 4, 3, 2,
+ 1, 5, 2, 3,
+};
+
+static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ int index = Jim_FindByName(Jim_String(objPtr), jim_true_false_strings,
+ sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings));
+ if (index < 0) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "expected boolean but got \"%#s\"", objPtr);
+ }
+ return JIM_ERR;
+ }
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &intObjType;
+
+ objPtr->internalRep.wideValue = index < 4 ? 1 : 0;
+ return JIM_OK;
+}
+
+static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
+static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfList(struct Jim_Obj *objPtr);
+static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType listObjType = {
+ "list",
+ FreeListInternalRep,
+ DupListInternalRep,
+ UpdateStringOfList,
+ JIM_TYPE_NONE,
+};
+
+void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int i;
+
+ for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
+ Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
+ }
+ Jim_Free(objPtr->internalRep.listValue.ele);
+}
+
+void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ int i;
+
+ JIM_NOTUSED(interp);
+
+ dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
+ dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
+ dupPtr->internalRep.listValue.ele =
+ Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen);
+ memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
+ sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len);
+ for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
+ Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
+ }
+ dupPtr->typePtr = &listObjType;
+}
+
+#define JIM_ELESTR_SIMPLE 0
+#define JIM_ELESTR_BRACE 1
+#define JIM_ELESTR_QUOTE 2
+static unsigned char ListElementQuotingType(const char *s, int len)
+{
+ int i, level, blevel, trySimple = 1;
+
+
+ if (len == 0)
+ return JIM_ELESTR_BRACE;
+ if (s[0] == '"' || s[0] == '{') {
+ trySimple = 0;
+ goto testbrace;
+ }
+ for (i = 0; i < len; i++) {
+ switch (s[i]) {
+ case ' ':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case ';':
+ case '\\':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '\f':
+ case '\v':
+ trySimple = 0;
+
+ case '{':
+ case '}':
+ goto testbrace;
+ }
+ }
+ return JIM_ELESTR_SIMPLE;
+
+ testbrace:
+
+ if (s[len - 1] == '\\')
+ return JIM_ELESTR_QUOTE;
+ level = 0;
+ blevel = 0;
+ for (i = 0; i < len; i++) {
+ switch (s[i]) {
+ case '{':
+ level++;
+ break;
+ case '}':
+ level--;
+ if (level < 0)
+ return JIM_ELESTR_QUOTE;
+ break;
+ case '[':
+ blevel++;
+ break;
+ case ']':
+ blevel--;
+ break;
+ case '\\':
+ if (s[i + 1] == '\n')
+ return JIM_ELESTR_QUOTE;
+ else if (s[i + 1] != '\0')
+ i++;
+ break;
+ }
+ }
+ if (blevel < 0) {
+ return JIM_ELESTR_QUOTE;
+ }
+
+ if (level == 0) {
+ if (!trySimple)
+ return JIM_ELESTR_BRACE;
+ for (i = 0; i < len; i++) {
+ switch (s[i]) {
+ case ' ':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case ';':
+ case '\\':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '\f':
+ case '\v':
+ return JIM_ELESTR_BRACE;
+ break;
+ }
+ }
+ return JIM_ELESTR_SIMPLE;
+ }
+ return JIM_ELESTR_QUOTE;
+}
+
+static int BackslashQuoteString(const char *s, int len, char *q)
+{
+ char *p = q;
+
+ while (len--) {
+ switch (*s) {
+ case ' ':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case ';':
+ case '\\':
+ *p++ = '\\';
+ *p++ = *s++;
+ break;
+ case '\n':
+ *p++ = '\\';
+ *p++ = 'n';
+ s++;
+ break;
+ case '\r':
+ *p++ = '\\';
+ *p++ = 'r';
+ s++;
+ break;
+ case '\t':
+ *p++ = '\\';
+ *p++ = 't';
+ s++;
+ break;
+ case '\f':
+ *p++ = '\\';
+ *p++ = 'f';
+ s++;
+ break;
+ case '\v':
+ *p++ = '\\';
+ *p++ = 'v';
+ s++;
+ break;
+ default:
+ *p++ = *s++;
+ break;
+ }
+ }
+ *p = '\0';
+
+ return p - q;
+}
+
+static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
+{
+ #define STATIC_QUOTING_LEN 32
+ int i, bufLen, realLength;
+ const char *strRep;
+ char *p;
+ unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
+
+
+ if (objc > STATIC_QUOTING_LEN) {
+ quotingType = Jim_Alloc(objc);
+ }
+ else {
+ quotingType = staticQuoting;
+ }
+ bufLen = 0;
+ for (i = 0; i < objc; i++) {
+ int len;
+
+ strRep = Jim_GetString(objv[i], &len);
+ quotingType[i] = ListElementQuotingType(strRep, len);
+ switch (quotingType[i]) {
+ case JIM_ELESTR_SIMPLE:
+ if (i != 0 || strRep[0] != '#') {
+ bufLen += len;
+ break;
+ }
+
+ quotingType[i] = JIM_ELESTR_BRACE;
+
+ case JIM_ELESTR_BRACE:
+ bufLen += len + 2;
+ break;
+ case JIM_ELESTR_QUOTE:
+ bufLen += len * 2;
+ break;
+ }
+ bufLen++;
+ }
+ bufLen++;
+
+
+ p = objPtr->bytes = Jim_Alloc(bufLen + 1);
+ realLength = 0;
+ for (i = 0; i < objc; i++) {
+ int len, qlen;
+
+ strRep = Jim_GetString(objv[i], &len);
+
+ switch (quotingType[i]) {
+ case JIM_ELESTR_SIMPLE:
+ memcpy(p, strRep, len);
+ p += len;
+ realLength += len;
+ break;
+ case JIM_ELESTR_BRACE:
+ *p++ = '{';
+ memcpy(p, strRep, len);
+ p += len;
+ *p++ = '}';
+ realLength += len + 2;
+ break;
+ case JIM_ELESTR_QUOTE:
+ if (i == 0 && strRep[0] == '#') {
+ *p++ = '\\';
+ realLength++;
+ }
+ qlen = BackslashQuoteString(strRep, len, p);
+ p += qlen;
+ realLength += qlen;
+ break;
+ }
+
+ if (i + 1 != objc) {
+ *p++ = ' ';
+ realLength++;
+ }
+ }
+ *p = '\0';
+ objPtr->length = realLength;
+
+ if (quotingType != staticQuoting) {
+ Jim_Free(quotingType);
+ }
+}
+
+static void UpdateStringOfList(struct Jim_Obj *objPtr)
+{
+ JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
+}
+
+static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ struct JimParserCtx parser;
+ const char *str;
+ int strLen;
+ Jim_Obj *fileNameObj;
+ int linenr;
+
+ if (objPtr->typePtr == &listObjType) {
+ return JIM_OK;
+ }
+
+
+ if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) {
+ Jim_Dict *dict = objPtr->internalRep.dictValue;
+
+
+ objPtr->typePtr = &listObjType;
+ objPtr->internalRep.listValue.len = dict->len;
+ objPtr->internalRep.listValue.maxLen = dict->maxLen;
+ objPtr->internalRep.listValue.ele = dict->table;
+
+
+ Jim_Free(dict->ht);
+
+
+ Jim_Free(dict);
+ return JIM_OK;
+ }
+
+
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr);
+ Jim_IncrRefCount(fileNameObj);
+
+
+ str = Jim_GetString(objPtr, &strLen);
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &listObjType;
+ objPtr->internalRep.listValue.len = 0;
+ objPtr->internalRep.listValue.maxLen = 0;
+ objPtr->internalRep.listValue.ele = NULL;
+
+
+ if (strLen) {
+ JimParserInit(&parser, str, strLen, linenr);
+ while (!parser.eof) {
+ Jim_Obj *elementPtr;
+
+ JimParseList(&parser);
+ if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
+ continue;
+ elementPtr = JimParserGetTokenObj(interp, &parser);
+ Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
+ ListAppendElement(objPtr, elementPtr);
+ }
+ }
+ Jim_DecrRefCount(interp, fileNameObj);
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &listObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.listValue.ele = NULL;
+ objPtr->internalRep.listValue.len = 0;
+ objPtr->internalRep.listValue.maxLen = 0;
+
+ if (len) {
+ ListInsertElements(objPtr, 0, len, elements);
+ }
+
+ return objPtr;
+}
+
+static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen,
+ Jim_Obj ***listVec)
+{
+ *listLen = Jim_ListLength(interp, listObj);
+ *listVec = listObj->internalRep.listValue.ele;
+}
+
+
+static int JimSign(jim_wide w)
+{
+ if (w == 0) {
+ return 0;
+ }
+ else if (w < 0) {
+ return -1;
+ }
+ return 1;
+}
+
+
+struct lsort_info {
+ jmp_buf jmpbuf;
+ Jim_Obj *command;
+ Jim_Interp *interp;
+ enum {
+ JIM_LSORT_ASCII,
+ JIM_LSORT_NOCASE,
+ JIM_LSORT_INTEGER,
+ JIM_LSORT_REAL,
+ JIM_LSORT_COMMAND,
+ JIM_LSORT_DICT
+ } type;
+ int order;
+ Jim_Obj **indexv;
+ int indexc;
+ int unique;
+ int (*subfn)(Jim_Obj **, Jim_Obj **);
+};
+
+static struct lsort_info *sort_info;
+
+static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ Jim_Obj *lObj, *rObj;
+
+ if (Jim_ListIndices(sort_info->interp, *lhsObj, sort_info->indexv, sort_info->indexc, &lObj, JIM_ERRMSG) != JIM_OK ||
+ Jim_ListIndices(sort_info->interp, *rhsObj, sort_info->indexv, sort_info->indexc, &rObj, JIM_ERRMSG) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, JIM_ERR);
+ }
+ return sort_info->subfn(&lObj, &rObj);
+}
+
+
+static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
+}
+
+static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
+}
+
+static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+
+ const char *left = Jim_String(*lhsObj);
+ const char *right = Jim_String(*rhsObj);
+
+ while (1) {
+ if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) {
+
+ jim_wide lint, rint;
+ char *lend, *rend;
+ lint = jim_strtoull(left, &lend);
+ rint = jim_strtoull(right, &rend);
+ if (lint != rint) {
+ return JimSign(lint - rint) * sort_info->order;
+ }
+ if (lend -left != rend - right) {
+ return JimSign((lend - left) - (rend - right)) * sort_info->order;
+ }
+ left = lend;
+ right = rend;
+ }
+ else {
+ int cl, cr;
+ left += utf8_tounicode_case(left, &cl, 1);
+ right += utf8_tounicode_case(right, &cr, 1);
+ if (cl != cr) {
+ return JimSign(cl - cr) * sort_info->order;
+ }
+ if (cl == 0) {
+
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
+ }
+ }
+ }
+}
+
+static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ jim_wide lhs = 0, rhs = 0;
+
+ if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
+ Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, JIM_ERR);
+ }
+
+ return JimSign(lhs - rhs) * sort_info->order;
+}
+
+static int ListSortReal(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ double lhs = 0, rhs = 0;
+
+ if (Jim_GetDouble(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
+ Jim_GetDouble(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, JIM_ERR);
+ }
+ if (lhs == rhs) {
+ return 0;
+ }
+ if (lhs > rhs) {
+ return sort_info->order;
+ }
+ return -sort_info->order;
+}
+
+static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ Jim_Obj *compare_script;
+ int rc;
+
+ jim_wide ret = 0;
+
+
+ compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
+ Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
+ Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
+
+ rc = Jim_EvalObj(sort_info->interp, compare_script);
+
+ if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, rc);
+ }
+
+ return JimSign(ret) * sort_info->order;
+}
+
+static void ListRemoveDuplicates(Jim_Obj *listObjPtr, int (*comp)(Jim_Obj **lhs, Jim_Obj **rhs))
+{
+ int src;
+ int dst = 0;
+ Jim_Obj **ele = listObjPtr->internalRep.listValue.ele;
+
+ for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) {
+ if (comp(&ele[dst], &ele[src]) == 0) {
+
+ Jim_DecrRefCount(sort_info->interp, ele[dst]);
+ }
+ else {
+
+ dst++;
+ }
+ ele[dst] = ele[src];
+ }
+
+
+ dst++;
+ if (dst < listObjPtr->internalRep.listValue.len) {
+ ele[dst] = ele[src];
+ }
+
+
+ listObjPtr->internalRep.listValue.len = dst;
+}
+
+
+static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
+{
+ struct lsort_info *prev_info;
+
+ typedef int (qsort_comparator) (const void *, const void *);
+ int (*fn) (Jim_Obj **, Jim_Obj **);
+ Jim_Obj **vector;
+ int len;
+ int rc;
+
+ JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object"));
+ SetListFromAny(interp, listObjPtr);
+
+
+ prev_info = sort_info;
+ sort_info = info;
+
+ vector = listObjPtr->internalRep.listValue.ele;
+ len = listObjPtr->internalRep.listValue.len;
+ switch (info->type) {
+ case JIM_LSORT_ASCII:
+ fn = ListSortString;
+ break;
+ case JIM_LSORT_NOCASE:
+ fn = ListSortStringNoCase;
+ break;
+ case JIM_LSORT_INTEGER:
+ fn = ListSortInteger;
+ break;
+ case JIM_LSORT_REAL:
+ fn = ListSortReal;
+ break;
+ case JIM_LSORT_COMMAND:
+ fn = ListSortCommand;
+ break;
+ case JIM_LSORT_DICT:
+ fn = ListSortDict;
+ break;
+ default:
+ fn = NULL;
+ JimPanic((1, "ListSort called with invalid sort type"));
+ return -1;
+ }
+
+ if (info->indexc) {
+
+ info->subfn = fn;
+ fn = ListSortIndexHelper;
+ }
+
+ if ((rc = setjmp(info->jmpbuf)) == 0) {
+ qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn);
+
+ if (info->unique && len > 1) {
+ ListRemoveDuplicates(listObjPtr, fn);
+ }
+
+ Jim_InvalidateStringRep(listObjPtr);
+ }
+ sort_info = prev_info;
+
+ return rc;
+}
+
+
+static void ListEnsureLength(Jim_Obj *listPtr, int idx)
+{
+ assert(idx >= 0);
+ if (idx >= listPtr->internalRep.listValue.maxLen) {
+ if (idx < 4) {
+
+ idx = 4;
+ }
+ listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
+ sizeof(Jim_Obj *) * idx);
+
+ listPtr->internalRep.listValue.maxLen = idx;
+ }
+}
+
+static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
+{
+ int currentLen = listPtr->internalRep.listValue.len;
+ int requiredLen = currentLen + elemc;
+ int i;
+ Jim_Obj **point;
+
+ if (elemc == 0) {
+
+ return;
+ }
+
+ if (requiredLen > listPtr->internalRep.listValue.maxLen) {
+ if (currentLen) {
+
+ requiredLen *= 2;
+ }
+ ListEnsureLength(listPtr, requiredLen);
+ }
+ if (idx < 0) {
+ idx = currentLen;
+ }
+ point = listPtr->internalRep.listValue.ele + idx;
+ memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
+ for (i = 0; i < elemc; ++i) {
+ point[i] = elemVec[i];
+ Jim_IncrRefCount(point[i]);
+ }
+ listPtr->internalRep.listValue.len += elemc;
+}
+
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+ ListInsertElements(listPtr, -1, 1, &objPtr);
+}
+
+static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+ ListInsertElements(listPtr, -1,
+ appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele);
+}
+
+void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+ JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object"));
+ SetListFromAny(interp, listPtr);
+ Jim_InvalidateStringRep(listPtr);
+ ListAppendElement(listPtr, objPtr);
+}
+
+void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+ JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object"));
+ SetListFromAny(interp, listPtr);
+ SetListFromAny(interp, appendListPtr);
+ Jim_InvalidateStringRep(listPtr);
+ ListAppendList(listPtr, appendListPtr);
+}
+
+int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ SetListFromAny(interp, objPtr);
+ return objPtr->internalRep.listValue.len;
+}
+
+void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+ int objc, Jim_Obj *const *objVec)
+{
+ JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object"));
+ SetListFromAny(interp, listPtr);
+ if (idx >= 0 && idx > listPtr->internalRep.listValue.len)
+ idx = listPtr->internalRep.listValue.len;
+ else if (idx < 0)
+ idx = 0;
+ Jim_InvalidateStringRep(listPtr);
+ ListInsertElements(listPtr, idx, objc, objVec);
+}
+
+Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx)
+{
+ SetListFromAny(interp, listPtr);
+ if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+ (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+ return NULL;
+ }
+ if (idx < 0)
+ idx = listPtr->internalRep.listValue.len + idx;
+ return listPtr->internalRep.listValue.ele[idx];
+}
+
+int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags)
+{
+ *objPtrPtr = Jim_ListGetIndex(interp, listPtr, idx);
+ if (*objPtrPtr == NULL) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultString(interp, "list index out of range", -1);
+ }
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr,
+ Jim_Obj *const *indexv, int indexc, Jim_Obj **resultObj, int flags)
+{
+ int i;
+ int static_idxes[5];
+ int *idxes = static_idxes;
+ int ret = JIM_OK;
+
+ if (indexc > sizeof(static_idxes) / sizeof(*static_idxes)) {
+ idxes = Jim_Alloc(indexc * sizeof(*idxes));
+ }
+
+ for (i = 0; i < indexc; i++) {
+ ret = Jim_GetIndex(interp, indexv[i], &idxes[i]);
+ if (ret != JIM_OK) {
+ goto err;
+ }
+ }
+
+ for (i = 0; i < indexc; i++) {
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, listPtr, idxes[i]);
+ if (!objPtr) {
+ if (flags & JIM_ERRMSG) {
+ if (idxes[i] < 0 || idxes[i] > Jim_ListLength(interp, listPtr)) {
+ Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
+ }
+ else {
+ Jim_SetResultFormatted(interp, "element %#s missing from sublist \"%#s\"", indexv[i], listPtr);
+ }
+ }
+ return -1;
+ }
+ listPtr = objPtr;
+ }
+ *resultObj = listPtr;
+err:
+ if (idxes != static_idxes)
+ Jim_Free(idxes);
+ return ret;
+}
+
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+ Jim_Obj *newObjPtr, int flags)
+{
+ SetListFromAny(interp, listPtr);
+ if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+ (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultString(interp, "list index out of range", -1);
+ }
+ return JIM_ERR;
+ }
+ if (idx < 0)
+ idx = listPtr->internalRep.listValue.len + idx;
+ Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
+ listPtr->internalRep.listValue.ele[idx] = newObjPtr;
+ Jim_IncrRefCount(newObjPtr);
+ return JIM_OK;
+}
+
+int Jim_ListSetIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
+ Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
+{
+ Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
+ int shared, i, idx;
+
+ varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED);
+ if (objPtr == NULL)
+ return JIM_ERR;
+ if ((shared = Jim_IsShared(objPtr)))
+ varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+ for (i = 0; i < indexc - 1; i++) {
+ listObjPtr = objPtr;
+ if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK)
+ goto err;
+
+ objPtr = Jim_ListGetIndex(interp, listObjPtr, idx);
+ if (objPtr == NULL) {
+ Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
+ goto err;
+ }
+ if (Jim_IsShared(objPtr)) {
+ objPtr = Jim_DuplicateObj(interp, objPtr);
+ ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE);
+ }
+ Jim_InvalidateStringRep(listObjPtr);
+ }
+ if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK)
+ goto err;
+ if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR)
+ goto err;
+ Jim_InvalidateStringRep(objPtr);
+ Jim_InvalidateStringRep(varObjPtr);
+ if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
+ goto err;
+ Jim_SetResult(interp, varObjPtr);
+ return JIM_OK;
+ err:
+ if (shared) {
+ Jim_FreeNewObj(interp, varObjPtr);
+ }
+ return JIM_ERR;
+}
+
+Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen)
+{
+ int i;
+ int listLen = Jim_ListLength(interp, listObjPtr);
+ Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp);
+
+ for (i = 0; i < listLen; ) {
+ Jim_AppendObj(interp, resObjPtr, Jim_ListGetIndex(interp, listObjPtr, i));
+ if (++i != listLen) {
+ Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
+ }
+ }
+ return resObjPtr;
+}
+
+Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ int i;
+
+ for (i = 0; i < objc; i++) {
+ if (!Jim_IsList(objv[i]))
+ break;
+ }
+ if (i == objc) {
+ Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; i < objc; i++)
+ ListAppendList(objPtr, objv[i]);
+ return objPtr;
+ }
+ else {
+
+ int len = 0, objLen;
+ char *bytes, *p;
+
+
+ for (i = 0; i < objc; i++) {
+ len += Jim_Length(objv[i]);
+ }
+ if (objc)
+ len += objc - 1;
+
+ p = bytes = Jim_Alloc(len + 1);
+ for (i = 0; i < objc; i++) {
+ const char *s = Jim_GetString(objv[i], &objLen);
+
+
+ while (objLen && isspace(UCHAR(*s))) {
+ s++;
+ objLen--;
+ len--;
+ }
+
+ while (objLen && isspace(UCHAR(s[objLen - 1]))) {
+
+ if (objLen > 1 && s[objLen - 2] == '\\') {
+ break;
+ }
+ objLen--;
+ len--;
+ }
+ memcpy(p, s, objLen);
+ p += objLen;
+ if (i + 1 != objc) {
+ if (objLen)
+ *p++ = ' ';
+ else {
+ len--;
+ }
+ }
+ }
+ *p = '\0';
+ return Jim_NewStringObjNoAlloc(interp, bytes, len);
+ }
+}
+
+Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr,
+ Jim_Obj *lastObjPtr)
+{
+ int first, last;
+ int len, rangeLen;
+
+ if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
+ Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
+ return NULL;
+ len = Jim_ListLength(interp, listObjPtr);
+ first = JimRelToAbsIndex(len, first);
+ last = JimRelToAbsIndex(len, last);
+ JimRelToAbsRange(len, &first, &last, &rangeLen);
+ if (first == 0 && last == len) {
+ return listObjPtr;
+ }
+ return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen);
+}
+
+static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfDict(struct Jim_Obj *objPtr);
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+
+static const Jim_ObjType dictObjType = {
+ "dict",
+ FreeDictInternalRep,
+ DupDictInternalRep,
+ UpdateStringOfDict,
+ JIM_TYPE_NONE,
+};
+
+static void JimFreeDict(Jim_Interp *interp, Jim_Dict *dict)
+{
+ int i;
+ for (i = 0; i < dict->len; i++) {
+ Jim_DecrRefCount(interp, dict->table[i]);
+ }
+ Jim_Free(dict->table);
+ Jim_Free(dict->ht);
+ Jim_Free(dict);
+}
+
+enum {
+ DICT_HASH_FIND = -1,
+ DICT_HASH_REMOVE = -2,
+ DICT_HASH_ADD = -3,
+};
+
+static int JimDictHashFind(Jim_Dict *dict, Jim_Obj *keyObjPtr, int op_tvoffset)
+{
+ unsigned h = (JimObjectHTHashFunction(keyObjPtr) + dict->uniq);
+ unsigned idx = h & dict->sizemask;
+ int tvoffset = 0;
+ unsigned peturb = h;
+ unsigned first_removed = ~0;
+
+ if (dict->len) {
+ while ((tvoffset = dict->ht[idx].offset)) {
+ if (tvoffset == -1) {
+ if (first_removed == ~0) {
+ first_removed = idx;
+ }
+ }
+ else if (dict->ht[idx].hash == h) {
+ if (Jim_StringEqObj(keyObjPtr, dict->table[tvoffset - 1])) {
+ break;
+ }
+ }
+
+ peturb >>= 5;
+ idx = (5 * idx + 1 + peturb) & dict->sizemask;
+ }
+ }
+
+ switch (op_tvoffset) {
+ case DICT_HASH_FIND:
+
+ break;
+ case DICT_HASH_REMOVE:
+ if (tvoffset) {
+
+ dict->ht[idx].offset = -1;
+ dict->dummy++;
+ }
+
+ break;
+ case DICT_HASH_ADD:
+ if (tvoffset == 0) {
+
+ if (first_removed != ~0) {
+ idx = first_removed;
+ dict->dummy--;
+ }
+ dict->ht[idx].offset = dict->len + 1;
+ dict->ht[idx].hash = h;
+ }
+
+ break;
+ default:
+ assert(tvoffset);
+
+ dict->ht[idx].offset = op_tvoffset;
+ break;
+ }
+
+ return tvoffset;
+}
+
+static void JimDictExpandHashTable(Jim_Dict *dict, unsigned int size)
+{
+ int i;
+ struct JimDictHashEntry *prevht = dict->ht;
+ int prevsize = dict->size;
+
+ dict->size = JimHashTableNextPower(size);
+ dict->sizemask = dict->size - 1;
+
+
+ dict->ht = Jim_Alloc(dict->size * sizeof(*dict->ht));
+ memset(dict->ht, 0, dict->size * sizeof(*dict->ht));
+
+
+ for (i = 0; i < prevsize; i++) {
+ if (prevht[i].offset > 0) {
+
+ unsigned h = prevht[i].hash;
+ unsigned idx = h & dict->sizemask;
+ unsigned peturb = h;
+
+ while (dict->ht[idx].offset) {
+ peturb >>= 5;
+ idx = (5 * idx + 1 + peturb) & dict->sizemask;
+ }
+ dict->ht[idx].offset = prevht[i].offset;
+ dict->ht[idx].hash = h;
+ }
+ }
+ Jim_Free(prevht);
+}
+
+static int JimDictAdd(Jim_Dict *dict, Jim_Obj *keyObjPtr)
+{
+ if (dict->size <= dict->len + dict->dummy) {
+ JimDictExpandHashTable(dict, dict->size ? dict->size * 2 : 8);
+ }
+ return JimDictHashFind(dict, keyObjPtr, DICT_HASH_ADD);
+}
+
+static Jim_Dict *JimDictNew(Jim_Interp *interp, int table_size, int ht_size)
+{
+ Jim_Dict *dict = Jim_Alloc(sizeof(*dict));
+ memset(dict, 0, sizeof(*dict));
+
+ if (ht_size) {
+ JimDictExpandHashTable(dict, ht_size);
+ }
+ if (table_size) {
+ dict->table = Jim_Alloc(table_size * sizeof(*dict->table));
+ dict->maxLen = table_size;
+ }
+#ifdef JIM_RANDOMISE_HASH
+ dict->uniq = (rand() ^ time(NULL) ^ clock());
+#endif
+ return dict;
+}
+
+static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ JimFreeDict(interp, objPtr->internalRep.dictValue);
+}
+
+static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ Jim_Dict *oldDict = srcPtr->internalRep.dictValue;
+ int i;
+
+
+ Jim_Dict *newDict = JimDictNew(interp, oldDict->maxLen, oldDict->size);
+
+
+ for (i = 0; i < oldDict->len; i++) {
+ newDict->table[i] = oldDict->table[i];
+ Jim_IncrRefCount(newDict->table[i]);
+ }
+ newDict->len = oldDict->len;
+
+
+ newDict->uniq = oldDict->uniq;
+
+
+ memcpy(newDict->ht, oldDict->ht, sizeof(*oldDict->ht) * oldDict->size);
+
+ dupPtr->internalRep.dictValue = newDict;
+ dupPtr->typePtr = &dictObjType;
+}
+
+static void UpdateStringOfDict(struct Jim_Obj *objPtr)
+{
+ JimMakeListStringRep(objPtr, objPtr->internalRep.dictValue->table, objPtr->internalRep.dictValue->len);
+}
+
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ int listlen;
+
+ if (objPtr->typePtr == &dictObjType) {
+ return JIM_OK;
+ }
+
+ if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) {
+ Jim_String(objPtr);
+ }
+
+ listlen = Jim_ListLength(interp, objPtr);
+ if (listlen % 2) {
+ Jim_SetResultString(interp, "missing value to go with key", -1);
+ return JIM_ERR;
+ }
+ else {
+
+ Jim_Dict *dict = JimDictNew(interp, 0, listlen);
+ int i;
+
+
+ dict->table = objPtr->internalRep.listValue.ele;
+ dict->maxLen = objPtr->internalRep.listValue.maxLen;
+
+
+ for (i = 0; i < listlen; i += 2) {
+ int tvoffset = JimDictAdd(dict, dict->table[i]);
+ if (tvoffset) {
+
+
+ Jim_DecrRefCount(interp, dict->table[tvoffset]);
+
+ dict->table[tvoffset] = dict->table[i + 1];
+
+ Jim_DecrRefCount(interp, dict->table[i]);
+ }
+ else {
+ if (dict->len != i) {
+ dict->table[dict->len++] = dict->table[i];
+ dict->table[dict->len++] = dict->table[i + 1];
+ }
+ else {
+ dict->len += 2;
+ }
+ }
+ }
+
+ objPtr->typePtr = &dictObjType;
+ objPtr->internalRep.dictValue = dict;
+
+ return JIM_OK;
+ }
+}
+
+
+
+static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+ Jim_Dict *dict = objPtr->internalRep.dictValue;
+ if (valueObjPtr == NULL) {
+
+ int tvoffset = JimDictHashFind(dict, keyObjPtr, DICT_HASH_REMOVE);
+ if (tvoffset) {
+
+ Jim_DecrRefCount(interp, dict->table[tvoffset - 1]);
+ Jim_DecrRefCount(interp, dict->table[tvoffset]);
+ dict->len -= 2;
+ if (tvoffset != dict->len + 1) {
+
+ dict->table[tvoffset - 1] = dict->table[dict->len];
+ dict->table[tvoffset] = dict->table[dict->len + 1];
+
+
+ JimDictHashFind(dict, dict->table[tvoffset - 1], tvoffset);
+ }
+ return JIM_OK;
+ }
+ return JIM_ERR;
+ }
+ else {
+
+ int tvoffset = JimDictAdd(dict, keyObjPtr);
+ if (tvoffset) {
+
+ Jim_IncrRefCount(valueObjPtr);
+ Jim_DecrRefCount(interp, dict->table[tvoffset]);
+ dict->table[tvoffset] = valueObjPtr;
+ }
+ else {
+ if (dict->maxLen == dict->len) {
+
+ if (dict->maxLen < 4) {
+ dict->maxLen = 4;
+ }
+ else {
+ dict->maxLen *= 2;
+ }
+ dict->table = Jim_Realloc(dict->table, dict->maxLen * sizeof(*dict->table));
+ }
+ Jim_IncrRefCount(keyObjPtr);
+ Jim_IncrRefCount(valueObjPtr);
+
+ dict->table[dict->len++] = keyObjPtr;
+ dict->table[dict->len++] = valueObjPtr;
+
+ }
+ return JIM_OK;
+ }
+}
+
+int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+ JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_InvalidateStringRep(objPtr);
+ return DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
+}
+
+Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+ Jim_Obj *objPtr;
+ int i;
+
+ JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even"));
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &dictObjType;
+ objPtr->bytes = NULL;
+
+ objPtr->internalRep.dictValue = JimDictNew(interp, len, len);
+ for (i = 0; i < len; i += 2)
+ DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
+ return objPtr;
+}
+
+int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
+ Jim_Obj **objPtrPtr, int flags)
+{
+ int tvoffset;
+ Jim_Dict *dict;
+
+ if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
+ return -1;
+ }
+ dict = dictPtr->internalRep.dictValue;
+ tvoffset = JimDictHashFind(dict, keyPtr, DICT_HASH_FIND);
+ if (tvoffset == 0) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
+ }
+ return JIM_ERR;
+ }
+ *objPtrPtr = dict->table[tvoffset];
+ return JIM_OK;
+}
+
+Jim_Obj **Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, int *len)
+{
+
+ if (Jim_IsList(dictPtr)) {
+ Jim_Obj **table;
+ JimListGetElements(interp, dictPtr, len, &table);
+ if (*len % 2 == 0) {
+ return table;
+ }
+
+ }
+ if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
+
+ *len = 1;
+ return NULL;
+ }
+ *len = dictPtr->internalRep.dictValue->len;
+ return dictPtr->internalRep.dictValue->table;
+}
+
+
+int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
+ Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
+{
+ int i;
+
+ if (keyc == 0) {
+ *objPtrPtr = dictPtr;
+ return JIM_OK;
+ }
+
+ for (i = 0; i < keyc; i++) {
+ Jim_Obj *objPtr;
+
+ int rc = Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags);
+ if (rc != JIM_OK) {
+ return rc;
+ }
+ dictPtr = objPtr;
+ }
+ *objPtrPtr = dictPtr;
+ return JIM_OK;
+}
+
+int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
+ Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags)
+{
+ Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
+ int shared, i;
+
+ varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags);
+ if (objPtr == NULL) {
+ if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) {
+
+ return JIM_ERR;
+ }
+ varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
+ if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, varObjPtr);
+ return JIM_ERR;
+ }
+ }
+ if ((shared = Jim_IsShared(objPtr)))
+ varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+ for (i = 0; i < keyc; i++) {
+ dictObjPtr = objPtr;
+
+
+ if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
+ goto err;
+ }
+
+ if (i == keyc - 1) {
+
+ if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
+ if (newObjPtr || (flags & JIM_MUSTEXIST)) {
+ goto err;
+ }
+ }
+ break;
+ }
+
+
+ Jim_InvalidateStringRep(dictObjPtr);
+ if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
+ newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
+ if (Jim_IsShared(objPtr)) {
+ objPtr = Jim_DuplicateObj(interp, objPtr);
+ DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+ }
+ }
+ else {
+ if (newObjPtr == NULL) {
+ goto err;
+ }
+ objPtr = Jim_NewDictObj(interp, NULL, 0);
+ DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+ }
+ }
+
+ Jim_InvalidateStringRep(objPtr);
+ Jim_InvalidateStringRep(varObjPtr);
+ if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
+ goto err;
+ }
+
+ if (!(flags & JIM_NORESULT)) {
+ Jim_SetResult(interp, varObjPtr);
+ }
+ return JIM_OK;
+ err:
+ if (shared) {
+ Jim_FreeNewObj(interp, varObjPtr);
+ }
+ return JIM_ERR;
+}
+
+static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
+static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType indexObjType = {
+ "index",
+ NULL,
+ NULL,
+ UpdateStringOfIndex,
+ JIM_TYPE_NONE,
+};
+
+static void UpdateStringOfIndex(struct Jim_Obj *objPtr)
+{
+ if (objPtr->internalRep.intValue == -1) {
+ JimSetStringBytes(objPtr, "end");
+ }
+ else {
+ char buf[JIM_INTEGER_SPACE + 1];
+ if (objPtr->internalRep.intValue >= 0 || objPtr->internalRep.intValue == -INT_MAX) {
+ sprintf(buf, "%d", objPtr->internalRep.intValue);
+ }
+ else {
+
+ sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
+ }
+ JimSetStringBytes(objPtr, buf);
+ }
+}
+
+static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ jim_wide idx;
+ int end = 0;
+ const char *str;
+ Jim_Obj *exprObj = objPtr;
+
+ JimPanic((objPtr->refCount == 0, "SetIndexFromAny() called with zero refcount object"));
+
+
+ str = Jim_String(objPtr);
+
+
+ if (strncmp(str, "end", 3) == 0) {
+ end = 1;
+ str += 3;
+ idx = 0;
+ switch (*str) {
+ case '\0':
+ exprObj = NULL;
+ break;
+
+ case '-':
+ case '+':
+ exprObj = Jim_NewStringObj(interp, str, -1);
+ break;
+
+ default:
+ goto badindex;
+ }
+ }
+ if (exprObj) {
+ int ret;
+ Jim_IncrRefCount(exprObj);
+ ret = Jim_GetWideExpr(interp, exprObj, &idx);
+ Jim_DecrRefCount(interp, exprObj);
+ if (ret != JIM_OK) {
+ goto badindex;
+ }
+ }
+
+ if (end) {
+ if (idx > 0) {
+ idx = INT_MAX;
+ }
+ else {
+
+ idx--;
+ }
+ }
+ else if (idx < 0) {
+ idx = -INT_MAX;
+ }
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &indexObjType;
+ objPtr->internalRep.intValue = idx;
+ return JIM_OK;
+
+ badindex:
+ Jim_SetResultFormatted(interp,
+ "bad index \"%#s\": must be intexpr or end?[+-]intexpr?", objPtr);
+ return JIM_ERR;
+}
+
+int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
+{
+
+ if (objPtr->typePtr == &intObjType) {
+ jim_wide val = JimWideValue(objPtr);
+
+ if (val < 0)
+ *indexPtr = -INT_MAX;
+ else if (val > INT_MAX)
+ *indexPtr = INT_MAX;
+ else
+ *indexPtr = (int)val;
+ return JIM_OK;
+ }
+ if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
+ return JIM_ERR;
+ *indexPtr = objPtr->internalRep.intValue;
+ return JIM_OK;
+}
+
+
+
+static const char * const jimReturnCodes[] = {
+ "ok",
+ "error",
+ "return",
+ "break",
+ "continue",
+ "signal",
+ "exit",
+ "eval",
+ NULL
+};
+
+#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1)
+
+static const Jim_ObjType returnCodeObjType = {
+ "return-code",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+const char *Jim_ReturnCode(int code)
+{
+ if (code < 0 || code >= (int)jimReturnCodesSize) {
+ return "?";
+ }
+ else {
+ return jimReturnCodes[code];
+ }
+}
+
+static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int returnCode;
+ jim_wide wideValue;
+
+
+ if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
+ returnCode = (int)wideValue;
+ else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
+ return JIM_ERR;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &returnCodeObjType;
+ objPtr->internalRep.intValue = returnCode;
+ return JIM_OK;
+}
+
+int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
+{
+ if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
+ return JIM_ERR;
+ *intPtr = objPtr->internalRep.intValue;
+ return JIM_OK;
+}
+
+static int JimParseExprOperator(struct JimParserCtx *pc);
+static int JimParseExprNumber(struct JimParserCtx *pc);
+static int JimParseExprIrrational(struct JimParserCtx *pc);
+static int JimParseExprBoolean(struct JimParserCtx *pc);
+
+
+enum
+{
+
+
+
+ JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
+ JIM_EXPROP_DIV,
+ JIM_EXPROP_MOD,
+ JIM_EXPROP_SUB,
+ JIM_EXPROP_ADD,
+ JIM_EXPROP_LSHIFT,
+ JIM_EXPROP_RSHIFT,
+ JIM_EXPROP_ROTL,
+ JIM_EXPROP_ROTR,
+ JIM_EXPROP_LT,
+ JIM_EXPROP_GT,
+ JIM_EXPROP_LTE,
+ JIM_EXPROP_GTE,
+ JIM_EXPROP_NUMEQ,
+ JIM_EXPROP_NUMNE,
+ JIM_EXPROP_BITAND,
+ JIM_EXPROP_BITXOR,
+ JIM_EXPROP_BITOR,
+ JIM_EXPROP_LOGICAND,
+ JIM_EXPROP_LOGICOR,
+ JIM_EXPROP_TERNARY,
+ JIM_EXPROP_COLON,
+ JIM_EXPROP_POW,
+
+
+ JIM_EXPROP_STREQ,
+ JIM_EXPROP_STRNE,
+ JIM_EXPROP_STRIN,
+ JIM_EXPROP_STRNI,
+ JIM_EXPROP_STRLT,
+ JIM_EXPROP_STRGT,
+ JIM_EXPROP_STRLE,
+ JIM_EXPROP_STRGE,
+
+
+ JIM_EXPROP_NOT,
+ JIM_EXPROP_BITNOT,
+ JIM_EXPROP_UNARYMINUS,
+ JIM_EXPROP_UNARYPLUS,
+
+
+ JIM_EXPROP_FUNC_INT,
+ JIM_EXPROP_FUNC_WIDE,
+ JIM_EXPROP_FUNC_ABS,
+ JIM_EXPROP_FUNC_DOUBLE,
+ JIM_EXPROP_FUNC_ROUND,
+ JIM_EXPROP_FUNC_RAND,
+ JIM_EXPROP_FUNC_SRAND,
+
+
+ JIM_EXPROP_FUNC_SIN,
+ JIM_EXPROP_FUNC_COS,
+ JIM_EXPROP_FUNC_TAN,
+ JIM_EXPROP_FUNC_ASIN,
+ JIM_EXPROP_FUNC_ACOS,
+ JIM_EXPROP_FUNC_ATAN,
+ JIM_EXPROP_FUNC_ATAN2,
+ JIM_EXPROP_FUNC_SINH,
+ JIM_EXPROP_FUNC_COSH,
+ JIM_EXPROP_FUNC_TANH,
+ JIM_EXPROP_FUNC_CEIL,
+ JIM_EXPROP_FUNC_FLOOR,
+ JIM_EXPROP_FUNC_EXP,
+ JIM_EXPROP_FUNC_LOG,
+ JIM_EXPROP_FUNC_LOG10,
+ JIM_EXPROP_FUNC_SQRT,
+ JIM_EXPROP_FUNC_POW,
+ JIM_EXPROP_FUNC_HYPOT,
+ JIM_EXPROP_FUNC_FMOD,
+};
+
+struct JimExprNode {
+ int type;
+ struct Jim_Obj *objPtr;
+
+ struct JimExprNode *left;
+ struct JimExprNode *right;
+ struct JimExprNode *ternary;
+};
+
+
+typedef struct Jim_ExprOperator
+{
+ const char *name;
+ int (*funcop) (Jim_Interp *interp, struct JimExprNode *opnode);
+ unsigned char precedence;
+ unsigned char arity;
+ unsigned char attr;
+ unsigned char namelen;
+} Jim_ExprOperator;
+
+static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr);
+static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node);
+static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node);
+
+static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
+{
+ int intresult = 1;
+ int rc, bA = 0;
+ double dA, dC = 0;
+ jim_wide wA, wC = 0;
+ Jim_Obj *A;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+
+ if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_FUNC_INT:
+ case JIM_EXPROP_FUNC_WIDE:
+ case JIM_EXPROP_FUNC_ROUND:
+ case JIM_EXPROP_UNARYPLUS:
+ wC = wA;
+ break;
+ case JIM_EXPROP_FUNC_DOUBLE:
+ dC = wA;
+ intresult = 0;
+ break;
+ case JIM_EXPROP_FUNC_ABS:
+ wC = wA >= 0 ? wA : -wA;
+ break;
+ case JIM_EXPROP_UNARYMINUS:
+ wC = -wA;
+ break;
+ case JIM_EXPROP_NOT:
+ wC = !wA;
+ break;
+ default:
+ abort();
+ }
+ }
+ else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_FUNC_INT:
+ case JIM_EXPROP_FUNC_WIDE:
+ wC = dA;
+ break;
+ case JIM_EXPROP_FUNC_ROUND:
+ wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
+ break;
+ case JIM_EXPROP_FUNC_DOUBLE:
+ case JIM_EXPROP_UNARYPLUS:
+ dC = dA;
+ intresult = 0;
+ break;
+ case JIM_EXPROP_FUNC_ABS:
+#ifdef JIM_MATH_FUNCTIONS
+ dC = fabs(dA);
+#else
+ dC = dA >= 0 ? dA : -dA;
+#endif
+ intresult = 0;
+ break;
+ case JIM_EXPROP_UNARYMINUS:
+ dC = -dA;
+ intresult = 0;
+ break;
+ case JIM_EXPROP_NOT:
+ wC = !dA;
+ break;
+ default:
+ abort();
+ }
+ }
+ else if ((rc = Jim_GetBoolean(interp, A, &bA)) == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_NOT:
+ wC = !bA;
+ break;
+ case JIM_EXPROP_UNARYPLUS:
+ case JIM_EXPROP_UNARYMINUS:
+ rc = JIM_ERR;
+ Jim_SetResultFormatted(interp,
+ "can't use non-numeric string as operand of \"%s\"",
+ node->type == JIM_EXPROP_UNARYPLUS ? "+" : "-");
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if (rc == JIM_OK) {
+ if (intresult) {
+ Jim_SetResultInt(interp, wC);
+ }
+ else {
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
+ }
+ }
+
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+
+static double JimRandDouble(Jim_Interp *interp)
+{
+ unsigned long x;
+ JimRandomBytes(interp, &x, sizeof(x));
+
+ return (double)x / (double)~0UL;
+}
+
+static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node)
+{
+ jim_wide wA;
+ Jim_Obj *A;
+ int rc;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+
+ rc = Jim_GetWide(interp, A, &wA);
+ if (rc == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_BITNOT:
+ Jim_SetResultInt(interp, ~wA);
+ break;
+ case JIM_EXPROP_FUNC_SRAND:
+ JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+ break;
+ default:
+ abort();
+ }
+ }
+
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+
+static int JimExprOpNone(Jim_Interp *interp, struct JimExprNode *node)
+{
+ JimPanic((node->type != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
+
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+
+ return JIM_OK;
+}
+
+#ifdef JIM_MATH_FUNCTIONS
+static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprNode *node)
+{
+ int rc;
+ double dA, dC;
+ Jim_Obj *A;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+
+ rc = Jim_GetDouble(interp, A, &dA);
+ if (rc == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_FUNC_SIN:
+ dC = sin(dA);
+ break;
+ case JIM_EXPROP_FUNC_COS:
+ dC = cos(dA);
+ break;
+ case JIM_EXPROP_FUNC_TAN:
+ dC = tan(dA);
+ break;
+ case JIM_EXPROP_FUNC_ASIN:
+ dC = asin(dA);
+ break;
+ case JIM_EXPROP_FUNC_ACOS:
+ dC = acos(dA);
+ break;
+ case JIM_EXPROP_FUNC_ATAN:
+ dC = atan(dA);
+ break;
+ case JIM_EXPROP_FUNC_SINH:
+ dC = sinh(dA);
+ break;
+ case JIM_EXPROP_FUNC_COSH:
+ dC = cosh(dA);
+ break;
+ case JIM_EXPROP_FUNC_TANH:
+ dC = tanh(dA);
+ break;
+ case JIM_EXPROP_FUNC_CEIL:
+ dC = ceil(dA);
+ break;
+ case JIM_EXPROP_FUNC_FLOOR:
+ dC = floor(dA);
+ break;
+ case JIM_EXPROP_FUNC_EXP:
+ dC = exp(dA);
+ break;
+ case JIM_EXPROP_FUNC_LOG:
+ dC = log(dA);
+ break;
+ case JIM_EXPROP_FUNC_LOG10:
+ dC = log10(dA);
+ break;
+ case JIM_EXPROP_FUNC_SQRT:
+ dC = sqrt(dA);
+ break;
+ default:
+ abort();
+ }
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
+ }
+
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+#endif
+
+
+static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprNode *node)
+{
+ jim_wide wA, wB;
+ int rc;
+ Jim_Obj *A, *B;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+ if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
+ Jim_DecrRefCount(interp, A);
+ return rc;
+ }
+
+ rc = JIM_ERR;
+
+ if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
+ jim_wide wC;
+
+ rc = JIM_OK;
+
+ switch (node->type) {
+ case JIM_EXPROP_LSHIFT:
+ wC = wA << wB;
+ break;
+ case JIM_EXPROP_RSHIFT:
+ wC = wA >> wB;
+ break;
+ case JIM_EXPROP_BITAND:
+ wC = wA & wB;
+ break;
+ case JIM_EXPROP_BITXOR:
+ wC = wA ^ wB;
+ break;
+ case JIM_EXPROP_BITOR:
+ wC = wA | wB;
+ break;
+ case JIM_EXPROP_MOD:
+ if (wB == 0) {
+ wC = 0;
+ Jim_SetResultString(interp, "Division by zero", -1);
+ rc = JIM_ERR;
+ }
+ else {
+ int negative = 0;
+
+ if (wB < 0) {
+ wB = -wB;
+ wA = -wA;
+ negative = 1;
+ }
+ wC = wA % wB;
+ if (wC < 0) {
+ wC += wB;
+ }
+ if (negative) {
+ wC = -wC;
+ }
+ }
+ break;
+ case JIM_EXPROP_ROTL:
+ case JIM_EXPROP_ROTR:{
+
+ unsigned long uA = (unsigned long)wA;
+ unsigned long uB = (unsigned long)wB;
+ const unsigned int S = sizeof(unsigned long) * 8;
+
+
+ uB %= S;
+
+ if (node->type == JIM_EXPROP_ROTR) {
+ uB = S - uB;
+ }
+ wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
+ break;
+ }
+ default:
+ abort();
+ }
+ Jim_SetResultInt(interp, wC);
+ }
+
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+
+ return rc;
+}
+
+
+
+static int JimExprOpBin(Jim_Interp *interp, struct JimExprNode *node)
+{
+ int rc = JIM_OK;
+ double dA, dB, dC = 0;
+ jim_wide wA, wB, wC = 0;
+ Jim_Obj *A, *B;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+ if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
+ Jim_DecrRefCount(interp, A);
+ return rc;
+ }
+
+ if ((A->typePtr != &doubleObjType || A->bytes) &&
+ (B->typePtr != &doubleObjType || B->bytes) &&
+ JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
+
+
+
+ switch (node->type) {
+ case JIM_EXPROP_POW:
+ case JIM_EXPROP_FUNC_POW:
+ if (wA == 0 && wB < 0) {
+ Jim_SetResultString(interp, "exponentiation of zero by negative power", -1);
+ rc = JIM_ERR;
+ goto done;
+ }
+ wC = JimPowWide(wA, wB);
+ goto intresult;
+ case JIM_EXPROP_ADD:
+ wC = wA + wB;
+ goto intresult;
+ case JIM_EXPROP_SUB:
+ wC = wA - wB;
+ goto intresult;
+ case JIM_EXPROP_MUL:
+ wC = wA * wB;
+ goto intresult;
+ case JIM_EXPROP_DIV:
+ if (wB == 0) {
+ Jim_SetResultString(interp, "Division by zero", -1);
+ rc = JIM_ERR;
+ goto done;
+ }
+ else {
+ if (wB < 0) {
+ wB = -wB;
+ wA = -wA;
+ }
+ wC = wA / wB;
+ if (wA % wB < 0) {
+ wC--;
+ }
+ goto intresult;
+ }
+ case JIM_EXPROP_LT:
+ wC = wA < wB;
+ goto intresult;
+ case JIM_EXPROP_GT:
+ wC = wA > wB;
+ goto intresult;
+ case JIM_EXPROP_LTE:
+ wC = wA <= wB;
+ goto intresult;
+ case JIM_EXPROP_GTE:
+ wC = wA >= wB;
+ goto intresult;
+ case JIM_EXPROP_NUMEQ:
+ wC = wA == wB;
+ goto intresult;
+ case JIM_EXPROP_NUMNE:
+ wC = wA != wB;
+ goto intresult;
+ }
+ }
+ if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
+ switch (node->type) {
+#ifndef JIM_MATH_FUNCTIONS
+ case JIM_EXPROP_POW:
+ case JIM_EXPROP_FUNC_POW:
+ case JIM_EXPROP_FUNC_ATAN2:
+ case JIM_EXPROP_FUNC_HYPOT:
+ case JIM_EXPROP_FUNC_FMOD:
+ Jim_SetResultString(interp, "unsupported", -1);
+ rc = JIM_ERR;
+ goto done;
+#else
+ case JIM_EXPROP_POW:
+ case JIM_EXPROP_FUNC_POW:
+ dC = pow(dA, dB);
+ goto doubleresult;
+ case JIM_EXPROP_FUNC_ATAN2:
+ dC = atan2(dA, dB);
+ goto doubleresult;
+ case JIM_EXPROP_FUNC_HYPOT:
+ dC = hypot(dA, dB);
+ goto doubleresult;
+ case JIM_EXPROP_FUNC_FMOD:
+ dC = fmod(dA, dB);
+ goto doubleresult;
+#endif
+ case JIM_EXPROP_ADD:
+ dC = dA + dB;
+ goto doubleresult;
+ case JIM_EXPROP_SUB:
+ dC = dA - dB;
+ goto doubleresult;
+ case JIM_EXPROP_MUL:
+ dC = dA * dB;
+ goto doubleresult;
+ case JIM_EXPROP_DIV:
+ if (dB == 0) {
+#ifdef INFINITY
+ dC = dA < 0 ? -INFINITY : INFINITY;
+#else
+ dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL);
+#endif
+ }
+ else {
+ dC = dA / dB;
+ }
+ goto doubleresult;
+ case JIM_EXPROP_LT:
+ wC = dA < dB;
+ goto intresult;
+ case JIM_EXPROP_GT:
+ wC = dA > dB;
+ goto intresult;
+ case JIM_EXPROP_LTE:
+ wC = dA <= dB;
+ goto intresult;
+ case JIM_EXPROP_GTE:
+ wC = dA >= dB;
+ goto intresult;
+ case JIM_EXPROP_NUMEQ:
+ wC = dA == dB;
+ goto intresult;
+ case JIM_EXPROP_NUMNE:
+ wC = dA != dB;
+ goto intresult;
+ }
+ }
+ else {
+
+
+
+ int i = Jim_StringCompareObj(interp, A, B, 0);
+
+ switch (node->type) {
+ case JIM_EXPROP_LT:
+ wC = i < 0;
+ goto intresult;
+ case JIM_EXPROP_GT:
+ wC = i > 0;
+ goto intresult;
+ case JIM_EXPROP_LTE:
+ wC = i <= 0;
+ goto intresult;
+ case JIM_EXPROP_GTE:
+ wC = i >= 0;
+ goto intresult;
+ case JIM_EXPROP_NUMEQ:
+ wC = i == 0;
+ goto intresult;
+ case JIM_EXPROP_NUMNE:
+ wC = i != 0;
+ goto intresult;
+ }
+ }
+
+ rc = JIM_ERR;
+done:
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+ return rc;
+intresult:
+ Jim_SetResultInt(interp, wC);
+ goto done;
+doubleresult:
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
+ goto done;
+}
+
+static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
+{
+ int listlen;
+ int i;
+
+ listlen = Jim_ListLength(interp, listObjPtr);
+ for (i = 0; i < listlen; i++) {
+ if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
+{
+ Jim_Obj *A, *B;
+ jim_wide wC;
+ int comp, rc;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+ if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
+ Jim_DecrRefCount(interp, A);
+ return rc;
+ }
+
+ switch (node->type) {
+ case JIM_EXPROP_STREQ:
+ case JIM_EXPROP_STRNE:
+ wC = Jim_StringEqObj(A, B);
+ if (node->type == JIM_EXPROP_STRNE) {
+ wC = !wC;
+ }
+ break;
+ case JIM_EXPROP_STRLT:
+ case JIM_EXPROP_STRGT:
+ case JIM_EXPROP_STRLE:
+ case JIM_EXPROP_STRGE:
+ comp = Jim_StringCompareObj(interp, A, B, 0);
+ if (node->type == JIM_EXPROP_STRLT) {
+ wC = comp == -1;
+ } else if (node->type == JIM_EXPROP_STRGT) {
+ wC = comp == 1;
+ } else if (node->type == JIM_EXPROP_STRLE) {
+ wC = comp == -1 || comp == 0;
+ } else {
+ wC = comp == 0 || comp == 1;
+ }
+ break;
+ case JIM_EXPROP_STRIN:
+ wC = JimSearchList(interp, B, A);
+ break;
+ case JIM_EXPROP_STRNI:
+ wC = !JimSearchList(interp, B, A);
+ break;
+ default:
+ abort();
+ }
+ Jim_SetResultInt(interp, wC);
+
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+
+ return rc;
+}
+
+static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
+{
+ long l;
+ double d;
+ int b;
+ int ret = -1;
+
+
+ Jim_IncrRefCount(obj);
+
+ if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
+ ret = (l != 0);
+ }
+ else if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
+ ret = (d != 0);
+ }
+ else if (Jim_GetBoolean(interp, obj, &b) == JIM_OK) {
+ ret = (b != 0);
+ }
+
+ Jim_DecrRefCount(interp, obj);
+ return ret;
+}
+
+static int JimExprOpAnd(Jim_Interp *interp, struct JimExprNode *node)
+{
+
+ int result = JimExprGetTermBoolean(interp, node->left);
+
+ if (result == 1) {
+
+ result = JimExprGetTermBoolean(interp, node->right);
+ }
+ if (result == -1) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, result);
+ return JIM_OK;
+}
+
+static int JimExprOpOr(Jim_Interp *interp, struct JimExprNode *node)
+{
+
+ int result = JimExprGetTermBoolean(interp, node->left);
+
+ if (result == 0) {
+
+ result = JimExprGetTermBoolean(interp, node->right);
+ }
+ if (result == -1) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, result);
+ return JIM_OK;
+}
+
+static int JimExprOpTernary(Jim_Interp *interp, struct JimExprNode *node)
+{
+
+ int result = JimExprGetTermBoolean(interp, node->left);
+
+ if (result == 1) {
+
+ return JimExprEvalTermNode(interp, node->right);
+ }
+ else if (result == 0) {
+
+ return JimExprEvalTermNode(interp, node->ternary);
+ }
+
+ return JIM_ERR;
+}
+
+enum
+{
+ OP_FUNC = 0x0001,
+ OP_RIGHT_ASSOC = 0x0002,
+};
+
+#define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
+#define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0)
+
+static const struct Jim_ExprOperator Jim_ExprOperators[] = {
+ OPRINIT("*", 110, 2, JimExprOpBin),
+ OPRINIT("/", 110, 2, JimExprOpBin),
+ OPRINIT("%", 110, 2, JimExprOpIntBin),
+
+ OPRINIT("-", 100, 2, JimExprOpBin),
+ OPRINIT("+", 100, 2, JimExprOpBin),
+
+ OPRINIT("<<", 90, 2, JimExprOpIntBin),
+ OPRINIT(">>", 90, 2, JimExprOpIntBin),
+
+ OPRINIT("<<<", 90, 2, JimExprOpIntBin),
+ OPRINIT(">>>", 90, 2, JimExprOpIntBin),
+
+ OPRINIT("<", 80, 2, JimExprOpBin),
+ OPRINIT(">", 80, 2, JimExprOpBin),
+ OPRINIT("<=", 80, 2, JimExprOpBin),
+ OPRINIT(">=", 80, 2, JimExprOpBin),
+
+ OPRINIT("==", 70, 2, JimExprOpBin),
+ OPRINIT("!=", 70, 2, JimExprOpBin),
+
+ OPRINIT("&", 50, 2, JimExprOpIntBin),
+ OPRINIT("^", 49, 2, JimExprOpIntBin),
+ OPRINIT("|", 48, 2, JimExprOpIntBin),
+
+ OPRINIT("&&", 10, 2, JimExprOpAnd),
+ OPRINIT("||", 9, 2, JimExprOpOr),
+ OPRINIT_ATTR("?", 5, 3, JimExprOpTernary, OP_RIGHT_ASSOC),
+ OPRINIT_ATTR(":", 5, 3, NULL, OP_RIGHT_ASSOC),
+
+
+ OPRINIT_ATTR("**", 120, 2, JimExprOpBin, OP_RIGHT_ASSOC),
+
+ OPRINIT("eq", 60, 2, JimExprOpStrBin),
+ OPRINIT("ne", 60, 2, JimExprOpStrBin),
+
+ OPRINIT("in", 55, 2, JimExprOpStrBin),
+ OPRINIT("ni", 55, 2, JimExprOpStrBin),
+
+ OPRINIT("lt", 75, 2, JimExprOpStrBin),
+ OPRINIT("gt", 75, 2, JimExprOpStrBin),
+ OPRINIT("le", 75, 2, JimExprOpStrBin),
+ OPRINIT("ge", 75, 2, JimExprOpStrBin),
+
+ OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
+ OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC),
+ OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
+ OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
+
+
+
+ OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("rand", 200, 0, JimExprOpNone, OP_FUNC),
+ OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary, OP_FUNC),
+
+#ifdef JIM_MATH_FUNCTIONS
+ OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin, OP_FUNC),
+ OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("pow", 200, 2, JimExprOpBin, OP_FUNC),
+ OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin, OP_FUNC),
+ OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin, OP_FUNC),
+#endif
+};
+#undef OPRINIT
+#undef OPRINIT_ATTR
+
+#define JIM_EXPR_OPERATORS_NUM \
+ (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
+
+static int JimParseExpression(struct JimParserCtx *pc)
+{
+ pc->errmsg = NULL;
+
+ while (1) {
+
+ while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+
+ if (*pc->p == '#') {
+ JimParseComment(pc);
+
+ continue;
+ }
+ break;
+ }
+
+
+ pc->tline = pc->linenr;
+ pc->tstart = pc->p;
+
+ if (pc->len == 0) {
+ pc->tend = pc->p;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return JIM_OK;
+ }
+ switch (*(pc->p)) {
+ case '(':
+ pc->tt = JIM_TT_SUBEXPR_START;
+ goto singlechar;
+ case ')':
+ pc->tt = JIM_TT_SUBEXPR_END;
+ goto singlechar;
+ case ',':
+ pc->tt = JIM_TT_SUBEXPR_COMMA;
+singlechar:
+ pc->tend = pc->p;
+ pc->p++;
+ pc->len--;
+ break;
+ case '[':
+ return JimParseCmd(pc);
+ case '$':
+ if (JimParseVar(pc) == JIM_ERR)
+ return JimParseExprOperator(pc);
+ else {
+
+ if (pc->tt == JIM_TT_EXPRSUGAR) {
+ pc->errmsg = "nesting expr in expr is not allowed";
+ return JIM_ERR;
+ }
+ return JIM_OK;
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '.':
+ return JimParseExprNumber(pc);
+ case '"':
+ return JimParseQuote(pc);
+ case '{':
+ return JimParseBrace(pc);
+
+ case 'N':
+ case 'I':
+ case 'n':
+ case 'i':
+ if (JimParseExprIrrational(pc) == JIM_ERR)
+ if (JimParseExprBoolean(pc) == JIM_ERR)
+ return JimParseExprOperator(pc);
+ break;
+ case 't':
+ case 'f':
+ case 'o':
+ case 'y':
+ if (JimParseExprBoolean(pc) == JIM_ERR)
+ return JimParseExprOperator(pc);
+ break;
+ default:
+ return JimParseExprOperator(pc);
+ break;
+ }
+ return JIM_OK;
+}
+
+static int JimParseExprNumber(struct JimParserCtx *pc)
+{
+ char *end;
+
+
+ pc->tt = JIM_TT_EXPR_INT;
+
+ jim_strtoull(pc->p, (char **)&pc->p);
+
+ if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
+ if (strtod(pc->tstart, &end)) { }
+ if (end == pc->tstart)
+ return JIM_ERR;
+ if (end > pc->p) {
+
+ pc->tt = JIM_TT_EXPR_DOUBLE;
+ pc->p = end;
+ }
+ }
+ pc->tend = pc->p - 1;
+ pc->len -= (pc->p - pc->tstart);
+ return JIM_OK;
+}
+
+static int JimParseExprIrrational(struct JimParserCtx *pc)
+{
+ const char *irrationals[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
+ int i;
+
+ for (i = 0; irrationals[i]; i++) {
+ const char *irr = irrationals[i];
+
+ if (strncmp(irr, pc->p, 3) == 0) {
+ pc->p += 3;
+ pc->len -= 3;
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_EXPR_DOUBLE;
+ return JIM_OK;
+ }
+ }
+ return JIM_ERR;
+}
+
+static int JimParseExprBoolean(struct JimParserCtx *pc)
+{
+ int i;
+ for (i = 0; i < sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings); i++) {
+ if (strncmp(pc->p, jim_true_false_strings[i], jim_true_false_lens[i]) == 0) {
+ pc->p += jim_true_false_lens[i];
+ pc->len -= jim_true_false_lens[i];
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_EXPR_BOOLEAN;
+ return JIM_OK;
+ }
+ }
+ return JIM_ERR;
+}
+
+static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
+{
+ static Jim_ExprOperator dummy_op;
+ if (opcode < JIM_TT_EXPR_OP) {
+ return &dummy_op;
+ }
+ return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
+}
+
+static int JimParseExprOperator(struct JimParserCtx *pc)
+{
+ int i;
+ const struct Jim_ExprOperator *bestOp = NULL;
+ int bestLen = 0;
+
+
+ for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
+ const struct Jim_ExprOperator *op = &Jim_ExprOperators[i];
+
+ if (op->name[0] != pc->p[0]) {
+ continue;
+ }
+
+ if (op->namelen > bestLen && strncmp(op->name, pc->p, op->namelen) == 0) {
+ bestOp = op;
+ bestLen = op->namelen;
+ }
+ }
+ if (bestOp == NULL) {
+ return JIM_ERR;
+ }
+
+
+ if (bestOp->attr & OP_FUNC) {
+ const char *p = pc->p + bestLen;
+ int len = pc->len - bestLen;
+
+ while (len && isspace(UCHAR(*p))) {
+ len--;
+ p++;
+ }
+ if (*p != '(') {
+ pc->errmsg = "function requires parentheses";
+ return JIM_ERR;
+ }
+ }
+ pc->tend = pc->p + bestLen - 1;
+ pc->p += bestLen;
+ pc->len -= bestLen;
+
+ pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
+ return JIM_OK;
+}
+
+
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType exprObjType = {
+ "expression",
+ FreeExprInternalRep,
+ DupExprInternalRep,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+
+struct ExprTree
+{
+ struct JimExprNode *expr;
+ struct JimExprNode *nodes;
+ int len;
+ int inUse;
+};
+
+static void ExprTreeFreeNodes(Jim_Interp *interp, struct JimExprNode *nodes, int num)
+{
+ int i;
+ for (i = 0; i < num; i++) {
+ if (nodes[i].objPtr) {
+ Jim_DecrRefCount(interp, nodes[i].objPtr);
+ }
+ }
+ Jim_Free(nodes);
+}
+
+static void ExprTreeFree(Jim_Interp *interp, struct ExprTree *expr)
+{
+ ExprTreeFreeNodes(interp, expr->nodes, expr->len);
+ Jim_Free(expr);
+}
+
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ struct ExprTree *expr = (void *)objPtr->internalRep.ptr;
+
+ if (expr) {
+ if (--expr->inUse != 0) {
+ return;
+ }
+
+ ExprTreeFree(interp, expr);
+ }
+}
+
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+ JIM_NOTUSED(srcPtr);
+
+
+ dupPtr->typePtr = NULL;
+}
+
+struct ExprBuilder {
+ int parencount;
+ int level;
+ ParseToken *token;
+ ParseToken *first_token;
+ Jim_Stack stack;
+ Jim_Obj *exprObjPtr;
+ Jim_Obj *fileNameObj;
+ struct JimExprNode *nodes;
+ struct JimExprNode *next;
+};
+
+#ifdef DEBUG_SHOW_EXPR
+static void JimShowExprNode(struct JimExprNode *node, int level)
+{
+ int i;
+ for (i = 0; i < level; i++) {
+ printf(" ");
+ }
+ if (TOKEN_IS_EXPR_OP(node->type)) {
+ printf("%s\n", jim_tt_name(node->type));
+ if (node->left) {
+ JimShowExprNode(node->left, level + 1);
+ }
+ if (node->right) {
+ JimShowExprNode(node->right, level + 1);
+ }
+ if (node->ternary) {
+ JimShowExprNode(node->ternary, level + 1);
+ }
+ }
+ else {
+ printf("[%s] %s\n", jim_tt_name(node->type), Jim_String(node->objPtr));
+ }
+}
+#endif
+
+#define EXPR_UNTIL_CLOSE 0x0001
+#define EXPR_FUNC_ARGS 0x0002
+#define EXPR_TERNARY 0x0004
+
+static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms) {
+ int rc;
+ struct JimExprNode *node;
+
+ int exp_stacklen = builder->stack.len + exp_numterms;
+
+ if (builder->level++ > 200) {
+ Jim_SetResultString(interp, "Expression too complex", -1);
+ return JIM_ERR;
+ }
+
+ while (builder->token->type != JIM_TT_EOL) {
+ ParseToken *t = builder->token++;
+ int prevtt;
+
+ if (t == builder->first_token) {
+ prevtt = JIM_TT_NONE;
+ }
+ else {
+ prevtt = t[-1].type;
+ }
+
+ if (t->type == JIM_TT_SUBEXPR_START) {
+ if (builder->stack.len == exp_stacklen) {
+ Jim_SetResultFormatted(interp, "unexpected open parenthesis in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+ builder->parencount++;
+ rc = ExprTreeBuildTree(interp, builder, 0, EXPR_UNTIL_CLOSE, 1);
+ if (rc != JIM_OK) {
+ return rc;
+ }
+
+ }
+ else if (t->type == JIM_TT_SUBEXPR_END) {
+ if (!(flags & EXPR_UNTIL_CLOSE)) {
+ if (builder->stack.len == exp_stacklen && builder->level > 1) {
+ builder->token--;
+ builder->level--;
+ return JIM_OK;
+ }
+ Jim_SetResultFormatted(interp, "unexpected closing parenthesis in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+ builder->parencount--;
+ if (builder->stack.len == exp_stacklen) {
+
+ break;
+ }
+ }
+ else if (t->type == JIM_TT_SUBEXPR_COMMA) {
+ if (!(flags & EXPR_FUNC_ARGS)) {
+ if (builder->stack.len == exp_stacklen) {
+
+ builder->token--;
+ builder->level--;
+ return JIM_OK;
+ }
+ Jim_SetResultFormatted(interp, "unexpected comma in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+ else {
+
+ if (builder->stack.len > exp_stacklen) {
+ Jim_SetResultFormatted(interp, "too many arguments to math function");
+ return JIM_ERR;
+ }
+ }
+
+ }
+ else if (t->type == JIM_EXPROP_COLON) {
+ if (!(flags & EXPR_TERNARY)) {
+ if (builder->level != 1) {
+
+ builder->token--;
+ builder->level--;
+ return JIM_OK;
+ }
+ Jim_SetResultFormatted(interp, ": without ? in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+ if (builder->stack.len == exp_stacklen) {
+
+ builder->token--;
+ builder->level--;
+ return JIM_OK;
+ }
+
+ }
+ else if (TOKEN_IS_EXPR_OP(t->type)) {
+ const struct Jim_ExprOperator *op;
+
+
+ if (TOKEN_IS_EXPR_OP(prevtt) || TOKEN_IS_EXPR_START(prevtt)) {
+ if (t->type == JIM_EXPROP_SUB) {
+ t->type = JIM_EXPROP_UNARYMINUS;
+ }
+ else if (t->type == JIM_EXPROP_ADD) {
+ t->type = JIM_EXPROP_UNARYPLUS;
+ }
+ }
+
+ op = JimExprOperatorInfoByOpcode(t->type);
+
+ if (op->precedence < precedence || (!(op->attr & OP_RIGHT_ASSOC) && op->precedence == precedence)) {
+
+ builder->token--;
+ break;
+ }
+
+ if (op->attr & OP_FUNC) {
+ if (builder->token->type != JIM_TT_SUBEXPR_START) {
+ Jim_SetResultString(interp, "missing arguments for math function", -1);
+ return JIM_ERR;
+ }
+ builder->token++;
+ if (op->arity == 0) {
+ if (builder->token->type != JIM_TT_SUBEXPR_END) {
+ Jim_SetResultString(interp, "too many arguments for math function", -1);
+ return JIM_ERR;
+ }
+ builder->token++;
+ goto noargs;
+ }
+ builder->parencount++;
+
+
+ rc = ExprTreeBuildTree(interp, builder, 0, EXPR_FUNC_ARGS | EXPR_UNTIL_CLOSE, op->arity);
+ }
+ else if (t->type == JIM_EXPROP_TERNARY) {
+
+ rc = ExprTreeBuildTree(interp, builder, op->precedence, EXPR_TERNARY, 2);
+ }
+ else {
+ rc = ExprTreeBuildTree(interp, builder, op->precedence, 0, 1);
+ }
+
+ if (rc != JIM_OK) {
+ return rc;
+ }
+
+noargs:
+ node = builder->next++;
+ node->type = t->type;
+
+ if (op->arity >= 3) {
+ node->ternary = Jim_StackPop(&builder->stack);
+ if (node->ternary == NULL) {
+ goto missingoperand;
+ }
+ }
+ if (op->arity >= 2) {
+ node->right = Jim_StackPop(&builder->stack);
+ if (node->right == NULL) {
+ goto missingoperand;
+ }
+ }
+ if (op->arity >= 1) {
+ node->left = Jim_StackPop(&builder->stack);
+ if (node->left == NULL) {
+missingoperand:
+ Jim_SetResultFormatted(interp, "missing operand to %s in expression: \"%#s\"", op->name, builder->exprObjPtr);
+ builder->next--;
+ return JIM_ERR;
+
+ }
+ }
+
+
+ Jim_StackPush(&builder->stack, node);
+ }
+ else {
+ Jim_Obj *objPtr = NULL;
+
+
+
+
+ if (!TOKEN_IS_EXPR_START(prevtt) && !TOKEN_IS_EXPR_OP(prevtt)) {
+ Jim_SetResultFormatted(interp, "missing operator in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+
+
+ if (t->type == JIM_TT_EXPR_INT || t->type == JIM_TT_EXPR_DOUBLE) {
+ char *endptr;
+ if (t->type == JIM_TT_EXPR_INT) {
+ objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
+ }
+ else {
+ objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
+ }
+ if (endptr != t->token + t->len) {
+
+ Jim_FreeNewObj(interp, objPtr);
+ objPtr = NULL;
+ }
+ }
+
+ if (!objPtr) {
+
+ objPtr = Jim_NewStringObj(interp, t->token, t->len);
+ if (t->type == JIM_TT_CMD) {
+
+ Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
+ }
+ }
+
+
+ node = builder->next++;
+ node->objPtr = objPtr;
+ Jim_IncrRefCount(node->objPtr);
+ node->type = t->type;
+ Jim_StackPush(&builder->stack, node);
+ }
+ }
+
+ if (builder->stack.len == exp_stacklen) {
+ builder->level--;
+ return JIM_OK;
+ }
+
+ if ((flags & EXPR_FUNC_ARGS)) {
+ Jim_SetResultFormatted(interp, "too %s arguments for math function", (builder->stack.len < exp_stacklen) ? "few" : "many");
+ }
+ else {
+ if (builder->stack.len < exp_stacklen) {
+ if (builder->level == 0) {
+ Jim_SetResultFormatted(interp, "empty expression");
+ }
+ else {
+ Jim_SetResultFormatted(interp, "syntax error in expression \"%#s\": premature end of expression", builder->exprObjPtr);
+ }
+ }
+ else {
+ Jim_SetResultFormatted(interp, "extra terms after expression");
+ }
+ }
+
+ return JIM_ERR;
+}
+
+static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *exprObjPtr, Jim_Obj *fileNameObj)
+{
+ struct ExprTree *expr;
+ struct ExprBuilder builder;
+ int rc;
+ struct JimExprNode *top = NULL;
+
+ builder.parencount = 0;
+ builder.level = 0;
+ builder.token = builder.first_token = tokenlist->list;
+ builder.exprObjPtr = exprObjPtr;
+ builder.fileNameObj = fileNameObj;
+
+ builder.nodes = Jim_Alloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
+ memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1));
+ builder.next = builder.nodes;
+ Jim_InitStack(&builder.stack);
+
+ rc = ExprTreeBuildTree(interp, &builder, 0, 0, 1);
+
+ if (rc == JIM_OK) {
+ top = Jim_StackPop(&builder.stack);
+
+ if (builder.parencount) {
+ Jim_SetResultString(interp, "missing close parenthesis", -1);
+ rc = JIM_ERR;
+ }
+ }
+
+
+ Jim_FreeStack(&builder.stack);
+
+ if (rc != JIM_OK) {
+ ExprTreeFreeNodes(interp, builder.nodes, builder.next - builder.nodes);
+ return NULL;
+ }
+
+ expr = Jim_Alloc(sizeof(*expr));
+ expr->inUse = 1;
+ expr->expr = top;
+ expr->nodes = builder.nodes;
+ expr->len = builder.next - builder.nodes;
+
+ assert(expr->len <= tokenlist->count - 1);
+
+ return expr;
+}
+
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ int exprTextLen;
+ const char *exprText;
+ struct JimParserCtx parser;
+ struct ExprTree *expr;
+ ParseTokenList tokenlist;
+ int line;
+ Jim_Obj *fileNameObj;
+ int rc = JIM_ERR;
+
+
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
+ Jim_IncrRefCount(fileNameObj);
+
+ exprText = Jim_GetString(objPtr, &exprTextLen);
+
+
+ ScriptTokenListInit(&tokenlist);
+
+ JimParserInit(&parser, exprText, exprTextLen, line);
+ while (!parser.eof) {
+ if (JimParseExpression(&parser) != JIM_OK) {
+ ScriptTokenListFree(&tokenlist);
+ Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
+ if (parser.errmsg) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), ": ", parser.errmsg, NULL);
+ }
+ expr = NULL;
+ goto err;
+ }
+
+ ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+ parser.tline);
+ }
+
+#ifdef DEBUG_SHOW_EXPR_TOKENS
+ {
+ int i;
+ printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj));
+ for (i = 0; i < tokenlist.count; i++) {
+ printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type),
+ tokenlist.list[i].len, tokenlist.list[i].token);
+ }
+ }
+#endif
+
+ if (tokenlist.count <= 1) {
+ Jim_SetResultString(interp, "empty expression", -1);
+ rc = JIM_ERR;
+ }
+ else {
+ rc = JimParseCheckMissing(interp, parser.missing.ch);
+ }
+ if (rc != JIM_OK) {
+ ScriptTokenListFree(&tokenlist);
+ Jim_DecrRefCount(interp, fileNameObj);
+ return rc;
+ }
+
+
+ expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
+
+
+ ScriptTokenListFree(&tokenlist);
+
+ if (!expr) {
+ goto err;
+ }
+
+#ifdef DEBUG_SHOW_EXPR
+ printf("==== Expr ====\n");
+ JimShowExprNode(expr->expr, 0);
+#endif
+
+ rc = JIM_OK;
+
+ err:
+
+ Jim_DecrRefCount(interp, fileNameObj);
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_SetIntRepPtr(objPtr, expr);
+ objPtr->typePtr = &exprObjType;
+ return rc;
+}
+
+static struct ExprTree *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &exprObjType) {
+ if (SetExprFromAny(interp, objPtr) != JIM_OK) {
+ return NULL;
+ }
+ }
+ return (struct ExprTree *) Jim_GetIntRepPtr(objPtr);
+}
+
+#ifdef JIM_OPTIMIZATION
+static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, struct JimExprNode *node)
+{
+ if (node->type == JIM_TT_EXPR_INT)
+ return node->objPtr;
+ else if (node->type == JIM_TT_VAR)
+ return Jim_GetVariable(interp, node->objPtr, JIM_NONE);
+ else if (node->type == JIM_TT_DICTSUGAR)
+ return JimExpandDictSugar(interp, node->objPtr);
+ else
+ return NULL;
+}
+#endif
+
+
+static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node)
+{
+ if (TOKEN_IS_EXPR_OP(node->type)) {
+ const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(node->type);
+ return op->funcop(interp, node);
+ }
+ else {
+ Jim_Obj *objPtr;
+
+
+ switch (node->type) {
+ case JIM_TT_EXPR_INT:
+ case JIM_TT_EXPR_DOUBLE:
+ case JIM_TT_EXPR_BOOLEAN:
+ case JIM_TT_STR:
+ Jim_SetResult(interp, node->objPtr);
+ return JIM_OK;
+
+ case JIM_TT_VAR:
+ objPtr = Jim_GetVariable(interp, node->objPtr, JIM_ERRMSG);
+ if (objPtr) {
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+
+ case JIM_TT_DICTSUGAR:
+ objPtr = JimExpandDictSugar(interp, node->objPtr);
+ if (objPtr) {
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+
+ case JIM_TT_ESC:
+ if (interp->safeexpr) {
+ return JIM_ERR;
+ }
+ if (Jim_SubstObj(interp, node->objPtr, &objPtr, JIM_NONE) == JIM_OK) {
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+
+ case JIM_TT_CMD:
+ if (interp->safeexpr) {
+ return JIM_ERR;
+ }
+ return Jim_EvalObj(interp, node->objPtr);
+
+ default:
+
+ return JIM_ERR;
+ }
+ }
+}
+
+static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr)
+{
+ int rc = JimExprEvalTermNode(interp, node);
+ if (rc == JIM_OK) {
+ *objPtrPtr = Jim_GetResult(interp);
+ Jim_IncrRefCount(*objPtrPtr);
+ }
+ return rc;
+}
+
+static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node)
+{
+ if (JimExprEvalTermNode(interp, node) == JIM_OK) {
+ return ExprBool(interp, Jim_GetResult(interp));
+ }
+ return -1;
+}
+
+int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
+{
+ struct ExprTree *expr;
+ int retcode = JIM_OK;
+
+ Jim_IncrRefCount(exprObjPtr);
+ expr = JimGetExpression(interp, exprObjPtr);
+ if (!expr) {
+ retcode = JIM_ERR;
+ goto done;
+ }
+
+#ifdef JIM_OPTIMIZATION
+ if (!interp->safeexpr) {
+ Jim_Obj *objPtr;
+
+
+ switch (expr->len) {
+ case 1:
+ objPtr = JimExprIntValOrVar(interp, expr->expr);
+ if (objPtr) {
+ Jim_SetResult(interp, objPtr);
+ goto done;
+ }
+ break;
+
+ case 2:
+ if (expr->expr->type == JIM_EXPROP_NOT) {
+ objPtr = JimExprIntValOrVar(interp, expr->expr->left);
+
+ if (objPtr && JimIsWide(objPtr)) {
+ Jim_SetResult(interp, JimWideValue(objPtr) ? interp->falseObj : interp->trueObj);
+ goto done;
+ }
+ }
+ break;
+
+ case 3:
+ objPtr = JimExprIntValOrVar(interp, expr->expr->left);
+ if (objPtr && JimIsWide(objPtr)) {
+ Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, expr->expr->right);
+ if (objPtr2 && JimIsWide(objPtr2)) {
+ jim_wide wideValueA = JimWideValue(objPtr);
+ jim_wide wideValueB = JimWideValue(objPtr2);
+ int cmpRes;
+ switch (expr->expr->type) {
+ case JIM_EXPROP_LT:
+ cmpRes = wideValueA < wideValueB;
+ break;
+ case JIM_EXPROP_LTE:
+ cmpRes = wideValueA <= wideValueB;
+ break;
+ case JIM_EXPROP_GT:
+ cmpRes = wideValueA > wideValueB;
+ break;
+ case JIM_EXPROP_GTE:
+ cmpRes = wideValueA >= wideValueB;
+ break;
+ case JIM_EXPROP_NUMEQ:
+ cmpRes = wideValueA == wideValueB;
+ break;
+ case JIM_EXPROP_NUMNE:
+ cmpRes = wideValueA != wideValueB;
+ break;
+ default:
+ goto noopt;
+ }
+ Jim_SetResult(interp, cmpRes ? interp->trueObj : interp->falseObj);
+ goto done;
+ }
+ }
+ break;
+ }
+ }
+noopt:
+#endif
+
+ expr->inUse++;
+
+
+ retcode = JimExprEvalTermNode(interp, expr->expr);
+
+
+ Jim_FreeIntRep(interp, exprObjPtr);
+ exprObjPtr->typePtr = &exprObjType;
+ Jim_SetIntRepPtr(exprObjPtr, expr);
+
+done:
+ Jim_DecrRefCount(interp, exprObjPtr);
+
+ return retcode;
+}
+
+int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
+{
+ int retcode = Jim_EvalExpression(interp, exprObjPtr);
+
+ if (retcode == JIM_OK) {
+ switch (ExprBool(interp, Jim_GetResult(interp))) {
+ case 0:
+ *boolPtr = 0;
+ break;
+
+ case 1:
+ *boolPtr = 1;
+ break;
+
+ case -1:
+ retcode = JIM_ERR;
+ break;
+ }
+ }
+ return retcode;
+}
+
+
+
+
+typedef struct ScanFmtPartDescr
+{
+ const char *arg;
+ const char *prefix;
+ size_t width;
+ int pos;
+ char type;
+ char modifier;
+} ScanFmtPartDescr;
+
+
+typedef struct ScanFmtStringObj
+{
+ jim_wide size;
+ char *stringRep;
+ size_t count;
+ size_t convCount;
+ size_t maxPos;
+ const char *error;
+ char *scratch;
+ ScanFmtPartDescr descr[1];
+} ScanFmtStringObj;
+
+
+static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
+
+static const Jim_ObjType scanFmtStringObjType = {
+ "scanformatstring",
+ FreeScanFmtInternalRep,
+ DupScanFmtInternalRep,
+ UpdateStringOfScanFmt,
+ JIM_TYPE_NONE,
+};
+
+void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ JIM_NOTUSED(interp);
+ Jim_Free((char *)objPtr->internalRep.ptr);
+ objPtr->internalRep.ptr = 0;
+}
+
+void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size;
+ ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size);
+
+ JIM_NOTUSED(interp);
+ memcpy(newVec, srcPtr->internalRep.ptr, size);
+ dupPtr->internalRep.ptr = newVec;
+ dupPtr->typePtr = &scanFmtStringObjType;
+}
+
+static void UpdateStringOfScanFmt(Jim_Obj *objPtr)
+{
+ JimSetStringBytes(objPtr, ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep);
+}
+
+
+static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ ScanFmtStringObj *fmtObj;
+ char *buffer;
+ int maxCount, i, approxSize, lastPos = -1;
+ const char *fmt = Jim_String(objPtr);
+ int maxFmtLen = Jim_Length(objPtr);
+ const char *fmtEnd = fmt + maxFmtLen;
+ int curr;
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
+ if (fmt[i] == '%')
+ ++maxCount;
+
+ approxSize = sizeof(ScanFmtStringObj)
+ +(maxCount + 1) * sizeof(ScanFmtPartDescr)
+ +maxFmtLen * sizeof(char) + 3 + 1
+ + maxFmtLen * sizeof(char) + 1
+ + maxFmtLen * sizeof(char)
+ +(maxCount + 1) * sizeof(char)
+ +1;
+ fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
+ memset(fmtObj, 0, approxSize);
+ fmtObj->size = approxSize;
+ fmtObj->maxPos = 0;
+ fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
+ fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
+ memcpy(fmtObj->stringRep, fmt, maxFmtLen);
+ buffer = fmtObj->stringRep + maxFmtLen + 1;
+ objPtr->internalRep.ptr = fmtObj;
+ objPtr->typePtr = &scanFmtStringObjType;
+ for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
+ int width = 0, skip;
+ ScanFmtPartDescr *descr = &fmtObj->descr[curr];
+
+ fmtObj->count++;
+ descr->width = 0;
+
+ if (*fmt != '%' || fmt[1] == '%') {
+ descr->type = 0;
+ descr->prefix = &buffer[i];
+ for (; fmt < fmtEnd; ++fmt) {
+ if (*fmt == '%') {
+ if (fmt[1] != '%')
+ break;
+ ++fmt;
+ }
+ buffer[i++] = *fmt;
+ }
+ buffer[i++] = 0;
+ }
+
+ ++fmt;
+
+ if (fmt >= fmtEnd)
+ goto done;
+ descr->pos = 0;
+ if (*fmt == '*') {
+ descr->pos = -1;
+ ++fmt;
+ }
+ else
+ fmtObj->convCount++;
+
+ if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+ fmt += skip;
+
+ if (descr->pos != -1 && *fmt == '$') {
+ int prev;
+
+ ++fmt;
+ descr->pos = width;
+ width = 0;
+
+ if ((lastPos == 0 && descr->pos > 0)
+ || (lastPos > 0 && descr->pos == 0)) {
+ fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
+ return JIM_ERR;
+ }
+
+ for (prev = 0; prev < curr; ++prev) {
+ if (fmtObj->descr[prev].pos == -1)
+ continue;
+ if (fmtObj->descr[prev].pos == descr->pos) {
+ fmtObj->error =
+ "variable is assigned by multiple \"%n$\" conversion specifiers";
+ return JIM_ERR;
+ }
+ }
+ if (descr->pos < 0) {
+ fmtObj->error =
+ "\"%n$\" conversion specifier is negative";
+ return JIM_ERR;
+ }
+
+ if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+ descr->width = width;
+ fmt += skip;
+ }
+ if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
+ fmtObj->maxPos = descr->pos;
+ }
+ else {
+
+ descr->width = width;
+ }
+ }
+
+ if (lastPos == -1)
+ lastPos = descr->pos;
+
+ if (*fmt == '[') {
+ int swapped = 1, beg = i, end, j;
+
+ descr->type = '[';
+ descr->arg = &buffer[i];
+ ++fmt;
+ if (*fmt == '^')
+ buffer[i++] = *fmt++;
+ if (*fmt == ']')
+ buffer[i++] = *fmt++;
+ while (*fmt && *fmt != ']')
+ buffer[i++] = *fmt++;
+ if (*fmt != ']') {
+ fmtObj->error = "unmatched [ in format string";
+ return JIM_ERR;
+ }
+ end = i;
+ buffer[i++] = 0;
+
+ while (swapped) {
+ swapped = 0;
+ for (j = beg + 1; j < end - 1; ++j) {
+ if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
+ char tmp = buffer[j - 1];
+
+ buffer[j - 1] = buffer[j + 1];
+ buffer[j + 1] = tmp;
+ swapped = 1;
+ }
+ }
+ }
+ }
+ else {
+
+ if (fmt < fmtEnd && strchr("hlL", *fmt))
+ descr->modifier = tolower((int)*fmt++);
+
+ if (fmt >= fmtEnd) {
+ fmtObj->error = "missing scan conversion character";
+ return JIM_ERR;
+ }
+
+ descr->type = *fmt;
+ if (strchr("efgcsndoxui", *fmt) == 0) {
+ fmtObj->error = "bad scan conversion character";
+ return JIM_ERR;
+ }
+ else if (*fmt == 'c' && descr->width != 0) {
+ fmtObj->error = "field width may not be specified in %c " "conversion";
+ return JIM_ERR;
+ }
+ else if (*fmt == 'u' && descr->modifier == 'l') {
+ fmtObj->error = "unsigned wide not supported";
+ return JIM_ERR;
+ }
+ }
+ curr++;
+ }
+ done:
+ return JIM_OK;
+}
+
+
+
+#define FormatGetCnvCount(_fo_) \
+ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
+#define FormatGetMaxPos(_fo_) \
+ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
+#define FormatGetError(_fo_) \
+ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
+
+static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
+{
+ char *buffer = Jim_StrDup(str);
+ char *p = buffer;
+
+ while (*str) {
+ int c;
+ int n;
+
+ if (!sdescr && isspace(UCHAR(*str)))
+ break;
+
+ n = utf8_tounicode(str, &c);
+ if (sdescr && !JimCharsetMatch(sdescr, strlen(sdescr), c, JIM_CHARSET_SCAN))
+ break;
+ while (n--)
+ *p++ = *str++;
+ }
+ *p = 0;
+ return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer);
+}
+
+
+static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int str_bytelen,
+ ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
+{
+ const char *tok;
+ const ScanFmtPartDescr *descr = &fmtObj->descr[idx];
+ size_t scanned = 0;
+ size_t anchor = pos;
+ int i;
+ Jim_Obj *tmpObj = NULL;
+
+
+ *valObjPtr = 0;
+ if (descr->prefix) {
+ for (i = 0; pos < str_bytelen && descr->prefix[i]; ++i) {
+
+ if (isspace(UCHAR(descr->prefix[i])))
+ while (pos < str_bytelen && isspace(UCHAR(str[pos])))
+ ++pos;
+ else if (descr->prefix[i] != str[pos])
+ break;
+ else
+ ++pos;
+ }
+ if (pos >= str_bytelen) {
+ return -1;
+ }
+ else if (descr->prefix[i] != 0)
+ return 0;
+ }
+
+ if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
+ while (isspace(UCHAR(str[pos])))
+ ++pos;
+
+
+ scanned = pos - anchor;
+
+
+ if (descr->type == 'n') {
+
+ *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
+ }
+ else if (pos >= str_bytelen) {
+
+ return -1;
+ }
+ else if (descr->type == 'c') {
+ int c;
+ scanned += utf8_tounicode(&str[pos], &c);
+ *valObjPtr = Jim_NewIntObj(interp, c);
+ return scanned;
+ }
+ else {
+
+ if (descr->width > 0) {
+ size_t sLen = utf8_strlen(&str[pos], str_bytelen - pos);
+ size_t tLen = descr->width > sLen ? sLen : descr->width;
+
+ tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
+ tok = tmpObj->bytes;
+ }
+ else {
+
+ tok = &str[pos];
+ }
+ switch (descr->type) {
+ case 'd':
+ case 'o':
+ case 'x':
+ case 'u':
+ case 'i':{
+ char *endp;
+ jim_wide w;
+
+ int base = descr->type == 'o' ? 8
+ : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
+
+
+ if (base == 0) {
+ w = jim_strtoull(tok, &endp);
+ }
+ else {
+ w = strtoull(tok, &endp, base);
+ }
+
+ if (endp != tok) {
+
+ *valObjPtr = Jim_NewIntObj(interp, w);
+
+
+ scanned += endp - tok;
+ }
+ else {
+ scanned = *tok ? 0 : -1;
+ }
+ break;
+ }
+ case 's':
+ case '[':{
+ *valObjPtr = JimScanAString(interp, descr->arg, tok);
+ scanned += Jim_Length(*valObjPtr);
+ break;
+ }
+ case 'e':
+ case 'f':
+ case 'g':{
+ char *endp;
+ double value = strtod(tok, &endp);
+
+ if (endp != tok) {
+
+ *valObjPtr = Jim_NewDoubleObj(interp, value);
+
+ scanned += endp - tok;
+ }
+ else {
+ scanned = *tok ? 0 : -1;
+ }
+ break;
+ }
+ }
+ if (tmpObj) {
+ Jim_FreeNewObj(interp, tmpObj);
+ }
+ }
+ return scanned;
+}
+
+
+Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags)
+{
+ size_t i, pos;
+ int scanned = 1;
+ const char *str = Jim_String(strObjPtr);
+ int str_bytelen = Jim_Length(strObjPtr);
+ Jim_Obj *resultList = 0;
+ Jim_Obj **resultVec = 0;
+ int resultc;
+ Jim_Obj *emptyStr = 0;
+ ScanFmtStringObj *fmtObj;
+
+
+ JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
+
+ fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
+
+ if (fmtObj->error != 0) {
+ if (flags & JIM_ERRMSG)
+ Jim_SetResultString(interp, fmtObj->error, -1);
+ return 0;
+ }
+
+ emptyStr = Jim_NewEmptyStringObj(interp);
+ Jim_IncrRefCount(emptyStr);
+
+ resultList = Jim_NewListObj(interp, NULL, 0);
+ if (fmtObj->maxPos > 0) {
+ for (i = 0; i < fmtObj->maxPos; ++i)
+ Jim_ListAppendElement(interp, resultList, emptyStr);
+ JimListGetElements(interp, resultList, &resultc, &resultVec);
+ }
+
+ for (i = 0, pos = 0; i < fmtObj->count; ++i) {
+ ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
+ Jim_Obj *value = 0;
+
+
+ if (descr->type == 0)
+ continue;
+
+ if (scanned > 0)
+ scanned = ScanOneEntry(interp, str, pos, str_bytelen, fmtObj, i, &value);
+
+ if (scanned == -1 && i == 0)
+ goto eof;
+
+ pos += scanned;
+
+
+ if (value == 0)
+ value = Jim_NewEmptyStringObj(interp);
+
+ if (descr->pos == -1) {
+ Jim_FreeNewObj(interp, value);
+ }
+ else if (descr->pos == 0)
+
+ Jim_ListAppendElement(interp, resultList, value);
+ else if (resultVec[descr->pos - 1] == emptyStr) {
+
+ Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
+ Jim_IncrRefCount(value);
+ resultVec[descr->pos - 1] = value;
+ }
+ else {
+
+ Jim_FreeNewObj(interp, value);
+ goto err;
+ }
+ }
+ Jim_DecrRefCount(interp, emptyStr);
+ return resultList;
+ eof:
+ Jim_DecrRefCount(interp, emptyStr);
+ Jim_FreeNewObj(interp, resultList);
+ return (Jim_Obj *)EOF;
+ err:
+ Jim_DecrRefCount(interp, emptyStr);
+ Jim_FreeNewObj(interp, resultList);
+ return 0;
+}
+
+
+static void JimPrngInit(Jim_Interp *interp)
+{
+#define PRNG_SEED_SIZE 256
+ int i;
+ unsigned int *seed;
+ time_t t = time(NULL);
+
+ interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
+
+ seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed));
+ for (i = 0; i < PRNG_SEED_SIZE; i++) {
+ seed[i] = (rand() ^ t ^ clock());
+ }
+ JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed));
+ Jim_Free(seed);
+}
+
+
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
+{
+ Jim_PrngState *prng;
+ unsigned char *destByte = (unsigned char *)dest;
+ unsigned int si, sj, x;
+
+
+ if (interp->prngState == NULL)
+ JimPrngInit(interp);
+ prng = interp->prngState;
+
+ for (x = 0; x < len; x++) {
+ prng->i = (prng->i + 1) & 0xff;
+ si = prng->sbox[prng->i];
+ prng->j = (prng->j + si) & 0xff;
+ sj = prng->sbox[prng->j];
+ prng->sbox[prng->i] = sj;
+ prng->sbox[prng->j] = si;
+ *destByte++ = prng->sbox[(si + sj) & 0xff];
+ }
+}
+
+
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
+{
+ int i;
+ Jim_PrngState *prng;
+
+
+ if (interp->prngState == NULL)
+ JimPrngInit(interp);
+ prng = interp->prngState;
+
+
+ for (i = 0; i < 256; i++)
+ prng->sbox[i] = i;
+
+ for (i = 0; i < seedLen; i++) {
+ unsigned char t;
+
+ t = prng->sbox[i & 0xFF];
+ prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
+ prng->sbox[seed[i]] = t;
+ }
+ prng->i = prng->j = 0;
+
+ for (i = 0; i < 256; i += seedLen) {
+ JimRandomBytes(interp, seed, seedLen);
+ }
+}
+
+
+static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_wide wideValue, increment = 1;
+ Jim_Obj *intObjPtr;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (Jim_GetWideExpr(interp, argv[2], &increment) != JIM_OK)
+ return JIM_ERR;
+ }
+ intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+ if (!intObjPtr) {
+
+ wideValue = 0;
+ }
+ else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (!intObjPtr || Jim_IsShared(intObjPtr)) {
+ intObjPtr = Jim_NewIntObj(interp, wideValue + increment);
+ if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, intObjPtr);
+ return JIM_ERR;
+ }
+ }
+ else {
+
+ Jim_InvalidateStringRep(intObjPtr);
+ JimWideValue(intObjPtr) = wideValue + increment;
+
+ if (argv[1]->typePtr != &variableObjType) {
+
+ Jim_SetVariable(interp, argv[1], intObjPtr);
+ }
+ }
+ Jim_SetResult(interp, intObjPtr);
+ return JIM_OK;
+}
+
+
+#define JIM_EVAL_SARGV_LEN 8
+#define JIM_EVAL_SINTV_LEN 8
+
+static int JimTraceCallback(Jim_Interp *interp, const char *type, int argc, Jim_Obj *const *argv)
+{
+ JimPanic((interp->traceCmdObj == NULL, "xtrace invoked with no object"));
+
+ int ret;
+ Jim_Obj *nargv[7];
+ Jim_Obj *traceCmdObj = interp->traceCmdObj;
+ Jim_Obj *resultObj = Jim_GetResult(interp);
+ ScriptObj *script = NULL;
+
+
+
+ if (interp->evalFrame->scriptObj) {
+ script = JimGetScript(interp, interp->evalFrame->scriptObj);
+ }
+
+ nargv[0] = traceCmdObj;
+ nargv[1] = Jim_NewStringObj(interp, type, -1);
+ nargv[2] = script ? script->fileNameObj : interp->emptyObj;
+ nargv[3] = Jim_NewIntObj(interp, script ? script->linenr : 1);
+ nargv[4] = resultObj;
+ nargv[5] = argv[0];
+ nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
+
+
+ interp->traceCmdObj = NULL;
+
+ Jim_IncrRefCount(resultObj);
+ ret = Jim_EvalObjVector(interp, 7, nargv);
+ Jim_DecrRefCount(interp, resultObj);
+
+ if (ret == JIM_OK || ret == JIM_RETURN) {
+
+ interp->traceCmdObj = traceCmdObj;
+ Jim_SetEmptyResult(interp);
+ ret = JIM_OK;
+ }
+ else {
+
+ Jim_DecrRefCount(interp, traceCmdObj);
+ }
+ return ret;
+}
+
+
+static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retcode;
+
+ if (interp->unknown_called > 50) {
+ return JIM_ERR;
+ }
+
+
+
+ if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
+ return JIM_ERR;
+
+ interp->unknown_called++;
+
+ retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv);
+ interp->unknown_called--;
+
+ return retcode;
+}
+
+static void JimPushEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *scriptObj)
+{
+ memset(frame, 0, sizeof(*frame));
+ frame->parent = interp->evalFrame;
+ frame->level = frame->parent->level + 1;
+ frame->procLevel = interp->procLevel;
+ frame->framePtr = interp->framePtr;
+ if (scriptObj) {
+ frame->scriptObj = scriptObj;
+ }
+ else {
+ frame->scriptObj = frame->parent->scriptObj;
+ }
+ interp->evalFrame = frame;
+#if 0
+ if (frame->scriptObj) {
+ printf("script: %.*s\n", 20, Jim_String(frame->scriptObj));
+ }
+#endif
+}
+
+static void JimPopEvalFrame(Jim_Interp *interp)
+{
+ interp->evalFrame = interp->evalFrame->parent;
+}
+
+
+static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ int retcode;
+ Jim_Cmd *cmdPtr;
+ void *prevPrivData;
+ Jim_Obj *tailcallObj = NULL;
+
+#if 0
+ printf("invoke");
+ int j;
+ for (j = 0; j < objc; j++) {
+ printf(" '%s'", Jim_String(objv[j]));
+ }
+ printf("\n");
+#endif
+
+ cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
+ if (cmdPtr == NULL) {
+ return JimUnknown(interp, objc, objv);
+ }
+ JimIncrCmdRefCount(cmdPtr);
+
+ if (interp->evalDepth == interp->maxEvalDepth) {
+ Jim_SetResultString(interp, "Infinite eval recursion", -1);
+ retcode = JIM_ERR;
+ goto out;
+ }
+ interp->evalDepth++;
+ prevPrivData = interp->cmdPrivData;
+
+tailcall:
+
+ interp->evalFrame->argc = objc;
+ interp->evalFrame->argv = objv;
+ interp->evalFrame->cmd = cmdPtr;
+
+ if (!interp->traceCmdObj ||
+ (retcode = JimTraceCallback(interp, "cmd", objc, objv)) == JIM_OK) {
+
+ Jim_SetEmptyResult(interp);
+ if (cmdPtr->isproc) {
+ retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
+ }
+ else {
+ interp->cmdPrivData = cmdPtr->u.native.privData;
+ retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
+ }
+ if (retcode == JIM_ERR) {
+ JimSetErrorStack(interp, NULL);
+ }
+ }
+
+ if (tailcallObj) {
+
+ Jim_DecrRefCount(interp, tailcallObj);
+ tailcallObj = NULL;
+ }
+
+
+ interp->evalFrame->argc = 0;
+ interp->evalFrame->argv = NULL;
+
+
+ if (retcode == JIM_EVAL && interp->framePtr->tailcallObj) {
+ JimDecrCmdRefCount(interp, cmdPtr);
+
+
+ cmdPtr = interp->framePtr->tailcallCmd;
+ interp->framePtr->tailcallCmd = NULL;
+ tailcallObj = interp->framePtr->tailcallObj;
+ interp->framePtr->tailcallObj = NULL;
+ objc = tailcallObj->internalRep.listValue.len;
+ objv = tailcallObj->internalRep.listValue.ele;
+ goto tailcall;
+ }
+
+ interp->cmdPrivData = prevPrivData;
+ interp->evalDepth--;
+
+out:
+ JimDecrCmdRefCount(interp, cmdPtr);
+
+ if (retcode == JIM_ERR) {
+ JimSetErrorStack(interp, NULL);
+ }
+
+ if (interp->framePtr->tailcallObj) {
+ JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
+ Jim_DecrRefCount(interp, interp->framePtr->tailcallObj);
+ interp->framePtr->tailcallCmd = NULL;
+ interp->framePtr->tailcallObj = NULL;
+ }
+
+ return retcode;
+}
+
+int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ int i, retcode;
+ Jim_EvalFrame frame;
+
+
+ for (i = 0; i < objc; i++)
+ Jim_IncrRefCount(objv[i]);
+
+
+ JimPushEvalFrame(interp, &frame, NULL);
+
+ retcode = JimInvokeCommand(interp, objc, objv);
+
+ JimPopEvalFrame(interp);
+
+
+ for (i = 0; i < objc; i++)
+ Jim_DecrRefCount(interp, objv[i]);
+
+ return retcode;
+}
+
+int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv)
+{
+ int ret;
+ Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv));
+
+ nargv[0] = prefix;
+ memcpy(&nargv[1], &objv[0], sizeof(nargv[0]) * objc);
+ ret = Jim_EvalObjVector(interp, objc + 1, nargv);
+ Jim_Free(nargv);
+ return ret;
+}
+
+static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
+{
+ Jim_Obj *objPtr;
+ int ret = JIM_ERR;
+
+ switch (token->type) {
+ case JIM_TT_STR:
+ case JIM_TT_ESC:
+ objPtr = token->objPtr;
+ break;
+ case JIM_TT_VAR:
+ objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG);
+ break;
+ case JIM_TT_DICTSUGAR:
+ objPtr = JimExpandDictSugar(interp, token->objPtr);
+ break;
+ case JIM_TT_EXPRSUGAR:
+ ret = Jim_EvalExpression(interp, token->objPtr);
+ if (ret == JIM_OK) {
+ objPtr = Jim_GetResult(interp);
+ }
+ else {
+ objPtr = NULL;
+ }
+ break;
+ case JIM_TT_CMD:
+ ret = Jim_EvalObj(interp, token->objPtr);
+ if (ret == JIM_OK || ret == JIM_RETURN) {
+ objPtr = interp->result;
+ } else {
+
+ objPtr = NULL;
+ }
+ break;
+ default:
+ JimPanic((1,
+ "default token type (%d) reached " "in Jim_SubstObj().", token->type));
+ objPtr = NULL;
+ break;
+ }
+ if (objPtr) {
+ *objPtrPtr = objPtr;
+ return JIM_OK;
+ }
+ return ret;
+}
+
+static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
+{
+ int totlen = 0, i;
+ Jim_Obj **intv;
+ Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
+ Jim_Obj *objPtr;
+ char *s;
+
+ if (tokens <= JIM_EVAL_SINTV_LEN)
+ intv = sintv;
+ else
+ intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens);
+
+ for (i = 0; i < tokens; i++) {
+ switch (JimSubstOneToken(interp, &token[i], &intv[i])) {
+ case JIM_OK:
+ case JIM_RETURN:
+ break;
+ case JIM_BREAK:
+ if (flags & JIM_SUBST_FLAG) {
+
+ tokens = i;
+ continue;
+ }
+
+
+ case JIM_CONTINUE:
+ if (flags & JIM_SUBST_FLAG) {
+ intv[i] = NULL;
+ continue;
+ }
+
+
+ default:
+ while (i--) {
+ Jim_DecrRefCount(interp, intv[i]);
+ }
+ if (intv != sintv) {
+ Jim_Free(intv);
+ }
+ return NULL;
+ }
+ Jim_IncrRefCount(intv[i]);
+ Jim_String(intv[i]);
+ totlen += intv[i]->length;
+ }
+
+
+ if (tokens == 1 && intv[0] && intv == sintv) {
+
+ intv[0]->refCount--;
+ return intv[0];
+ }
+
+ objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
+
+ if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
+ && token[2].type == JIM_TT_VAR) {
+
+ objPtr->typePtr = &interpolatedObjType;
+ objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
+ objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
+ Jim_IncrRefCount(intv[2]);
+ }
+ else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
+
+ int line;
+ Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line);
+ Jim_SetSourceInfo(interp, objPtr, fileNameObj, line);
+ }
+
+
+ s = objPtr->bytes = Jim_Alloc(totlen + 1);
+ objPtr->length = totlen;
+ for (i = 0; i < tokens; i++) {
+ if (intv[i]) {
+ memcpy(s, intv[i]->bytes, intv[i]->length);
+ s += intv[i]->length;
+ Jim_DecrRefCount(interp, intv[i]);
+ }
+ }
+ objPtr->bytes[totlen] = '\0';
+
+ if (intv != sintv) {
+ Jim_Free(intv);
+ }
+
+ return objPtr;
+}
+
+
+static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
+{
+ int retcode = JIM_OK;
+ Jim_EvalFrame frame;
+
+ JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list."));
+
+ JimPushEvalFrame(interp, &frame, NULL);
+
+ if (listPtr->internalRep.listValue.len) {
+ Jim_IncrRefCount(listPtr);
+ retcode = JimInvokeCommand(interp,
+ listPtr->internalRep.listValue.len,
+ listPtr->internalRep.listValue.ele);
+ Jim_DecrRefCount(interp, listPtr);
+ }
+
+ JimPopEvalFrame(interp);
+
+ return retcode;
+}
+
+int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
+{
+ SetListFromAny(interp, listPtr);
+ return JimEvalObjList(interp, listPtr);
+}
+
+int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
+{
+ int i;
+ ScriptObj *script;
+ ScriptToken *token;
+ int retcode = JIM_OK;
+ Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
+ Jim_EvalFrame frame;
+
+ if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
+ return JimEvalObjList(interp, scriptObjPtr);
+ }
+
+ Jim_IncrRefCount(scriptObjPtr);
+ script = JimGetScript(interp, scriptObjPtr);
+ if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
+ JimSetErrorStack(interp, script);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ return JIM_ERR;
+ }
+
+ Jim_SetEmptyResult(interp);
+
+ token = script->token;
+
+#ifdef JIM_OPTIMIZATION
+ if (script->len == 0) {
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ return JIM_OK;
+ }
+ if (script->len == 3
+ && token[1].objPtr->typePtr == &commandObjType
+ && token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0
+ && token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand
+ && token[2].objPtr->typePtr == &variableObjType) {
+
+ Jim_Obj *objPtr = Jim_GetVariable(interp, token[2].objPtr, JIM_NONE);
+
+ if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+ JimWideValue(objPtr)++;
+ Jim_InvalidateStringRep(objPtr);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ }
+#endif
+
+ script->inUse++;
+
+ JimPushEvalFrame(interp, &frame, scriptObjPtr);
+
+
+ interp->errorFlag = 0;
+ argv = sargv;
+
+ for (i = 0; i < script->len && retcode == JIM_OK; ) {
+ int argc;
+ int j;
+
+
+ argc = token[i].objPtr->internalRep.scriptLineValue.argc;
+ script->linenr = token[i].objPtr->internalRep.scriptLineValue.line;
+
+
+ if (argc > JIM_EVAL_SARGV_LEN)
+ argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
+
+
+ i++;
+
+ for (j = 0; j < argc; j++) {
+ long wordtokens = 1;
+ int expand = 0;
+ Jim_Obj *wordObjPtr = NULL;
+
+ if (token[i].type == JIM_TT_WORD) {
+ wordtokens = JimWideValue(token[i++].objPtr);
+ if (wordtokens < 0) {
+ expand = 1;
+ wordtokens = -wordtokens;
+ }
+ }
+
+ if (wordtokens == 1) {
+
+ switch (token[i].type) {
+ case JIM_TT_ESC:
+ case JIM_TT_STR:
+ wordObjPtr = token[i].objPtr;
+ break;
+ case JIM_TT_VAR:
+ wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
+ break;
+ case JIM_TT_EXPRSUGAR:
+ retcode = Jim_EvalExpression(interp, token[i].objPtr);
+ if (retcode == JIM_OK) {
+ wordObjPtr = Jim_GetResult(interp);
+ }
+ else {
+ wordObjPtr = NULL;
+ }
+ break;
+ case JIM_TT_DICTSUGAR:
+ wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr);
+ break;
+ case JIM_TT_CMD:
+ retcode = Jim_EvalObj(interp, token[i].objPtr);
+ if (retcode == JIM_OK) {
+ wordObjPtr = Jim_GetResult(interp);
+ }
+ break;
+ default:
+ JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
+ }
+ }
+ else {
+ wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE);
+ }
+
+ if (!wordObjPtr) {
+ if (retcode == JIM_OK) {
+ retcode = JIM_ERR;
+ }
+ break;
+ }
+
+ Jim_IncrRefCount(wordObjPtr);
+ i += wordtokens;
+
+ if (!expand) {
+ argv[j] = wordObjPtr;
+ }
+ else {
+
+ int len = Jim_ListLength(interp, wordObjPtr);
+ int newargc = argc + len - 1;
+ int k;
+
+ if (len > 1) {
+ if (argv == sargv) {
+ if (newargc > JIM_EVAL_SARGV_LEN) {
+ argv = Jim_Alloc(sizeof(*argv) * newargc);
+ memcpy(argv, sargv, sizeof(*argv) * j);
+ }
+ }
+ else {
+
+ argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
+ }
+ }
+
+
+ for (k = 0; k < len; k++) {
+ argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
+ Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
+ }
+
+ Jim_DecrRefCount(interp, wordObjPtr);
+
+
+ j--;
+ argc += len - 1;
+ }
+ }
+
+ if (retcode == JIM_OK && argc) {
+
+ retcode = JimInvokeCommand(interp, argc, argv);
+
+ if (Jim_CheckSignal(interp)) {
+ retcode = JIM_SIGNAL;
+ }
+ }
+
+
+ while (j-- > 0) {
+ Jim_DecrRefCount(interp, argv[j]);
+ }
+
+ if (argv != sargv) {
+ Jim_Free(argv);
+ argv = sargv;
+ }
+ }
+
+
+ if (retcode == JIM_ERR) {
+ JimSetErrorStack(interp, NULL);
+ }
+
+ JimPopEvalFrame(interp);
+
+ Jim_FreeIntRep(interp, scriptObjPtr);
+ scriptObjPtr->typePtr = &scriptObjType;
+ Jim_SetIntRepPtr(scriptObjPtr, script);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+
+ return retcode;
+}
+
+static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
+{
+ int retcode;
+
+ const char *varname = Jim_String(argNameObj);
+ if (*varname == '&') {
+
+ Jim_Obj *objPtr;
+ Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+ interp->framePtr = interp->framePtr->parent;
+ objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
+ interp->framePtr = savedCallFrame;
+ if (!objPtr) {
+ return JIM_ERR;
+ }
+
+
+ objPtr = Jim_NewStringObj(interp, varname + 1, -1);
+ Jim_IncrRefCount(objPtr);
+ retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+ else {
+ retcode = Jim_SetVariable(interp, argNameObj, argValObj);
+ }
+ return retcode;
+}
+
+static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
+{
+
+ Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
+ int i;
+
+ for (i = 0; i < cmd->u.proc.argListLen; i++) {
+ Jim_AppendString(interp, argmsg, " ", 1);
+
+ if (i == cmd->u.proc.argsPos) {
+ if (cmd->u.proc.arglist[i].defaultObjPtr) {
+
+ Jim_AppendString(interp, argmsg, "?", 1);
+ Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
+ Jim_AppendString(interp, argmsg, " ...?", -1);
+ }
+ else {
+
+ Jim_AppendString(interp, argmsg, "?arg ...?", -1);
+ }
+ }
+ else {
+ if (cmd->u.proc.arglist[i].defaultObjPtr) {
+ Jim_AppendString(interp, argmsg, "?", 1);
+ Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
+ Jim_AppendString(interp, argmsg, "?", 1);
+ }
+ else {
+ const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr);
+ if (*arg == '&') {
+ arg++;
+ }
+ Jim_AppendString(interp, argmsg, arg, -1);
+ }
+ }
+ }
+ Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
+}
+
+#ifdef jim_ext_namespace
+int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)
+{
+ Jim_CallFrame *callFramePtr;
+ int retcode;
+
+
+ callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
+ callFramePtr->argv = interp->evalFrame->argv;
+ callFramePtr->argc = interp->evalFrame->argc;
+ callFramePtr->procArgsObjPtr = NULL;
+ callFramePtr->procBodyObjPtr = scriptObj;
+ callFramePtr->staticVars = NULL;
+ Jim_IncrRefCount(scriptObj);
+ interp->framePtr = callFramePtr;
+
+
+ if (interp->framePtr->level == interp->maxCallFrameDepth) {
+ Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
+ retcode = JIM_ERR;
+ }
+ else {
+
+ retcode = Jim_EvalObj(interp, scriptObj);
+ }
+
+
+ interp->framePtr = interp->framePtr->parent;
+ JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
+
+ return retcode;
+}
+#endif
+
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv)
+{
+ Jim_CallFrame *callFramePtr;
+ int i, d, retcode, optargs;
+
+
+ if (argc - 1 < cmd->u.proc.reqArity ||
+ (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
+ JimSetProcWrongArgs(interp, argv[0], cmd);
+ return JIM_ERR;
+ }
+
+ if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) {
+
+ return JIM_OK;
+ }
+
+
+ if (interp->framePtr->level == interp->maxCallFrameDepth) {
+ Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
+ return JIM_ERR;
+ }
+
+
+ callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj);
+ callFramePtr->argv = argv;
+ callFramePtr->argc = argc;
+ callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
+ callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
+ callFramePtr->staticVars = cmd->u.proc.staticVars;
+
+ interp->procLevel++;
+
+ Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
+ Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
+ interp->framePtr = callFramePtr;
+
+
+ optargs = (argc - 1 - cmd->u.proc.reqArity);
+
+
+ i = 1;
+ for (d = 0; d < cmd->u.proc.argListLen; d++) {
+ Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
+ if (d == cmd->u.proc.argsPos) {
+
+ Jim_Obj *listObjPtr;
+ int argsLen = 0;
+ if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
+ argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
+ }
+ listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
+
+
+ if (cmd->u.proc.arglist[d].defaultObjPtr) {
+ nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
+ }
+ retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
+ if (retcode != JIM_OK) {
+ goto badargset;
+ }
+
+ i += argsLen;
+ continue;
+ }
+
+
+ if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
+ retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
+ }
+ else {
+
+ retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
+ }
+ if (retcode != JIM_OK) {
+ goto badargset;
+ }
+ }
+
+ if (interp->traceCmdObj == NULL ||
+ (retcode = JimTraceCallback(interp, "proc", argc, argv)) == JIM_OK) {
+
+ retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
+ }
+
+badargset:
+
+
+ retcode = JimInvokeDefer(interp, retcode);
+ interp->framePtr = interp->framePtr->parent;
+ JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
+
+
+ if (retcode == JIM_RETURN) {
+ if (--interp->returnLevel <= 0) {
+ retcode = interp->returnCode;
+ interp->returnCode = JIM_OK;
+ interp->returnLevel = 0;
+ }
+ }
+ interp->procLevel--;
+
+ return retcode;
+}
+
+int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
+{
+ int retval;
+ Jim_Obj *scriptObjPtr;
+
+ scriptObjPtr = Jim_NewStringObj(interp, script, -1);
+ Jim_IncrRefCount(scriptObjPtr);
+ if (filename) {
+ Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
+ }
+ retval = Jim_EvalObj(interp, scriptObjPtr);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ return retval;
+}
+
+int Jim_Eval(Jim_Interp *interp, const char *script)
+{
+ return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1));
+}
+
+
+int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
+{
+ int retval;
+ Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+ interp->framePtr = interp->topFramePtr;
+ retval = Jim_Eval(interp, script);
+ interp->framePtr = savedFramePtr;
+
+ return retval;
+}
+
+int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename)
+{
+ int retval;
+ Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+ interp->framePtr = interp->topFramePtr;
+ retval = Jim_EvalFile(interp, filename);
+ interp->framePtr = savedFramePtr;
+
+ return retval;
+}
+
+#include <sys/stat.h>
+
+static Jim_Obj *JimReadTextFile(Jim_Interp *interp, const char *filename)
+{
+ jim_stat_t sb;
+ int fd;
+ char *buf;
+ int readlen;
+
+ if (Jim_Stat(filename, &sb) == -1 || (fd = open(filename, O_RDONLY | O_TEXT, 0666)) < 0) {
+ Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
+ return NULL;
+ }
+ buf = Jim_Alloc(sb.st_size + 1);
+ readlen = read(fd, buf, sb.st_size);
+ close(fd);
+ if (readlen < 0) {
+ Jim_Free(buf);
+ Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
+ return NULL;
+ }
+ else {
+ Jim_Obj *objPtr;
+ buf[readlen] = 0;
+
+ objPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
+
+ return objPtr;
+ }
+}
+
+
+int Jim_EvalFile(Jim_Interp *interp, const char *filename)
+{
+ Jim_Obj *filenameObj;
+ Jim_Obj *oldFilenameObj;
+ Jim_Obj *scriptObjPtr;
+ int retcode;
+
+ scriptObjPtr = JimReadTextFile(interp, filename);
+ if (!scriptObjPtr) {
+ return JIM_ERR;
+ }
+
+ filenameObj = Jim_NewStringObj(interp, filename, -1);
+ Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
+
+ oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
+
+ retcode = Jim_EvalObj(interp, scriptObjPtr);
+
+ JimPopInterpObj(interp, interp->currentFilenameObj, oldFilenameObj);
+
+
+ if (retcode == JIM_RETURN) {
+ if (--interp->returnLevel <= 0) {
+ retcode = interp->returnCode;
+ interp->returnCode = JIM_OK;
+ interp->returnLevel = 0;
+ }
+ }
+
+ return retcode;
+}
+
+static void JimParseSubst(struct JimParserCtx *pc, int flags)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+
+ if (pc->len == 0) {
+ pc->tend = pc->p;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return;
+ }
+ if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
+ JimParseCmd(pc);
+ return;
+ }
+ if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
+ if (JimParseVar(pc) == JIM_OK) {
+ return;
+ }
+
+ pc->tstart = pc->p;
+
+ pc->p++;
+ pc->len--;
+ }
+ while (pc->len) {
+ if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
+ break;
+ }
+ if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
+ break;
+ }
+ if (*pc->p == '\\' && pc->len > 1) {
+ pc->p++;
+ pc->len--;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC;
+}
+
+
+static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
+{
+ int scriptTextLen;
+ const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+ struct JimParserCtx parser;
+ struct ScriptObj *script = Jim_Alloc(sizeof(*script));
+ ParseTokenList tokenlist;
+
+
+ ScriptTokenListInit(&tokenlist);
+
+ JimParserInit(&parser, scriptText, scriptTextLen, 1);
+ while (1) {
+ JimParseSubst(&parser, flags);
+ if (parser.eof) {
+
+ break;
+ }
+ ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+ parser.tline);
+ }
+
+
+ script->inUse = 1;
+ script->substFlags = flags;
+ script->fileNameObj = interp->emptyObj;
+ Jim_IncrRefCount(script->fileNameObj);
+ SubstObjAddTokens(interp, script, &tokenlist);
+
+
+ ScriptTokenListFree(&tokenlist);
+
+#ifdef DEBUG_SHOW_SUBST
+ {
+ int i;
+
+ printf("==== Subst ====\n");
+ for (i = 0; i < script->len; i++) {
+ printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type),
+ Jim_String(script->token[i].objPtr));
+ }
+ }
+#endif
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_SetIntRepPtr(objPtr, script);
+ objPtr->typePtr = &scriptObjType;
+ return JIM_OK;
+}
+
+static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags)
+ SetSubstFromAny(interp, objPtr, flags);
+ return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
+}
+
+int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
+{
+ ScriptObj *script;
+
+ JimPanic((substObjPtr->refCount == 0, "Jim_SubstObj() called with zero refcount object"));
+
+ script = Jim_GetSubst(interp, substObjPtr, flags);
+
+ Jim_IncrRefCount(substObjPtr);
+ script->inUse++;
+
+ *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
+
+ script->inUse--;
+ Jim_DecrRefCount(interp, substObjPtr);
+ if (*resObjPtrPtr == NULL) {
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
+{
+ Jim_Obj *objPtr;
+ Jim_Obj *listObjPtr;
+
+ JimPanic((argc == 0, "Jim_WrongNumArgs() called with argc=0"));
+
+ listObjPtr = Jim_NewListObj(interp, argv, argc);
+
+ if (msg && *msg) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1));
+ }
+ Jim_IncrRefCount(listObjPtr);
+ objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1);
+ Jim_DecrRefCount(interp, listObjPtr);
+
+ Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
+}
+
+typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
+ Jim_Obj *keyObjPtr, void *value, Jim_Obj *patternObjPtr, int type);
+
+#define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
+
+static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
+ JimHashtableIteratorCallbackType *callback, int type)
+{
+ Jim_HashEntry *he;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+
+ if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
+ he = Jim_FindHashEntry(ht, patternObjPtr);
+ if (he) {
+ callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
+ patternObjPtr, type);
+ }
+ }
+ else {
+ Jim_HashTableIterator htiter;
+ JimInitHashTableIterator(ht, &htiter);
+ while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
+ callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
+ patternObjPtr, type);
+ }
+ }
+ return listObjPtr;
+}
+
+
+#define JIM_CMDLIST_COMMANDS 0
+#define JIM_CMDLIST_PROCS 1
+#define JIM_CMDLIST_CHANNELS 2
+
+static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
+ Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
+{
+ Jim_Cmd *cmdPtr = (Jim_Cmd *)value;
+
+ if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
+
+ return;
+ }
+
+ Jim_IncrRefCount(keyObj);
+
+ if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, keyObj) >= 0) {
+ int match = 1;
+ if (patternObj) {
+ int plen, slen;
+ const char *pattern = Jim_GetStringNoQualifier(patternObj, &plen);
+ const char *str = Jim_GetStringNoQualifier(keyObj, &slen);
+#ifdef JIM_NO_INTROSPECTION
+
+ match = (JimStringCompareUtf8(pattern, plen, str, slen, 0) == 0);
+#else
+ match = JimGlobMatch(pattern, plen, str, slen, 0);
+#endif
+ }
+ if (match) {
+ Jim_ListAppendElement(interp, listObjPtr, keyObj);
+ }
+ }
+ Jim_DecrRefCount(interp, keyObj);
+}
+
+static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
+{
+ return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type);
+}
+
+
+#define JIM_VARLIST_GLOBALS 0
+#define JIM_VARLIST_LOCALS 1
+#define JIM_VARLIST_VARS 2
+#define JIM_VARLIST_MASK 0x000f
+
+#define JIM_VARLIST_VALUES 0x1000
+
+static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
+ Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
+{
+ Jim_VarVal *vv = (Jim_VarVal *)value;
+
+ if ((type & JIM_VARLIST_MASK) != JIM_VARLIST_LOCALS || vv->linkFramePtr == NULL) {
+ if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, keyObj, 0)) {
+ Jim_ListAppendElement(interp, listObjPtr, keyObj);
+ if (type & JIM_VARLIST_VALUES) {
+ Jim_ListAppendElement(interp, listObjPtr, vv->objPtr);
+ }
+ }
+ }
+}
+
+
+static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode)
+{
+ if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) {
+ return interp->emptyObj;
+ }
+ else {
+ Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr;
+ return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch,
+ mode);
+ }
+}
+
+static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
+{
+ long level;
+
+ if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
+ Jim_CallFrame *targetCallFrame = JimGetCallFrameByInteger(interp, level);
+ if (targetCallFrame && targetCallFrame != interp->topFramePtr) {
+#ifdef JIM_NO_INTROSPECTION
+
+ *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, 1);
+#else
+ *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
+#endif
+ return JIM_OK;
+ }
+ }
+ Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+ return JIM_ERR;
+}
+
+static int JimInfoFrame(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
+{
+ long level;
+
+ if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, level);
+ if (frame) {
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "source", -1));
+ if (frame->scriptObj) {
+ ScriptObj *script = JimGetScript(interp, frame->scriptObj);
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "line", -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, script->linenr));
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "file", -1));
+ Jim_ListAppendElement(interp, listObj, script->fileNameObj);
+ }
+#ifndef JIM_NO_INTROSPECTION
+ {
+ Jim_Obj *cmdObj = Jim_NewListObj(interp, frame->argv, frame->argc);
+
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "cmd", -1));
+ Jim_ListAppendElement(interp, listObj, cmdObj);
+ }
+#endif
+ {
+ Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
+ if (procNameObj) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1));
+ Jim_ListAppendElement(interp, listObj, procNameObj);
+ }
+ }
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "level", -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - frame->framePtr->level));
+
+ *objPtrPtr = listObj;
+ return JIM_OK;
+ }
+ }
+ Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+ return JIM_ERR;
+}
+
+
+static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) {
+ Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1);
+ return JIM_ERR;
+ }
+ else {
+ fputs(Jim_String(argv[2]), stdout);
+ }
+ }
+ else {
+ puts(Jim_String(argv[1]));
+ }
+ return JIM_OK;
+}
+
+
+static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+ jim_wide wideValue, res;
+ double doubleValue, doubleRes;
+ int i;
+
+ res = (op == JIM_EXPROP_ADD) ? 0 : 1;
+
+ for (i = 1; i < argc; i++) {
+ if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
+ goto trydouble;
+ if (op == JIM_EXPROP_ADD)
+ res += wideValue;
+ else
+ res *= wideValue;
+ }
+ Jim_SetResultInt(interp, res);
+ return JIM_OK;
+ trydouble:
+ doubleRes = (double)res;
+ for (; i < argc; i++) {
+ if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+ return JIM_ERR;
+ if (op == JIM_EXPROP_ADD)
+ doubleRes += doubleValue;
+ else
+ doubleRes *= doubleValue;
+ }
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ return JIM_OK;
+}
+
+
+static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+ jim_wide wideValue, res = 0;
+ double doubleValue, doubleRes = 0;
+ int i = 2;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
+ return JIM_ERR;
+ }
+ else if (argc == 2) {
+ if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
+ if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) {
+ return JIM_ERR;
+ }
+ else {
+ if (op == JIM_EXPROP_SUB)
+ doubleRes = -doubleValue;
+ else
+ doubleRes = 1.0 / doubleValue;
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ return JIM_OK;
+ }
+ }
+ if (op == JIM_EXPROP_SUB) {
+ res = -wideValue;
+ Jim_SetResultInt(interp, res);
+ }
+ else {
+ doubleRes = 1.0 / wideValue;
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ }
+ return JIM_OK;
+ }
+ else {
+ if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
+ if (Jim_GetDouble(interp, argv[1], &doubleRes)
+ != JIM_OK) {
+ return JIM_ERR;
+ }
+ else {
+ goto trydouble;
+ }
+ }
+ }
+ for (i = 2; i < argc; i++) {
+ if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
+ doubleRes = (double)res;
+ goto trydouble;
+ }
+ if (op == JIM_EXPROP_SUB)
+ res -= wideValue;
+ else {
+ if (wideValue == 0) {
+ Jim_SetResultString(interp, "Division by zero", -1);
+ return JIM_ERR;
+ }
+ res /= wideValue;
+ }
+ }
+ Jim_SetResultInt(interp, res);
+ return JIM_OK;
+ trydouble:
+ for (; i < argc; i++) {
+ if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+ return JIM_ERR;
+ if (op == JIM_EXPROP_SUB)
+ doubleRes -= doubleValue;
+ else
+ doubleRes /= doubleValue;
+ }
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ return JIM_OK;
+}
+
+
+
+static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
+}
+
+
+static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
+}
+
+
+static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
+}
+
+
+static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
+}
+
+
+static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+ if (!objPtr)
+ return JIM_ERR;
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+ return JIM_ERR;
+ Jim_SetResult(interp, argv[2]);
+ return JIM_OK;
+}
+
+static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i = 1;
+ int complain = 1;
+
+ while (i < argc) {
+ if (Jim_CompareStringImmediate(interp, argv[i], "--")) {
+ i++;
+ break;
+ }
+ if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) {
+ complain = 0;
+ i++;
+ continue;
+ }
+ break;
+ }
+
+ while (i < argc) {
+ if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK
+ && complain) {
+ return JIM_ERR;
+ }
+ i++;
+ }
+
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+}
+
+static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
+{
+ if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
+ if (--interp->break_level > 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "condition body");
+ return JIM_ERR;
+ }
+
+
+ while (1) {
+ int boolean = 0, retval;
+
+ if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
+ return retval;
+ if (!boolean)
+ break;
+
+ if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
+ if (JimCheckLoopRetcode(interp, retval)) {
+ return retval;
+ }
+ switch (retval) {
+ case JIM_BREAK:
+ goto out;
+ case JIM_CONTINUE:
+ continue;
+ default:
+ return retval;
+ }
+ }
+ }
+ out:
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+}
+
+
+static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retval;
+ int boolean = 1;
+ int immediate = 0;
+ Jim_Obj *varNamePtr = NULL;
+ Jim_Obj *stopVarNamePtr = NULL;
+
+ if (argc != 5) {
+ Jim_WrongNumArgs(interp, 1, argv, "start test next body");
+ return JIM_ERR;
+ }
+
+
+ if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
+ return retval;
+ }
+
+ retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+
+
+#ifdef JIM_OPTIMIZATION
+ if (retval == JIM_OK && boolean) {
+ ScriptObj *incrScript;
+ struct ExprTree *expr;
+ jim_wide stop, currentVal;
+ Jim_Obj *objPtr;
+ int cmpOffset;
+
+
+ expr = JimGetExpression(interp, argv[2]);
+ incrScript = JimGetScript(interp, argv[3]);
+
+
+ if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) {
+ goto evalstart;
+ }
+
+ if (incrScript->token[1].type != JIM_TT_ESC) {
+ goto evalstart;
+ }
+
+ if (expr->expr->type == JIM_EXPROP_LT) {
+ cmpOffset = 0;
+ }
+ else if (expr->expr->type == JIM_EXPROP_LTE) {
+ cmpOffset = 1;
+ }
+ else {
+ goto evalstart;
+ }
+
+ if (expr->expr->left->type != JIM_TT_VAR) {
+ goto evalstart;
+ }
+
+ if (expr->expr->right->type != JIM_TT_VAR && expr->expr->right->type != JIM_TT_EXPR_INT) {
+ goto evalstart;
+ }
+
+
+ if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
+ goto evalstart;
+ }
+
+
+ if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->expr->left->objPtr)) {
+ goto evalstart;
+ }
+
+
+ if (expr->expr->right->type == JIM_TT_EXPR_INT) {
+ if (Jim_GetWideExpr(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) {
+ goto evalstart;
+ }
+ }
+ else {
+ stopVarNamePtr = expr->expr->right->objPtr;
+ Jim_IncrRefCount(stopVarNamePtr);
+
+ stop = 0;
+ }
+
+
+ varNamePtr = expr->expr->left->objPtr;
+ Jim_IncrRefCount(varNamePtr);
+
+ objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
+ if (objPtr == NULL || Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK) {
+ goto testcond;
+ }
+
+
+ while (retval == JIM_OK) {
+
+
+
+
+ if (stopVarNamePtr) {
+ objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
+ if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
+ goto testcond;
+ }
+ }
+
+ if (currentVal >= stop + cmpOffset) {
+ break;
+ }
+
+
+ retval = Jim_EvalObj(interp, argv[4]);
+ if (JimCheckLoopRetcode(interp, retval)) {
+ immediate++;
+ goto out;
+ }
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+ retval = JIM_OK;
+
+ objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
+
+
+ if (objPtr == NULL) {
+ retval = JIM_ERR;
+ goto out;
+ }
+ if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+ currentVal = ++JimWideValue(objPtr);
+ Jim_InvalidateStringRep(objPtr);
+ }
+ else {
+ if (Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK ||
+ Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp,
+ ++currentVal)) != JIM_OK) {
+ goto evalnext;
+ }
+ }
+ }
+ }
+ goto out;
+ }
+ evalstart:
+#endif
+
+ while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
+
+ retval = Jim_EvalObj(interp, argv[4]);
+ if (JimCheckLoopRetcode(interp, retval)) {
+ immediate++;
+ break;
+ }
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+
+JIM_IF_OPTIM(evalnext:)
+ retval = Jim_EvalObj(interp, argv[3]);
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+
+JIM_IF_OPTIM(testcond:)
+ retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+ }
+ }
+ }
+JIM_IF_OPTIM(out:)
+ if (stopVarNamePtr) {
+ Jim_DecrRefCount(interp, stopVarNamePtr);
+ }
+ if (varNamePtr) {
+ Jim_DecrRefCount(interp, varNamePtr);
+ }
+
+ if (!immediate) {
+ if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+ }
+ }
+
+ return retval;
+}
+
+
+static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retval;
+ jim_wide i;
+ jim_wide limit = 0;
+ jim_wide incr = 1;
+ Jim_Obj *bodyObjPtr;
+
+ if (argc < 4 || argc > 6) {
+ Jim_WrongNumArgs(interp, 1, argv, "var ?first? limit ?incr? body");
+ return JIM_ERR;
+ }
+
+ retval = Jim_GetWideExpr(interp, argv[2], &i);
+ if (argc > 4 && retval == JIM_OK) {
+ retval = Jim_GetWideExpr(interp, argv[3], &limit);
+ }
+ if (argc > 5 && retval == JIM_OK) {
+ Jim_GetWideExpr(interp, argv[4], &incr);
+ }
+ if (retval != JIM_OK) {
+ return retval;
+ }
+ if (argc == 4) {
+ limit = i;
+ i = 0;
+ }
+ bodyObjPtr = argv[argc - 1];
+
+ retval = Jim_SetVariable(interp, argv[1], Jim_NewIntObj(interp, i));
+
+ while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) {
+ retval = Jim_EvalObj(interp, bodyObjPtr);
+ if (JimCheckLoopRetcode(interp, retval)) {
+ return retval;
+ }
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+
+ retval = JIM_OK;
+
+
+ i += incr;
+
+ if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+ if (argv[1]->typePtr != &variableObjType) {
+ if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ JimWideValue(objPtr) = i;
+ Jim_InvalidateStringRep(objPtr);
+
+ if (argv[1]->typePtr != &variableObjType) {
+ if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+ retval = JIM_ERR;
+ break;
+ }
+ }
+ }
+ else {
+ objPtr = Jim_NewIntObj(interp, i);
+ retval = Jim_SetVariable(interp, argv[1], objPtr);
+ if (retval != JIM_OK) {
+ Jim_FreeNewObj(interp, objPtr);
+ }
+ }
+ }
+ }
+
+ if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) {
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+ }
+ return retval;
+}
+
+typedef struct {
+ Jim_Obj *objPtr;
+ int idx;
+} Jim_ListIter;
+
+static void JimListIterInit(Jim_ListIter *iter, Jim_Obj *objPtr)
+{
+ iter->objPtr = objPtr;
+ iter->idx = 0;
+}
+
+static Jim_Obj *JimListIterNext(Jim_Interp *interp, Jim_ListIter *iter)
+{
+ if (iter->idx >= Jim_ListLength(interp, iter->objPtr)) {
+ return NULL;
+ }
+ return iter->objPtr->internalRep.listValue.ele[iter->idx++];
+}
+
+static int JimListIterDone(Jim_Interp *interp, Jim_ListIter *iter)
+{
+ return iter->idx >= Jim_ListLength(interp, iter->objPtr);
+}
+
+
+static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
+{
+ int result = JIM_OK;
+ int i, numargs;
+ Jim_ListIter twoiters[2];
+ Jim_ListIter *iters;
+ Jim_Obj *script;
+ Jim_Obj *resultObj;
+
+ if (argc < 4 || argc % 2 != 0) {
+ Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
+ return JIM_ERR;
+ }
+ script = argv[argc - 1];
+ numargs = (argc - 1 - 1);
+
+ if (numargs == 2) {
+ iters = twoiters;
+ }
+ else {
+ iters = Jim_Alloc(numargs * sizeof(*iters));
+ }
+ for (i = 0; i < numargs; i++) {
+ JimListIterInit(&iters[i], argv[i + 1]);
+ if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) {
+ result = JIM_ERR;
+ }
+ }
+ if (result != JIM_OK) {
+ Jim_SetResultString(interp, "foreach varlist is empty", -1);
+ goto empty_varlist;
+ }
+
+ if (doMap) {
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ }
+ else {
+ resultObj = interp->emptyObj;
+ }
+ Jim_IncrRefCount(resultObj);
+
+ while (1) {
+
+ for (i = 0; i < numargs; i += 2) {
+ if (!JimListIterDone(interp, &iters[i + 1])) {
+ break;
+ }
+ }
+ if (i == numargs) {
+
+ break;
+ }
+
+
+ for (i = 0; i < numargs; i += 2) {
+ Jim_Obj *varName;
+
+
+ JimListIterInit(&iters[i], argv[i + 1]);
+ while ((varName = JimListIterNext(interp, &iters[i])) != NULL) {
+ Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]);
+ if (!valObj) {
+
+ valObj = interp->emptyObj;
+ }
+
+ Jim_IncrRefCount(valObj);
+ result = Jim_SetVariable(interp, varName, valObj);
+ Jim_DecrRefCount(interp, valObj);
+ if (result != JIM_OK) {
+ goto err;
+ }
+ }
+ }
+ result = Jim_EvalObj(interp, script);
+ if (JimCheckLoopRetcode(interp, result)) {
+ goto err;
+ }
+ switch (result) {
+ case JIM_OK:
+ if (doMap) {
+ Jim_ListAppendElement(interp, resultObj, interp->result);
+ }
+ break;
+ case JIM_CONTINUE:
+ break;
+ case JIM_BREAK:
+ goto out;
+ default:
+ goto err;
+ }
+ }
+ out:
+ result = JIM_OK;
+ Jim_SetResult(interp, resultObj);
+ err:
+ Jim_DecrRefCount(interp, resultObj);
+ empty_varlist:
+ if (numargs > 2) {
+ Jim_Free(iters);
+ }
+ return result;
+}
+
+
+static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimForeachMapHelper(interp, argc, argv, 0);
+}
+
+
+static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimForeachMapHelper(interp, argc, argv, 1);
+}
+
+
+static int Jim_LassignCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int result = JIM_ERR;
+ int i;
+ Jim_ListIter iter;
+ Jim_Obj *resultObj;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varList list ?varName ...?");
+ return JIM_ERR;
+ }
+
+ JimListIterInit(&iter, argv[1]);
+
+ for (i = 2; i < argc; i++) {
+ Jim_Obj *valObj = JimListIterNext(interp, &iter);
+ result = Jim_SetVariable(interp, argv[i], valObj ? valObj : interp->emptyObj);
+ if (result != JIM_OK) {
+ return result;
+ }
+ }
+
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ while (!JimListIterDone(interp, &iter)) {
+ Jim_ListAppendElement(interp, resultObj, JimListIterNext(interp, &iter));
+ }
+
+ Jim_SetResult(interp, resultObj);
+
+ return JIM_OK;
+}
+
+
+static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int boolean, retval, current = 1, falsebody = 0;
+
+ if (argc >= 3) {
+ while (1) {
+
+ if (current >= argc)
+ goto err;
+ if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
+ != JIM_OK)
+ return retval;
+
+ if (current >= argc)
+ goto err;
+ if (Jim_CompareStringImmediate(interp, argv[current], "then"))
+ current++;
+
+ if (current >= argc)
+ goto err;
+ if (boolean)
+ return Jim_EvalObj(interp, argv[current]);
+
+ if (++current >= argc) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ return JIM_OK;
+ }
+ falsebody = current++;
+ if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
+
+ if (current != argc - 1)
+ goto err;
+ return Jim_EvalObj(interp, argv[current]);
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
+ continue;
+
+ else if (falsebody != argc - 1)
+ goto err;
+ return Jim_EvalObj(interp, argv[falsebody]);
+ }
+ return JIM_OK;
+ }
+ err:
+ Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
+ return JIM_ERR;
+}
+
+
+int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
+ Jim_Obj *stringObj, int flags)
+{
+ Jim_Obj *parms[5];
+ int argc = 0;
+ long eq;
+ int rc;
+
+ parms[argc++] = commandObj;
+ if (flags & JIM_NOCASE) {
+ parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1);
+ }
+ if (flags & JIM_OPT_END) {
+ parms[argc++] = Jim_NewStringObj(interp, "--", -1);
+ }
+ parms[argc++] = patternObj;
+ parms[argc++] = stringObj;
+
+ rc = Jim_EvalObjVector(interp, argc, parms);
+
+ if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) {
+ eq = -rc;
+ }
+
+ return eq;
+}
+
+
+static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
+ int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
+ int match_flags = 0;
+ Jim_Obj *command = NULL, *scriptObj = NULL, *strObj;
+ Jim_Obj **caseList;
+
+ if (argc < 3) {
+ wrongnumargs:
+ Jim_WrongNumArgs(interp, 1, argv, "?options? string "
+ "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
+ return JIM_ERR;
+ }
+ for (opt = 1; opt < argc; ++opt) {
+ const char *option = Jim_String(argv[opt]);
+
+ if (*option != '-')
+ break;
+ else if (strncmp(option, "--", 2) == 0) {
+ ++opt;
+ break;
+ }
+ else if (strncmp(option, "-exact", 2) == 0)
+ matchOpt = SWITCH_EXACT;
+ else if (strncmp(option, "-glob", 2) == 0)
+ matchOpt = SWITCH_GLOB;
+ else if (strncmp(option, "-regexp", 2) == 0) {
+ matchOpt = SWITCH_RE;
+ match_flags |= JIM_OPT_END;
+ }
+ else if (strncmp(option, "-command", 2) == 0) {
+ matchOpt = SWITCH_CMD;
+ if ((argc - opt) < 2)
+ goto wrongnumargs;
+ command = argv[++opt];
+ }
+ else {
+ Jim_SetResultFormatted(interp,
+ "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
+ argv[opt]);
+ return JIM_ERR;
+ }
+ if ((argc - opt) < 2)
+ goto wrongnumargs;
+ }
+ strObj = argv[opt++];
+ patCount = argc - opt;
+ if (patCount == 1) {
+ JimListGetElements(interp, argv[opt], &patCount, &caseList);
+ }
+ else
+ caseList = (Jim_Obj **)&argv[opt];
+ if (patCount == 0 || patCount % 2 != 0)
+ goto wrongnumargs;
+ for (i = 0; scriptObj == NULL && i < patCount; i += 2) {
+ Jim_Obj *patObj = caseList[i];
+
+ if (!Jim_CompareStringImmediate(interp, patObj, "default")
+ || i < (patCount - 2)) {
+ switch (matchOpt) {
+ case SWITCH_EXACT:
+ if (Jim_StringEqObj(strObj, patObj))
+ scriptObj = caseList[i + 1];
+ break;
+ case SWITCH_GLOB:
+ if (Jim_StringMatchObj(interp, patObj, strObj, 0))
+ scriptObj = caseList[i + 1];
+ break;
+ case SWITCH_RE:
+ command = Jim_NewStringObj(interp, "regexp", -1);
+
+ case SWITCH_CMD:{
+ int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, match_flags);
+
+ if (argc - opt == 1) {
+ JimListGetElements(interp, argv[opt], &patCount, &caseList);
+ }
+
+ if (rc < 0) {
+ return -rc;
+ }
+ if (rc)
+ scriptObj = caseList[i + 1];
+ break;
+ }
+ }
+ }
+ else {
+ scriptObj = caseList[i + 1];
+ }
+ }
+ for (; i < patCount && Jim_CompareStringImmediate(interp, scriptObj, "-"); i += 2)
+ scriptObj = caseList[i + 1];
+ if (scriptObj && Jim_CompareStringImmediate(interp, scriptObj, "-")) {
+ Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
+ return JIM_ERR;
+ }
+ Jim_SetEmptyResult(interp);
+ if (scriptObj) {
+ return Jim_EvalObj(interp, scriptObj);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObjPtr;
+
+ listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int ret;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "list ?index ...?");
+ return JIM_ERR;
+ }
+ ret = Jim_ListIndices(interp, argv[1], argv + 2, argc - 2, &objPtr, JIM_NONE);
+ if (ret < 0) {
+ ret = JIM_OK;
+ Jim_SetEmptyResult(interp);
+ }
+ else if (ret == JIM_OK) {
+ Jim_SetResult(interp, objPtr);
+ }
+ return ret;
+}
+
+
+static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "list");
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1]));
+ return JIM_OK;
+}
+
+
+static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ static const char * const options[] = {
+ "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
+ "-stride", "-index", NULL
+ };
+ enum
+ { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE,
+ OPT_COMMAND, OPT_STRIDE, OPT_INDEX };
+ int i;
+ int opt_bool = 0;
+ int opt_not = 0;
+ int opt_all = 0;
+ int opt_inline = 0;
+ int opt_match = OPT_EXACT;
+ int listlen;
+ int rc = JIM_OK;
+ Jim_Obj *listObjPtr = NULL;
+ Jim_Obj *commandObj = NULL;
+ Jim_Obj *indexObj = NULL;
+ int match_flags = 0;
+ long stride = 1;
+
+ if (argc < 3) {
+ wrongargs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? ?-stride len? ?-index val? list value");
+ return JIM_ERR;
+ }
+
+ for (i = 1; i < argc - 2; i++) {
+ int option;
+
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_BOOL:
+ opt_bool = 1;
+ opt_inline = 0;
+ break;
+ case OPT_NOT:
+ opt_not = 1;
+ break;
+ case OPT_NOCASE:
+ match_flags |= JIM_NOCASE;
+ break;
+ case OPT_INLINE:
+ opt_inline = 1;
+ opt_bool = 0;
+ break;
+ case OPT_ALL:
+ opt_all = 1;
+ break;
+ case OPT_REGEXP:
+ opt_match = option;
+ match_flags |= JIM_OPT_END;
+ break;
+ case OPT_COMMAND:
+ if (i >= argc - 2) {
+ goto wrongargs;
+ }
+ commandObj = argv[++i];
+
+ case OPT_EXACT:
+ case OPT_GLOB:
+ opt_match = option;
+ break;
+ case OPT_INDEX:
+ if (i >= argc - 2) {
+ goto wrongargs;
+ }
+ indexObj = argv[++i];
+ break;
+ case OPT_STRIDE:
+ if (i >= argc - 2) {
+ goto wrongargs;
+ }
+ if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (stride < 1) {
+ Jim_SetResultString(interp, "stride length must be at least 1", -1);
+ return JIM_ERR;
+ }
+ break;
+ }
+ }
+
+ argc -= i;
+ if (argc < 2) {
+ goto wrongargs;
+ }
+ argv += i;
+
+ listlen = Jim_ListLength(interp, argv[0]);
+ if (listlen % stride) {
+ Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
+ return JIM_ERR;
+ }
+
+ if (opt_all) {
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
+ }
+ if (opt_match == OPT_REGEXP) {
+ commandObj = Jim_NewStringObj(interp, "regexp", -1);
+ }
+ if (commandObj) {
+ Jim_IncrRefCount(commandObj);
+ }
+
+ for (i = 0; i < listlen; i += stride) {
+ int eq = 0;
+ Jim_Obj *searchListObj;
+ Jim_Obj *objPtr;
+ int offset;
+
+ if (indexObj) {
+ int indexlen = Jim_ListLength(interp, indexObj);
+ if (stride == 1) {
+ searchListObj = Jim_ListGetIndex(interp, argv[0], i);
+ }
+ else {
+ searchListObj = Jim_NewListObj(interp, argv[0]->internalRep.listValue.ele + i, stride);
+ }
+ Jim_IncrRefCount(searchListObj);
+ rc = Jim_ListIndices(interp, searchListObj, indexObj->internalRep.listValue.ele, indexlen, &objPtr, JIM_ERRMSG);
+ if (rc != JIM_OK) {
+ Jim_DecrRefCount(interp, searchListObj);
+ rc = JIM_ERR;
+ goto done;
+ }
+
+ offset = 0;
+ }
+ else {
+
+ searchListObj = argv[0];
+ offset = i;
+ objPtr = Jim_ListGetIndex(interp, searchListObj, i);
+ Jim_IncrRefCount(searchListObj);
+ }
+
+ switch (opt_match) {
+ case OPT_EXACT:
+ eq = Jim_StringCompareObj(interp, argv[1], objPtr, match_flags) == 0;
+ break;
+
+ case OPT_GLOB:
+ eq = Jim_StringMatchObj(interp, argv[1], objPtr, match_flags);
+ break;
+
+ case OPT_REGEXP:
+ case OPT_COMMAND:
+ eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, match_flags);
+ if (eq < 0) {
+ Jim_DecrRefCount(interp, searchListObj);
+ rc = JIM_ERR;
+ goto done;
+ }
+ break;
+ }
+
+
+ if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
+ Jim_Obj *resultObj;
+
+ if (opt_bool) {
+ resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
+ }
+ else if (!opt_inline) {
+ resultObj = Jim_NewIntObj(interp, i);
+ }
+ else if (stride == 1) {
+ resultObj = objPtr;
+ }
+ else if (opt_all) {
+
+ ListInsertElements(listObjPtr, -1, stride,
+ searchListObj->internalRep.listValue.ele + offset);
+
+ resultObj = NULL;
+ }
+ else {
+ resultObj = Jim_NewListObj(interp, searchListObj->internalRep.listValue.ele + offset, stride);
+ }
+
+ if (opt_all) {
+
+ if (stride == 1) {
+ Jim_ListAppendElement(interp, listObjPtr, resultObj);
+ }
+ }
+ else {
+ Jim_SetResult(interp, resultObj);
+ Jim_DecrRefCount(interp, searchListObj);
+ goto done;
+ }
+ }
+ Jim_DecrRefCount(interp, searchListObj);
+ }
+
+ if (opt_all) {
+ Jim_SetResult(interp, listObjPtr);
+ listObjPtr = NULL;
+ }
+ else {
+
+ if (opt_bool) {
+ Jim_SetResultBool(interp, opt_not);
+ }
+ else if (!opt_inline) {
+ Jim_SetResultInt(interp, -1);
+ }
+ }
+
+ done:
+ if (listObjPtr) {
+ Jim_FreeNewObj(interp, listObjPtr);
+ }
+ if (commandObj) {
+ Jim_DecrRefCount(interp, commandObj);
+ }
+ return rc;
+}
+
+
+static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObjPtr;
+ int new_obj = 0;
+ int i;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
+ return JIM_ERR;
+ }
+ listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+ if (!listObjPtr) {
+
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
+ new_obj = 1;
+ }
+ else if (Jim_IsShared(listObjPtr)) {
+ listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
+ new_obj = 1;
+ }
+ for (i = 2; i < argc; i++)
+ Jim_ListAppendElement(interp, listObjPtr, argv[i]);
+ if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
+ if (new_obj)
+ Jim_FreeNewObj(interp, listObjPtr);
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int idx, len;
+ Jim_Obj *listPtr;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "list index ?element ...?");
+ return JIM_ERR;
+ }
+ listPtr = argv[1];
+ if (Jim_IsShared(listPtr))
+ listPtr = Jim_DuplicateObj(interp, listPtr);
+ if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK)
+ goto err;
+ len = Jim_ListLength(interp, listPtr);
+ if (idx >= len)
+ idx = len;
+ else if (idx < 0)
+ idx = len + idx + 1;
+ Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]);
+ Jim_SetResult(interp, listPtr);
+ return JIM_OK;
+ err:
+ if (listPtr != argv[1]) {
+ Jim_FreeNewObj(interp, listPtr);
+ }
+ return JIM_ERR;
+}
+
+
+static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int first, last, len, rangeLen;
+ Jim_Obj *listObj;
+ Jim_Obj *newListObj;
+
+ if (argc < 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "list first last ?element ...?");
+ return JIM_ERR;
+ }
+ if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK ||
+ Jim_GetIndex(interp, argv[3], &last) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ listObj = argv[1];
+ len = Jim_ListLength(interp, listObj);
+
+ first = JimRelToAbsIndex(len, first);
+ last = JimRelToAbsIndex(len, last);
+ JimRelToAbsRange(len, &first, &last, &rangeLen);
+
+
+ if (first > len) {
+ first = len;
+ }
+
+
+ newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
+
+
+ ListInsertElements(newListObj, -1, argc - 4, argv + 4);
+
+
+ ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
+
+ Jim_SetResult(interp, newListObj);
+ return JIM_OK;
+}
+
+
+static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "listVar ?index ...? value");
+ return JIM_ERR;
+ }
+ else if (argc == 3) {
+
+ if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+ return JIM_ERR;
+ Jim_SetResult(interp, argv[2]);
+ return JIM_OK;
+ }
+ return Jim_ListSetIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]);
+}
+
+
+static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
+{
+ static const char * const options[] = {
+ "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
+ "-stride", "-dictionary", NULL
+ };
+ enum {
+ OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
+ OPT_STRIDE, OPT_DICT
+ };
+ Jim_Obj *resObj;
+ int i;
+ int retCode;
+ int shared;
+ long stride = 1;
+ Jim_Obj **elements;
+ int listlen;
+
+ struct lsort_info info;
+
+ if (argc < 2) {
+wrongargs:
+ Jim_WrongNumArgs(interp, 1, argv, "?options? list");
+ return JIM_ERR;
+ }
+
+ info.type = JIM_LSORT_ASCII;
+ info.order = 1;
+ info.indexc = 0;
+ info.unique = 0;
+ info.command = NULL;
+ info.interp = interp;
+
+ for (i = 1; i < (argc - 1); i++) {
+ int option;
+
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG)
+ != JIM_OK)
+ return JIM_ERR;
+ switch (option) {
+ case OPT_ASCII:
+ info.type = JIM_LSORT_ASCII;
+ break;
+ case OPT_DICT:
+ info.type = JIM_LSORT_DICT;
+ break;
+ case OPT_NOCASE:
+ info.type = JIM_LSORT_NOCASE;
+ break;
+ case OPT_INTEGER:
+ info.type = JIM_LSORT_INTEGER;
+ break;
+ case OPT_REAL:
+ info.type = JIM_LSORT_REAL;
+ break;
+ case OPT_INCREASING:
+ info.order = 1;
+ break;
+ case OPT_DECREASING:
+ info.order = -1;
+ break;
+ case OPT_UNIQUE:
+ info.unique = 1;
+ break;
+ case OPT_COMMAND:
+ if (i >= (argc - 2)) {
+ Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1);
+ return JIM_ERR;
+ }
+ info.type = JIM_LSORT_COMMAND;
+ info.command = argv[i + 1];
+ i++;
+ break;
+ case OPT_STRIDE:
+ if (i >= argc - 2) {
+ goto wrongargs;
+ }
+ if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (stride < 2) {
+ Jim_SetResultString(interp, "stride length must be at least 2", -1);
+ return JIM_ERR;
+ }
+ break;
+ case OPT_INDEX:
+ if (i >= (argc - 2)) {
+badindex:
+ Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1);
+ return JIM_ERR;
+ }
+ JimListGetElements(interp, argv[i + 1], &info.indexc, &info.indexv);
+ if (info.indexc == 0) {
+ goto badindex;
+ }
+ i++;
+ break;
+ }
+ }
+ resObj = argv[argc - 1];
+ JimListGetElements(interp, resObj, &listlen, &elements);
+ if (listlen <= 1) {
+
+ Jim_SetResult(interp, resObj);
+ return JIM_OK;
+ }
+
+ if (stride > 1) {
+ Jim_Obj *tmpListObj;
+ int i;
+
+ if (listlen % stride) {
+ Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
+ return JIM_ERR;
+ }
+
+ tmpListObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_IncrRefCount(tmpListObj);
+ for (i = 0; i < listlen; i += stride) {
+ Jim_ListAppendElement(interp, tmpListObj, Jim_NewListObj(interp, elements + i, stride));
+ }
+ retCode = ListSortElements(interp, tmpListObj, &info);
+ if (retCode == JIM_OK) {
+ resObj = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; i < listlen; i += stride) {
+ Jim_ListAppendList(interp, resObj, Jim_ListGetIndex(interp, tmpListObj, i / stride));
+ }
+ Jim_SetResult(interp, resObj);
+ }
+ Jim_DecrRefCount(interp, tmpListObj);
+ }
+ else {
+ if ((shared = Jim_IsShared(resObj))) {
+ resObj = Jim_DuplicateObj(interp, resObj);
+ }
+ retCode = ListSortElements(interp, resObj, &info);
+ if (retCode == JIM_OK) {
+ Jim_SetResult(interp, resObj);
+ }
+ else if (shared) {
+ Jim_FreeNewObj(interp, resObj);
+ }
+ }
+ return retCode;
+}
+
+
+static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *stringObjPtr;
+ int i;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?value ...?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+ if (!stringObjPtr)
+ return JIM_ERR;
+ }
+ else {
+ int new_obj = 0;
+ stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+ if (!stringObjPtr) {
+
+ stringObjPtr = Jim_NewEmptyStringObj(interp);
+ new_obj = 1;
+ }
+ else if (Jim_IsShared(stringObjPtr)) {
+ new_obj = 1;
+ stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
+ }
+ for (i = 2; i < argc; i++) {
+ Jim_AppendObj(interp, stringObjPtr, argv[i]);
+ }
+ if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
+ if (new_obj) {
+ Jim_FreeNewObj(interp, stringObjPtr);
+ }
+ return JIM_ERR;
+ }
+ }
+ Jim_SetResult(interp, stringObjPtr);
+ return JIM_OK;
+}
+
+
+
+
+
+static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int rc;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?");
+ return JIM_ERR;
+ }
+
+ if (argc == 2) {
+ rc = Jim_EvalObj(interp, argv[1]);
+ }
+ else {
+ rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+ }
+
+ return rc;
+}
+
+
+static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc >= 2) {
+ int retcode;
+ Jim_CallFrame *savedCallFrame, *targetCallFrame;
+ const char *str;
+
+
+ savedCallFrame = interp->framePtr;
+
+
+ str = Jim_String(argv[1]);
+ if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
+ argc--;
+ argv++;
+ }
+ else {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+ }
+ if (targetCallFrame == NULL) {
+ return JIM_ERR;
+ }
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?");
+ return JIM_ERR;
+ }
+
+ interp->framePtr = targetCallFrame;
+ if (argc == 2) {
+ retcode = Jim_EvalObj(interp, argv[1]);
+ }
+ else {
+ retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+ }
+ interp->framePtr = savedCallFrame;
+ return retcode;
+ }
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
+ return JIM_ERR;
+ }
+}
+
+
+static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retcode;
+
+ if (argc == 2) {
+ retcode = Jim_EvalExpression(interp, argv[1]);
+ }
+#ifndef JIM_COMPAT
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "expression");
+ retcode = JIM_ERR;
+ }
+#else
+ else if (argc > 2) {
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
+ Jim_IncrRefCount(objPtr);
+ retcode = Jim_EvalExpression(interp, objPtr);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
+ return JIM_ERR;
+ }
+#endif
+ return retcode;
+}
+
+static int JimBreakContinueHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int retcode)
+{
+ if (argc != 1 && argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?level?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ long level;
+ int ret = Jim_GetLong(interp, argv[1], &level);
+ if (ret != JIM_OK) {
+ return ret;
+ }
+ interp->break_level = level;
+ }
+ return retcode;
+}
+
+
+static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimBreakContinueHelper(interp, argc, argv, JIM_BREAK);
+}
+
+
+static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimBreakContinueHelper(interp, argc, argv, JIM_CONTINUE);
+}
+
+
+static int Jim_StacktraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObj;
+ int i;
+ jim_wide skip = 0;
+ jim_wide last = 0;
+
+ if (argc > 1) {
+ if (Jim_GetWideExpr(interp, argv[1], &skip) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ if (argc > 2) {
+ if (Jim_GetWideExpr(interp, argv[2], &last) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+
+ listObj = Jim_NewListObj(interp, NULL, 0);
+ for (i = skip; i <= interp->procLevel; i++) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
+ if (frame->procLevel < last) {
+ break;
+ }
+ JimAddStackFrame(interp, frame, listObj);
+ }
+ Jim_SetResult(interp, listObj);
+ return JIM_OK;
+}
+
+
+static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ Jim_Obj *stackTraceObj = NULL;
+ Jim_Obj *errorCodeObj = NULL;
+ int returnCode = JIM_OK;
+ long level = 1;
+
+ for (i = 1; i < argc - 1; i += 2) {
+ if (Jim_CompareStringImmediate(interp, argv[i], "-code")) {
+ if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) {
+ return JIM_ERR;
+ }
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) {
+ stackTraceObj = argv[i + 1];
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) {
+ errorCodeObj = argv[i + 1];
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) {
+ if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) {
+ Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]);
+ return JIM_ERR;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ if (i != argc - 1 && i != argc) {
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
+ }
+
+
+ if (stackTraceObj && returnCode == JIM_ERR) {
+ JimSetStackTrace(interp, stackTraceObj);
+ }
+
+ if (errorCodeObj && returnCode == JIM_ERR) {
+ Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
+ }
+ interp->returnCode = returnCode;
+ interp->returnLevel = level;
+
+ if (i == argc - 1) {
+ Jim_SetResult(interp, argv[i]);
+ }
+ return level == 0 ? returnCode : JIM_RETURN;
+}
+
+
+static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (interp->framePtr->level == 0) {
+ Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1);
+ return JIM_ERR;
+ }
+ else if (argc >= 2) {
+
+ Jim_CallFrame *cf = interp->framePtr->parent;
+
+ Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
+ if (cmdPtr == NULL) {
+ return JIM_ERR;
+ }
+
+ JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd"));
+
+
+ JimIncrCmdRefCount(cmdPtr);
+ cf->tailcallCmd = cmdPtr;
+
+
+ JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj"));
+
+ cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1);
+ Jim_IncrRefCount(cf->tailcallObj);
+
+
+ return JIM_EVAL;
+ }
+ return JIM_OK;
+}
+
+static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *cmdList;
+ Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
+
+
+ cmdList = Jim_DuplicateObj(interp, prefixListObj);
+ Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1);
+
+ return JimEvalObjList(interp, cmdList);
+}
+
+static void JimAliasCmdDelete(Jim_Interp *interp, void *privData)
+{
+ Jim_Obj *prefixListObj = privData;
+ Jim_DecrRefCount(interp, prefixListObj);
+}
+
+static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *prefixListObj;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?");
+ return JIM_ERR;
+ }
+
+ prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2);
+ Jim_IncrRefCount(prefixListObj);
+ Jim_SetResult(interp, argv[1]);
+
+ return Jim_CreateCommandObj(interp, argv[1], JimAliasCmd, prefixListObj, JimAliasCmdDelete);
+}
+
+
+static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Cmd *cmd;
+
+ if (argc != 4 && argc != 5) {
+ Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
+ return JIM_ERR;
+ }
+
+ if (argc == 4) {
+ cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL);
+ }
+ else {
+ cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL);
+ }
+
+ if (cmd) {
+
+ Jim_Obj *nameObjPtr = JimQualifyName(interp, argv[1]);
+ JimCreateCommand(interp, nameObjPtr, cmd);
+
+
+ JimUpdateProcNamespace(interp, cmd, nameObjPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+
+
+ Jim_SetResult(interp, argv[1]);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+
+static int Jim_XtraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "callback");
+ return JIM_ERR;
+ }
+
+ if (interp->traceCmdObj) {
+ Jim_DecrRefCount(interp, interp->traceCmdObj);
+ interp->traceCmdObj = NULL;
+ }
+
+ if (Jim_Length(argv[1])) {
+
+ interp->traceCmdObj = argv[1];
+ Jim_IncrRefCount(interp->traceCmdObj);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retcode;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
+ return JIM_ERR;
+ }
+
+
+ interp->local++;
+ retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+ interp->local--;
+
+
+
+ if (retcode == 0) {
+ Jim_Obj *cmdNameObj = Jim_GetResult(interp);
+
+ if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) {
+ return JIM_ERR;
+ }
+ if (interp->framePtr->localCommands == NULL) {
+ interp->framePtr->localCommands = Jim_Alloc(sizeof(*interp->framePtr->localCommands));
+ Jim_InitStack(interp->framePtr->localCommands);
+ }
+ Jim_IncrRefCount(cmdNameObj);
+ Jim_StackPush(interp->framePtr->localCommands, cmdNameObj);
+ }
+
+ return retcode;
+}
+
+
+static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
+ return JIM_ERR;
+ }
+ else {
+ int retcode;
+
+ Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
+ if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) {
+ Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]);
+ return JIM_ERR;
+ }
+
+ cmdPtr->u.proc.upcall++;
+ JimIncrCmdRefCount(cmdPtr);
+
+
+ retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+
+
+ cmdPtr->u.proc.upcall--;
+ JimDecrCmdRefCount(interp, cmdPtr);
+
+ return retcode;
+ }
+}
+
+
+static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "lambdaExpr ?arg ...?");
+ return JIM_ERR;
+ }
+ else {
+ int ret;
+ Jim_Cmd *cmd;
+ Jim_Obj *argListObjPtr;
+ Jim_Obj *bodyObjPtr;
+ Jim_Obj *nsObj = NULL;
+ Jim_Obj **nargv;
+
+ int len = Jim_ListLength(interp, argv[1]);
+ if (len != 2 && len != 3) {
+ Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]);
+ return JIM_ERR;
+ }
+
+ if (len == 3) {
+#ifdef jim_ext_namespace
+
+ nsObj = Jim_ListGetIndex(interp, argv[1], 2);
+#else
+ Jim_SetResultString(interp, "namespaces not enabled", -1);
+ return JIM_ERR;
+#endif
+ }
+ argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0);
+ bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1);
+
+ cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj);
+
+ if (cmd) {
+
+ nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv));
+ nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1);
+ Jim_IncrRefCount(nargv[0]);
+ memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv));
+ ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv);
+ Jim_DecrRefCount(interp, nargv[0]);
+ Jim_Free(nargv);
+
+ JimDecrCmdRefCount(interp, cmd);
+ return ret;
+ }
+ return JIM_ERR;
+ }
+}
+
+
+
+static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+ return JIM_OK;
+}
+
+
+static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ Jim_CallFrame *targetCallFrame;
+
+
+ if (argc > 3 && (argc % 2 == 0)) {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
+ argc--;
+ argv++;
+ }
+ else {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+ }
+ if (targetCallFrame == NULL) {
+ return JIM_ERR;
+ }
+
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
+ return JIM_ERR;
+ }
+
+
+ for (i = 1; i < argc; i += 2) {
+ if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
+ return JIM_ERR;
+ }
+
+ if (interp->framePtr->level == 0)
+ return JIM_OK;
+ for (i = 1; i < argc; i++) {
+
+ const char *name = Jim_String(argv[i]);
+ if (name[0] != ':' || name[1] != ':') {
+ if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
+ return JIM_ERR;
+ }
+ }
+ return JIM_OK;
+}
+
+static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
+ Jim_Obj *objPtr, int nocase)
+{
+ int numMaps;
+ const char *str, *noMatchStart = NULL;
+ int strLen, i;
+ Jim_Obj *resultObjPtr;
+
+ numMaps = Jim_ListLength(interp, mapListObjPtr);
+ if (numMaps % 2) {
+ Jim_SetResultString(interp, "list must contain an even number of elements", -1);
+ return NULL;
+ }
+
+ str = Jim_String(objPtr);
+ strLen = Jim_Utf8Length(interp, objPtr);
+
+
+ resultObjPtr = Jim_NewStringObj(interp, "", 0);
+ while (strLen) {
+ for (i = 0; i < numMaps; i += 2) {
+ Jim_Obj *eachObjPtr;
+ const char *k;
+ int kl;
+
+ eachObjPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
+ k = Jim_String(eachObjPtr);
+ kl = Jim_Utf8Length(interp, eachObjPtr);
+
+ if (strLen >= kl && kl) {
+ int rc;
+ rc = JimStringCompareUtf8(str, kl, k, kl, nocase);
+ if (rc == 0) {
+ if (noMatchStart) {
+ Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+ noMatchStart = NULL;
+ }
+ Jim_AppendObj(interp, resultObjPtr, Jim_ListGetIndex(interp, mapListObjPtr, i + 1));
+ str += utf8_index(str, kl);
+ strLen -= kl;
+ break;
+ }
+ }
+ }
+ if (i == numMaps) {
+ int c;
+ if (noMatchStart == NULL)
+ noMatchStart = str;
+ str += utf8_tounicode(str, &c);
+ strLen--;
+ }
+ }
+ if (noMatchStart) {
+ Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+ }
+ return resultObjPtr;
+}
+
+
+static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int len;
+ int opt_case = 1;
+ int option;
+ static const char * const nocase_options[] = {
+ "-nocase", NULL
+ };
+ static const char * const nocase_length_options[] = {
+ "-nocase", "-length", NULL
+ };
+
+ enum {
+ OPT_BYTELENGTH,
+ OPT_BYTERANGE,
+ OPT_CAT,
+ OPT_COMPARE,
+ OPT_EQUAL,
+ OPT_FIRST,
+ OPT_INDEX,
+ OPT_IS,
+ OPT_LAST,
+ OPT_LENGTH,
+ OPT_MAP,
+ OPT_MATCH,
+ OPT_RANGE,
+ OPT_REPEAT,
+ OPT_REPLACE,
+ OPT_REVERSE,
+ OPT_TOLOWER,
+ OPT_TOTITLE,
+ OPT_TOUPPER,
+ OPT_TRIM,
+ OPT_TRIMLEFT,
+ OPT_TRIMRIGHT,
+ OPT_COUNT
+ };
+ static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
+ JIM_DEF_SUBCMD("bytelength", "string", 1, 1),
+ JIM_DEF_SUBCMD("byterange", "string first last", 3, 3),
+ JIM_DEF_SUBCMD("cat", "?...?", 0, -1),
+ JIM_DEF_SUBCMD("compare", "?-nocase? ?-length int? string1 string2", 2, 5),
+ JIM_DEF_SUBCMD("equal", "?-nocase? ?-length int? string1 string2", 2, 5),
+ JIM_DEF_SUBCMD("first", "subString string ?index?", 2, 3),
+ JIM_DEF_SUBCMD("index", "string index", 2, 2),
+ JIM_DEF_SUBCMD("is", "class ?-strict? str", 2, 3),
+ JIM_DEF_SUBCMD("last", "subString string ?index?", 2, 3),
+ JIM_DEF_SUBCMD("length","string", 1, 1),
+ JIM_DEF_SUBCMD("map", "?-nocase? mapList string", 2, 3),
+ JIM_DEF_SUBCMD("match", "?-nocase? pattern string", 2, 3),
+ JIM_DEF_SUBCMD("range", "string first last", 3, 3),
+ JIM_DEF_SUBCMD("repeat", "string count", 2, 2),
+ JIM_DEF_SUBCMD("replace", "string first last ?string?", 3, 4),
+ JIM_DEF_SUBCMD("reverse", "string", 1, 1),
+ JIM_DEF_SUBCMD("tolower", "string", 1, 1),
+ JIM_DEF_SUBCMD("totitle", "string", 1, 1),
+ JIM_DEF_SUBCMD("toupper", "string", 1, 1),
+ JIM_DEF_SUBCMD("trim", "string ?trimchars?", 1, 2),
+ JIM_DEF_SUBCMD("trimleft", "string ?trimchars?", 1, 2),
+ JIM_DEF_SUBCMD("trimright", "string ?trimchars?", 1, 2),
+ { NULL }
+ };
+ const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
+ if (!ct) {
+ return JIM_ERR;
+ }
+ if (ct->function) {
+
+ return ct->function(interp, argc, argv);
+ }
+
+ option = ct - cmds;
+
+ switch (option) {
+ case OPT_LENGTH:
+ Jim_SetResultInt(interp, Jim_Utf8Length(interp, argv[2]));
+ return JIM_OK;
+
+ case OPT_BYTELENGTH:
+ Jim_SetResultInt(interp, Jim_Length(argv[2]));
+ return JIM_OK;
+
+ case OPT_CAT:{
+ Jim_Obj *objPtr;
+ if (argc == 3) {
+
+ objPtr = argv[2];
+ }
+ else {
+ int i;
+
+ objPtr = Jim_NewStringObj(interp, "", 0);
+
+ for (i = 2; i < argc; i++) {
+ Jim_AppendObj(interp, objPtr, argv[i]);
+ }
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_COMPARE:
+ case OPT_EQUAL:
+ {
+
+ long opt_length = -1;
+ int n = argc - 4;
+ int i = 2;
+ while (n > 0) {
+ int subopt;
+ if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL,
+ JIM_ENUM_ABBREV) != JIM_OK) {
+badcompareargs:
+ Jim_SubCmdArgError(interp, ct, argv[0]);
+ return JIM_ERR;
+ }
+ if (subopt == 0) {
+
+ opt_case = 0;
+ n--;
+ }
+ else {
+
+ if (n < 2) {
+ goto badcompareargs;
+ }
+ if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) {
+ return JIM_ERR;
+ }
+ n -= 2;
+ }
+ }
+ if (n) {
+ goto badcompareargs;
+ }
+ argv += argc - 2;
+ if (opt_length < 0 && option != OPT_COMPARE && opt_case) {
+
+ Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
+ }
+ else {
+ const char *s1 = Jim_String(argv[0]);
+ int l1 = Jim_Utf8Length(interp, argv[0]);
+ const char *s2 = Jim_String(argv[1]);
+ int l2 = Jim_Utf8Length(interp, argv[1]);
+ if (opt_length >= 0) {
+ if (l1 > opt_length) {
+ l1 = opt_length;
+ }
+ if (l2 > opt_length) {
+ l2 = opt_length;
+ }
+ }
+ n = JimStringCompareUtf8(s1, l1, s2, l2, !opt_case);
+ Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0);
+ }
+ return JIM_OK;
+ }
+
+ case OPT_MATCH:
+ if (argc != 4 &&
+ (argc != 5 ||
+ Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+ JIM_ENUM_ABBREV) != JIM_OK)) {
+ Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string");
+ return JIM_ERR;
+ }
+ if (opt_case == 0) {
+ argv++;
+ }
+ Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case));
+ return JIM_OK;
+
+ case OPT_MAP:{
+ Jim_Obj *objPtr;
+
+ if (argc != 4 &&
+ (argc != 5 ||
+ Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+ JIM_ENUM_ABBREV) != JIM_OK)) {
+ Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string");
+ return JIM_ERR;
+ }
+
+ if (opt_case == 0) {
+ argv++;
+ }
+ objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_RANGE:{
+ Jim_Obj *objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_BYTERANGE:{
+ Jim_Obj *objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_REPLACE:{
+ Jim_Obj *objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+
+ case OPT_REPEAT:{
+ Jim_Obj *objPtr;
+ jim_wide count;
+
+ if (Jim_GetWideExpr(interp, argv[3], &count) != JIM_OK) {
+ return JIM_ERR;
+ }
+ objPtr = Jim_NewStringObj(interp, "", 0);
+ if (count > 0) {
+ while (count--) {
+ Jim_AppendObj(interp, objPtr, argv[2]);
+ }
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_REVERSE:{
+ char *buf, *p;
+ const char *str;
+ int i;
+
+ str = Jim_GetString(argv[2], &len);
+ buf = Jim_Alloc(len + 1);
+ assert(buf);
+ p = buf + len;
+ *p = 0;
+ for (i = 0; i < len; ) {
+ int c;
+ int l = utf8_tounicode(str, &c);
+ memcpy(p - l, str, l);
+ p -= l;
+ i += l;
+ str += l;
+ }
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+ return JIM_OK;
+ }
+
+ case OPT_INDEX:{
+ int idx;
+ const char *str;
+
+ if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) {
+ return JIM_ERR;
+ }
+ str = Jim_String(argv[2]);
+ len = Jim_Utf8Length(interp, argv[2]);
+ idx = JimRelToAbsIndex(len, idx);
+ if (idx < 0 || idx >= len || str == NULL) {
+ Jim_SetResultString(interp, "", 0);
+ }
+ else if (len == Jim_Length(argv[2])) {
+
+ Jim_SetResultString(interp, str + idx, 1);
+ }
+ else {
+ int c;
+ int i = utf8_index(str, idx);
+ Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c));
+ }
+ return JIM_OK;
+ }
+
+ case OPT_FIRST:
+ case OPT_LAST:{
+ int idx = 0, l1, l2;
+ const char *s1, *s2;
+
+ s1 = Jim_String(argv[2]);
+ s2 = Jim_String(argv[3]);
+ l1 = Jim_Utf8Length(interp, argv[2]);
+ l2 = Jim_Utf8Length(interp, argv[3]);
+ if (argc == 5) {
+ if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) {
+ return JIM_ERR;
+ }
+ idx = JimRelToAbsIndex(l2, idx);
+ if (idx < 0) {
+ idx = 0;
+ }
+ }
+ else if (option == OPT_LAST) {
+ idx = l2;
+ }
+ if (option == OPT_FIRST) {
+ Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx));
+ }
+ else {
+#ifdef JIM_UTF8
+ Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx));
+#else
+ Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx));
+#endif
+ }
+ return JIM_OK;
+ }
+
+ case OPT_TRIM:
+ Jim_SetResult(interp, JimStringTrim(interp, argv[2], argc == 4 ? argv[3] : NULL));
+ return JIM_OK;
+ case OPT_TRIMLEFT:
+ Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], argc == 4 ? argv[3] : NULL));
+ return JIM_OK;
+ case OPT_TRIMRIGHT:{
+ Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], argc == 4 ? argv[3] : NULL));
+ return JIM_OK;
+ }
+
+ case OPT_TOLOWER:
+ Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
+ return JIM_OK;
+ case OPT_TOUPPER:
+ Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
+ return JIM_OK;
+ case OPT_TOTITLE:
+ Jim_SetResult(interp, JimStringToTitle(interp, argv[2]));
+ return JIM_OK;
+
+ case OPT_IS:
+ if (argc == 5 && !Jim_CompareStringImmediate(interp, argv[3], "-strict")) {
+ Jim_SubCmdArgError(interp, ct, argv[0]);
+ return JIM_ERR;
+ }
+ return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ long i, count = 1;
+ jim_wide start, elapsed;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
+ return JIM_ERR;
+ }
+ if (count < 0)
+ return JIM_OK;
+ i = count;
+ start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+ while (i-- > 0) {
+ int retval;
+
+ retval = Jim_EvalObj(interp, argv[1]);
+ if (retval != JIM_OK) {
+ return retval;
+ }
+ }
+ elapsed = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
+ if (elapsed < count * 10) {
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, elapsed * 1.0 / count));
+ }
+ else {
+ Jim_SetResultInt(interp, count == 0 ? 0 : elapsed / count);
+ }
+ Jim_AppendString(interp, Jim_GetResult(interp)," microseconds per iteration", -1);
+ return JIM_OK;
+}
+
+
+static int Jim_TimeRateCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ long us = 0;
+ jim_wide start, delta, overhead;
+ Jim_Obj *objPtr;
+ double us_per_iter;
+ int count;
+ int n;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "script ?milliseconds?");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (Jim_GetLong(interp, argv[2], &us) != JIM_OK)
+ return JIM_ERR;
+ us *= 1000;
+ }
+ if (us < 1) {
+
+ us = 1000 * 1000;
+ }
+
+
+ start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+ count = 0;
+ do {
+ int retval = Jim_EvalObj(interp, argv[1]);
+ delta = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
+ if (retval != JIM_OK) {
+ return retval;
+ }
+ count++;
+ } while (delta < us);
+
+
+ start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+ n = 0;
+ do {
+ int retval = Jim_EvalObj(interp, interp->nullScriptObj);
+ overhead = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
+ if (retval != JIM_OK) {
+ return retval;
+ }
+ n++;
+ } while (n < count);
+
+ delta -= overhead;
+
+ us_per_iter = (double)delta / count;
+ objPtr = Jim_NewListObj(interp, NULL, 0);
+
+ Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "us_per_iter", -1));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, us_per_iter));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "iters_per_sec", -1));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, 1e6 / us_per_iter));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "count", -1));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, count));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "elapsed_us", -1));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, delta));
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ long exitCode = 0;
+
+ if (argc > 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
+ return JIM_ERR;
+ Jim_SetResult(interp, argv[1]);
+ }
+ interp->exitCode = exitCode;
+ return JIM_EXIT;
+}
+
+static int JimMatchReturnCodes(Jim_Interp *interp, Jim_Obj *retcodeListObj, int rc)
+{
+ int len = Jim_ListLength(interp, retcodeListObj);
+ int i;
+ for (i = 0; i < len; i++) {
+ int returncode;
+ if (Jim_GetReturnCode(interp, Jim_ListGetIndex(interp, retcodeListObj, i), &returncode) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (rc == returncode) {
+ return JIM_OK;
+ }
+ }
+ return -1;
+}
+
+
+static int JimCatchTryHelper(Jim_Interp *interp, int istry, int argc, Jim_Obj *const *argv)
+{
+ static const char * const wrongargs_catchtry[2] = {
+ "?-?no?code ... --? script ?resultVarName? ?optionVarName?",
+ "?-?no?code ... --? script ?on|trap codes vars script? ... ?finally script?"
+ };
+ int exitCode = 0;
+ int i;
+ int sig = 0;
+ int ok;
+ Jim_Obj *finallyScriptObj = NULL;
+ Jim_Obj *msgVarObj = NULL;
+ Jim_Obj *optsVarObj = NULL;
+ Jim_Obj *handlerScriptObj = NULL;
+ Jim_Obj *errorCodeObj;
+ int idx;
+
+
+ jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
+ static const int max_ignore_code = sizeof(ignore_mask) * 8;
+
+ JimPanic((istry != 0 && istry != 1, "wrong args to JimCatchTryHelper"));
+
+ Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
+
+ for (i = 1; i < argc - 1; i++) {
+ const char *arg = Jim_String(argv[i]);
+ jim_wide option;
+ int ignore;
+
+
+ if (strcmp(arg, "--") == 0) {
+ i++;
+ break;
+ }
+ if (*arg != '-') {
+ break;
+ }
+
+ if (strncmp(arg, "-no", 3) == 0) {
+ arg += 3;
+ ignore = 1;
+ }
+ else {
+ arg++;
+ ignore = 0;
+ }
+
+ if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
+ option = -1;
+ }
+ if (option < 0) {
+ option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize);
+ }
+ if (option < 0) {
+ goto wrongargs;
+ }
+
+ if (ignore) {
+ ignore_mask |= ((jim_wide)1 << option);
+ }
+ else {
+ ignore_mask &= (~((jim_wide)1 << option));
+ }
+ }
+
+ idx = i;
+
+ if (argc - idx < 1) {
+wrongargs:
+ Jim_WrongNumArgs(interp, 1, argv, wrongargs_catchtry[istry]);
+ return JIM_ERR;
+ }
+
+ if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
+ sig++;
+ }
+
+ interp->signal_level += sig;
+ if (Jim_CheckSignal(interp)) {
+
+ exitCode = JIM_SIGNAL;
+ }
+ else {
+ exitCode = Jim_EvalObj(interp, argv[idx]);
+
+ interp->errorFlag = 0;
+ }
+ interp->signal_level -= sig;
+
+ errorCodeObj = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
+
+ idx++;
+ if (istry) {
+ while (idx < argc) {
+ int option;
+ int ret;
+ static const char * const try_options[] = { "on", "trap", "finally", NULL };
+ enum { TRY_ON, TRY_TRAP, TRY_FINALLY, };
+
+ if (Jim_GetEnum(interp, argv[idx], try_options, &option, "handler", JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case TRY_ON:
+ case TRY_TRAP:
+ if (idx + 4 > argc) {
+ goto wrongargs;
+ }
+ if (option == TRY_ON) {
+ ret = JimMatchReturnCodes(interp, argv[idx + 1], exitCode);
+ if (ret > JIM_OK) {
+ goto wrongargs;
+ }
+ }
+ else if (errorCodeObj) {
+ int len = Jim_ListLength(interp, argv[idx + 1]);
+
+ if (len > Jim_ListLength(interp, errorCodeObj)) {
+
+ ret = -1;
+ }
+ else {
+ int i;
+ ret = JIM_OK;
+
+ for (i = 0; i < len; i++) {
+ Jim_Obj *matchObj = Jim_ListGetIndex(interp, argv[idx + 1], i);
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, errorCodeObj, i);
+ if (Jim_StringCompareObj(interp, matchObj, objPtr, 0) != 0) {
+ ret = -1;
+ break;
+ }
+ }
+ }
+ }
+ else {
+
+ ret = -1;
+ }
+
+ if (ret == JIM_OK && handlerScriptObj == NULL) {
+ msgVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 0);
+ optsVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 1);
+ handlerScriptObj = argv[idx + 3];
+ }
+ idx += 4;
+ break;
+ case TRY_FINALLY:
+ if (idx + 2 != argc) {
+ goto wrongargs;
+ }
+ finallyScriptObj = argv[idx + 1];
+ idx += 2;
+ break;
+ }
+ }
+ }
+ else {
+ if (argc - idx >= 1) {
+ msgVarObj = argv[idx];
+ idx++;
+ if (argc - idx >= 1) {
+ optsVarObj = argv[idx];
+ idx++;
+ }
+ }
+ }
+
+
+ if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {
+
+ if (finallyScriptObj) {
+ Jim_EvalObj(interp, finallyScriptObj);
+ }
+ return exitCode;
+ }
+
+ if (sig && exitCode == JIM_SIGNAL) {
+
+ if (interp->signal_set_result) {
+ interp->signal_set_result(interp, interp->sigmask);
+ }
+ else if (!istry) {
+ Jim_SetResultInt(interp, interp->sigmask);
+ }
+ interp->sigmask = 0;
+ }
+
+ ok = 1;
+ if (msgVarObj && Jim_Length(msgVarObj)) {
+ if (Jim_SetVariable(interp, msgVarObj, Jim_GetResult(interp)) != JIM_OK) {
+ ok = 0;
+ }
+ }
+ if (ok && optsVarObj && Jim_Length(optsVarObj)) {
+ Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
+
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
+ Jim_ListAppendElement(interp, optListObj,
+ Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
+ Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
+ if (exitCode == JIM_ERR) {
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
+ -1));
+ Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
+
+ if (errorCodeObj) {
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
+ Jim_ListAppendElement(interp, optListObj, errorCodeObj);
+ }
+ }
+ if (Jim_SetVariable(interp, optsVarObj, optListObj) != JIM_OK) {
+ ok = 0;
+ }
+ }
+ if (ok && handlerScriptObj) {
+
+ exitCode = Jim_EvalObj(interp, handlerScriptObj);
+ }
+
+ if (finallyScriptObj) {
+
+ Jim_Obj *prevResultObj = Jim_GetResult(interp);
+ Jim_IncrRefCount(prevResultObj);
+ int ret = Jim_EvalObj(interp, finallyScriptObj);
+ if (ret == JIM_OK) {
+ Jim_SetResult(interp, prevResultObj);
+ }
+ else {
+ exitCode = ret;
+ }
+ Jim_DecrRefCount(interp, prevResultObj);
+ }
+ if (!istry) {
+ Jim_SetResultInt(interp, exitCode);
+ exitCode = JIM_OK;
+ }
+ return exitCode;
+}
+
+
+static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimCatchTryHelper(interp, 0, argc, argv);
+}
+
+
+static int Jim_TryCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimCatchTryHelper(interp, 1, argc, argv);
+}
+
+
+
+static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
+ return JIM_ERR;
+ }
+
+ return Jim_RenameCommand(interp, argv[1], argv[2]);
+}
+
+#define JIM_DICTMATCH_KEYS 0x0001
+#define JIM_DICTMATCH_VALUES 0x002
+
+int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types)
+{
+ Jim_Obj *listObjPtr;
+ Jim_Dict *dict;
+ int i;
+
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ dict = objPtr->internalRep.dictValue;
+
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; i < dict->len; i += 2 ) {
+ Jim_Obj *keyObj = dict->table[i];
+ Jim_Obj *valObj = dict->table[i + 1];
+ if (patternObj) {
+ Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? keyObj : valObj;
+ if (!Jim_StringMatchObj(interp, patternObj, matchObj, 0)) {
+
+ continue;
+ }
+ }
+ if (return_types & JIM_DICTMATCH_KEYS) {
+ Jim_ListAppendElement(interp, listObjPtr, keyObj);
+ }
+ if (return_types & JIM_DICTMATCH_VALUES) {
+ Jim_ListAppendElement(interp, listObjPtr, valObj);
+ }
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+}
+
+int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return -1;
+ }
+ return objPtr->internalRep.dictValue->len / 2;
+}
+
+Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ Jim_Obj *objPtr = Jim_NewDictObj(interp, NULL, 0);
+ int i;
+
+ JimPanic((objc == 0, "Jim_DictMerge called with objc=0"));
+
+
+
+ for (i = 0; i < objc; i++) {
+ Jim_Obj **table;
+ int tablelen;
+ int j;
+
+ table = Jim_DictPairs(interp, objv[i], &tablelen);
+ if (tablelen && !table) {
+ Jim_FreeNewObj(interp, objPtr);
+ return NULL;
+ }
+ for (j = 0; j < tablelen; j += 2) {
+ DictAddElement(interp, objPtr, table[j], table[j + 1]);
+ }
+ }
+ return objPtr;
+}
+
+int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ char buffer[100];
+ Jim_Obj *output;
+ Jim_Dict *dict;
+
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ dict = objPtr->internalRep.dictValue;
+
+
+ snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets", dict->len, dict->size);
+ output = Jim_NewStringObj(interp, buffer, -1);
+ Jim_SetResult(interp, output);
+ return JIM_OK;
+}
+
+static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *prefixObj = Jim_NewStringObj(interp, basecmd, -1);
+
+ Jim_AppendString(interp, prefixObj, " ", 1);
+ Jim_AppendString(interp, prefixObj, subcmd, -1);
+
+ return Jim_EvalObjPrefix(interp, prefixObj, argc, argv);
+}
+
+static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const *keyv, int keyc, Jim_Obj *scriptObj)
+{
+ int i;
+ Jim_Obj *objPtr;
+ Jim_Obj *dictObj;
+ Jim_Obj **dictValues;
+ int len;
+ int ret = JIM_OK;
+
+
+ dictObj = Jim_GetVariable(interp, dictVarName, JIM_ERRMSG);
+ if (dictObj == NULL || Jim_DictKeysVector(interp, dictObj, keyv, keyc, &objPtr, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ dictValues = Jim_DictPairs(interp, objPtr, &len);
+ if (len && dictValues == NULL) {
+ return JIM_ERR;
+ }
+ for (i = 0; i < len; i += 2) {
+ if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) {
+ return JIM_ERR;
+ }
+ }
+
+
+ if (Jim_Length(scriptObj)) {
+ ret = Jim_EvalObj(interp, scriptObj);
+
+
+ if (ret == JIM_OK && Jim_GetVariable(interp, dictVarName, 0) != NULL) {
+
+ Jim_Obj **newkeyv = Jim_Alloc(sizeof(*newkeyv) * (keyc + 1));
+ for (i = 0; i < keyc; i++) {
+ newkeyv[i] = keyv[i];
+ }
+
+ for (i = 0; i < len; i += 2) {
+
+ if (Jim_StringCompareObj(interp, dictVarName, dictValues[i], 0) != 0) {
+
+ objPtr = Jim_GetVariable(interp, dictValues[i], 0);
+ newkeyv[keyc] = dictValues[i];
+ Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, JIM_NORESULT);
+ }
+ }
+ Jim_Free(newkeyv);
+ }
+ }
+
+ return ret;
+}
+
+
+static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int types = JIM_DICTMATCH_KEYS;
+
+ enum {
+ OPT_CREATE,
+ OPT_GET,
+ OPT_GETDEF,
+ OPT_GETWITHDEFAULT,
+ OPT_SET,
+ OPT_UNSET,
+ OPT_EXISTS,
+ OPT_KEYS,
+ OPT_SIZE,
+ OPT_INFO,
+ OPT_MERGE,
+ OPT_WITH,
+ OPT_APPEND,
+ OPT_LAPPEND,
+ OPT_INCR,
+ OPT_REMOVE,
+ OPT_VALUES,
+ OPT_FOR,
+ OPT_REPLACE,
+ OPT_UPDATE,
+ OPT_COUNT
+ };
+ static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
+ JIM_DEF_SUBCMD("create", "?key value ...?", 0, -2),
+ JIM_DEF_SUBCMD("get", "dictionary ?key ...?", 1, -1),
+ JIM_DEF_SUBCMD_HIDDEN("getdef", "dictionary ?key ...? key default", 3, -1),
+ JIM_DEF_SUBCMD("getwithdefault", "dictionary ?key ...? key default", 3, -1),
+ JIM_DEF_SUBCMD("set", "varName key ?key ...? value", 3, -1),
+ JIM_DEF_SUBCMD("unset", "varName key ?key ...?", 2, -1),
+ JIM_DEF_SUBCMD("exists", "dictionary key ?key ...?", 2, -1),
+ JIM_DEF_SUBCMD("keys", "dictionary ?pattern?", 1, 2),
+ JIM_DEF_SUBCMD("size", "dictionary", 1, 1),
+ JIM_DEF_SUBCMD("info", "dictionary", 1, 1),
+ JIM_DEF_SUBCMD("merge", "?...?", 0, -1),
+ JIM_DEF_SUBCMD("with", "dictVar ?key ...? script", 2, -1),
+ JIM_DEF_SUBCMD("append", "varName key ?value ...?", 2, -1),
+ JIM_DEF_SUBCMD("lappend", "varName key ?value ...?", 2, -1),
+ JIM_DEF_SUBCMD("incr", "varName key ?increment?", 2, 3),
+ JIM_DEF_SUBCMD("remove", "dictionary ?key ...?", 1, -1),
+ JIM_DEF_SUBCMD("values", "dictionary ?pattern?", 1, 2),
+ JIM_DEF_SUBCMD("for", "vars dictionary script", 3, 3),
+ JIM_DEF_SUBCMD("replace", "dictionary ?key value ...?", 1, -1),
+ JIM_DEF_SUBCMD("update", "varName ?arg ...? script", 2, -1),
+ { NULL }
+ };
+ const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
+ if (!ct) {
+ return JIM_ERR;
+ }
+ if (ct->function) {
+
+ return ct->function(interp, argc, argv);
+ }
+
+
+ switch (ct - cmds) {
+ case OPT_GET:
+ if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
+ JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+
+ case OPT_GETDEF:
+ case OPT_GETWITHDEFAULT:{
+ int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 4, &objPtr, JIM_ERRMSG);
+ if (rc == -1) {
+
+ return JIM_ERR;
+ }
+ if (rc == JIM_ERR) {
+ Jim_SetResult(interp, argv[argc - 1]);
+ }
+ else {
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+ }
+
+ case OPT_SET:
+ return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG | JIM_UNSHARED);
+
+ case OPT_EXISTS:{
+ int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_NONE);
+ if (rc < 0) {
+ return JIM_ERR;
+ }
+ Jim_SetResultBool(interp, rc == JIM_OK);
+ return JIM_OK;
+ }
+
+ case OPT_UNSET:
+ if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_UNSHARED) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return JIM_OK;
+
+ case OPT_VALUES:
+ types = JIM_DICTMATCH_VALUES;
+
+ case OPT_KEYS:
+ return Jim_DictMatchTypes(interp, argv[2], argc == 4 ? argv[3] : NULL, types, types);
+
+ case OPT_SIZE:
+ if (Jim_DictSize(interp, argv[2]) < 0) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2]));
+ return JIM_OK;
+
+ case OPT_MERGE:
+ if (argc == 2) {
+ return JIM_OK;
+ }
+ objPtr = Jim_DictMerge(interp, argc - 2, argv + 2);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+
+ case OPT_CREATE:
+ objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+
+ case OPT_INFO:
+ return Jim_DictInfo(interp, argv[2]);
+
+ case OPT_WITH:
+ return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]);
+
+ case OPT_UPDATE:
+ if (argc < 6 || argc % 2) {
+
+ argc = 2;
+ }
+
+ default:
+ return Jim_EvalEnsemble(interp, "dict", Jim_String(argv[1]), argc - 2, argv + 2);
+ }
+}
+
+
+static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ static const char * const options[] = {
+ "-nobackslashes", "-nocommands", "-novariables", NULL
+ };
+ enum
+ { OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES };
+ int i;
+ int flags = JIM_SUBST_FLAG;
+ Jim_Obj *objPtr;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?options? string");
+ return JIM_ERR;
+ }
+ for (i = 1; i < (argc - 1); i++) {
+ int option;
+
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL,
+ JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_NOBACKSLASHES:
+ flags |= JIM_SUBST_NOESC;
+ break;
+ case OPT_NOCOMMANDS:
+ flags |= JIM_SUBST_NOCMD;
+ break;
+ case OPT_NOVARIABLES:
+ flags |= JIM_SUBST_NOVAR;
+ break;
+ }
+ }
+ if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+#ifdef jim_ext_namespace
+static int JimIsGlobalNamespace(Jim_Obj *objPtr)
+{
+ int len;
+ const char *str = Jim_GetString(objPtr, &len);
+ return len >= 2 && str[0] == ':' && str[1] == ':';
+}
+#endif
+
+
+static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int mode = 0;
+
+
+ enum {
+ INFO_ALIAS,
+ INFO_ARGS,
+ INFO_BODY,
+ INFO_CHANNELS,
+ INFO_COMMANDS,
+ INFO_COMPLETE,
+ INFO_EXISTS,
+ INFO_FRAME,
+ INFO_GLOBALS,
+ INFO_HOSTNAME,
+ INFO_LEVEL,
+ INFO_LOCALS,
+ INFO_NAMEOFEXECUTABLE,
+ INFO_PATCHLEVEL,
+ INFO_PROCS,
+ INFO_REFERENCES,
+ INFO_RETURNCODES,
+ INFO_SCRIPT,
+ INFO_SOURCE,
+ INFO_STACKTRACE,
+ INFO_STATICS,
+ INFO_VARS,
+ INFO_VERSION,
+ INFO_COUNT
+ };
+ static const jim_subcmd_type cmds[INFO_COUNT + 1] = {
+ JIM_DEF_SUBCMD("alias", "command", 1, 1),
+ JIM_DEF_SUBCMD("args", "procname", 1, 1),
+ JIM_DEF_SUBCMD("body", "procname", 1, 1),
+ JIM_DEF_SUBCMD("channels", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("commands", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("complete", "script ?missing?", 1, 2),
+ JIM_DEF_SUBCMD("exists", "varName", 1, 1),
+ JIM_DEF_SUBCMD("frame", "?levelNum?", 0, 1),
+ JIM_DEF_SUBCMD("globals", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("hostname", NULL, 0, 0),
+ JIM_DEF_SUBCMD("level", "?levelNum?", 0, 1),
+ JIM_DEF_SUBCMD("locals", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("nameofexecutable", NULL, 0, 0),
+ JIM_DEF_SUBCMD("patchlevel", NULL, 0, 0),
+ JIM_DEF_SUBCMD("procs", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("references", NULL, 0, 0),
+ JIM_DEF_SUBCMD("returncodes", "?code?", 0, 1),
+ JIM_DEF_SUBCMD("script", "?filename?", 0, 1),
+ JIM_DEF_SUBCMD("source", "source ?filename line?", 1, 3),
+ JIM_DEF_SUBCMD("stacktrace", NULL, 0, 0),
+ JIM_DEF_SUBCMD("statics", "procname", 1, 1),
+ JIM_DEF_SUBCMD("vars", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("version", NULL, 0, 0),
+ { NULL }
+ };
+ const jim_subcmd_type *ct;
+#ifdef jim_ext_namespace
+ int nons = 0;
+
+ if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
+
+ argc--;
+ argv++;
+ nons = 1;
+ }
+#endif
+ ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
+ if (!ct) {
+ return JIM_ERR;
+ }
+ if (ct->function) {
+
+ return ct->function(interp, argc, argv);
+ }
+
+ int option = ct - cmds;
+
+ switch (option) {
+ case INFO_EXISTS:
+ Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL);
+ return JIM_OK;
+
+ case INFO_ALIAS:{
+ Jim_Cmd *cmdPtr;
+
+ if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
+ return JIM_ERR;
+ }
+ if (cmdPtr->isproc || cmdPtr->u.native.cmdProc != JimAliasCmd) {
+ Jim_SetResultFormatted(interp, "command \"%#s\" is not an alias", argv[2]);
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData);
+ return JIM_OK;
+ }
+
+ case INFO_CHANNELS:
+ mode++;
+#ifndef jim_ext_aio
+ Jim_SetResultString(interp, "aio not enabled", -1);
+ return JIM_ERR;
+#endif
+
+ case INFO_PROCS:
+ mode++;
+
+ case INFO_COMMANDS:
+
+#ifdef jim_ext_namespace
+ if (!nons) {
+ if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
+ return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
+ }
+ }
+#endif
+ Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
+ return JIM_OK;
+
+ case INFO_VARS:
+ mode++;
+
+ case INFO_LOCALS:
+ mode++;
+
+ case INFO_GLOBALS:
+
+#ifdef jim_ext_namespace
+ if (!nons) {
+ if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
+ return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
+ }
+ }
+#endif
+ Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
+ return JIM_OK;
+
+ case INFO_SCRIPT:
+ if (argc == 3) {
+ Jim_IncrRefCount(argv[2]);
+ Jim_DecrRefCount(interp, interp->currentFilenameObj);
+ interp->currentFilenameObj = argv[2];
+ }
+ Jim_SetResult(interp, interp->currentFilenameObj);
+ return JIM_OK;
+
+ case INFO_SOURCE:{
+ Jim_Obj *resObjPtr;
+ Jim_Obj *fileNameObj;
+
+ if (argc == 4) {
+ Jim_SubCmdArgError(interp, ct, argv[0]);
+ return JIM_ERR;
+ }
+ if (argc == 5) {
+ jim_wide line;
+ if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
+ return JIM_ERR;
+ }
+ resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
+ Jim_SetSourceInfo(interp, resObjPtr, argv[3], line);
+ }
+ else {
+ int line;
+ fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line);
+ resObjPtr = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
+ Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
+ }
+ Jim_SetResult(interp, resObjPtr);
+ return JIM_OK;
+ }
+
+ case INFO_STACKTRACE:
+ Jim_SetResult(interp, interp->stackTrace);
+ return JIM_OK;
+
+ case INFO_LEVEL:
+ if (argc == 2) {
+ Jim_SetResultInt(interp, interp->framePtr->level);
+ }
+ else {
+ if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+
+ case INFO_FRAME:
+ if (argc == 2) {
+ Jim_SetResultInt(interp, interp->procLevel + 1);
+ }
+ else {
+ if (JimInfoFrame(interp, argv[2], &objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+
+ case INFO_BODY:
+ case INFO_STATICS:
+ case INFO_ARGS:{
+ Jim_Cmd *cmdPtr;
+
+ if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
+ return JIM_ERR;
+ }
+ if (!cmdPtr->isproc) {
+ Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]);
+ return JIM_ERR;
+ }
+ switch (option) {
+#ifdef JIM_NO_INTROSPECTION
+ default:
+ Jim_SetResultString(interp, "unsupported", -1);
+ return JIM_ERR;
+#else
+ case INFO_BODY:
+ Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr);
+ break;
+ case INFO_ARGS:
+ Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
+ break;
+#endif
+ case INFO_STATICS:
+ if (cmdPtr->u.proc.staticVars) {
+ Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
+ NULL, JimVariablesMatch, JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES));
+ }
+ break;
+ }
+ return JIM_OK;
+ }
+
+ case INFO_VERSION:
+ case INFO_PATCHLEVEL:{
+ char buf[(JIM_INTEGER_SPACE * 2) + 1];
+
+ sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100);
+ Jim_SetResultString(interp, buf, -1);
+ return JIM_OK;
+ }
+
+ case INFO_COMPLETE: {
+ char missing;
+
+ Jim_SetResultBool(interp, Jim_ScriptIsComplete(interp, argv[2], &missing));
+ if (missing != ' ' && argc == 4) {
+ Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1));
+ }
+ return JIM_OK;
+ }
+
+ case INFO_HOSTNAME:
+
+ return Jim_Eval(interp, "os.gethostname");
+
+ case INFO_NAMEOFEXECUTABLE:
+
+ return Jim_Eval(interp, "{info nameofexecutable}");
+
+ case INFO_RETURNCODES:
+ if (argc == 2) {
+ int i;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; jimReturnCodes[i]; i++) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i));
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp,
+ jimReturnCodes[i], -1));
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ }
+ else if (argc == 3) {
+ long code;
+ const char *name;
+
+ if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) {
+ return JIM_ERR;
+ }
+ name = Jim_ReturnCode(code);
+ if (*name == '?') {
+ Jim_SetResultInt(interp, code);
+ }
+ else {
+ Jim_SetResultString(interp, name, -1);
+ }
+ }
+ return JIM_OK;
+ case INFO_REFERENCES:
+#ifdef JIM_REFERENCES
+ return JimInfoReferences(interp, argc, argv);
+#else
+ Jim_SetResultString(interp, "not supported", -1);
+ return JIM_ERR;
+#endif
+ default:
+ abort();
+ }
+}
+
+
+static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int result = 0;
+
+ static const char * const options[] = {
+ "-command", "-proc", "-alias", "-var", NULL
+ };
+ enum
+ {
+ OPT_COMMAND, OPT_PROC, OPT_ALIAS, OPT_VAR
+ };
+ int option;
+
+ if (argc == 2) {
+ option = OPT_VAR;
+ objPtr = argv[1];
+ }
+ else if (argc == 3) {
+ if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ objPtr = argv[2];
+ }
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "?option? name");
+ return JIM_ERR;
+ }
+
+ if (option == OPT_VAR) {
+ result = Jim_GetVariable(interp, objPtr, 0) != NULL;
+ }
+ else {
+
+ Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
+
+ if (cmd) {
+ switch (option) {
+ case OPT_COMMAND:
+ result = 1;
+ break;
+
+ case OPT_ALIAS:
+ result = cmd->isproc == 0 && cmd->u.native.cmdProc == JimAliasCmd;
+ break;
+
+ case OPT_PROC:
+ result = cmd->isproc;
+ break;
+ }
+ }
+ }
+ Jim_SetResultBool(interp, result);
+ return JIM_OK;
+}
+
+
+static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *str, *splitChars, *noMatchStart;
+ int splitLen, strLen;
+ Jim_Obj *resObjPtr;
+ int c;
+ int len;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
+ return JIM_ERR;
+ }
+
+ str = Jim_GetString(argv[1], &len);
+ if (len == 0) {
+ return JIM_OK;
+ }
+ strLen = Jim_Utf8Length(interp, argv[1]);
+
+
+ if (argc == 2) {
+ splitChars = " \n\t\r";
+ splitLen = 4;
+ }
+ else {
+ splitChars = Jim_String(argv[2]);
+ splitLen = Jim_Utf8Length(interp, argv[2]);
+ }
+
+ noMatchStart = str;
+ resObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+
+ if (splitLen) {
+ Jim_Obj *objPtr;
+ while (strLen--) {
+ const char *sc = splitChars;
+ int scLen = splitLen;
+ int sl = utf8_tounicode(str, &c);
+ while (scLen--) {
+ int pc;
+ sc += utf8_tounicode(sc, &pc);
+ if (c == pc) {
+ objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+ Jim_ListAppendElement(interp, resObjPtr, objPtr);
+ noMatchStart = str + sl;
+ break;
+ }
+ }
+ str += sl;
+ }
+ objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+ Jim_ListAppendElement(interp, resObjPtr, objPtr);
+ }
+ else {
+ Jim_Obj **commonObj = NULL;
+#define NUM_COMMON (128 - 9)
+ while (strLen--) {
+ int n = utf8_tounicode(str, &c);
+#ifdef JIM_OPTIMIZATION
+ if (c >= 9 && c < 128) {
+
+ c -= 9;
+ if (!commonObj) {
+ commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
+ memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
+ }
+ if (!commonObj[c]) {
+ commonObj[c] = Jim_NewStringObj(interp, str, 1);
+ }
+ Jim_ListAppendElement(interp, resObjPtr, commonObj[c]);
+ str++;
+ continue;
+ }
+#endif
+ Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1));
+ str += n;
+ }
+ Jim_Free(commonObj);
+ }
+
+ Jim_SetResult(interp, resObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *joinStr;
+ int joinStrLen;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
+ return JIM_ERR;
+ }
+
+ if (argc == 2) {
+ joinStr = " ";
+ joinStrLen = 1;
+ }
+ else {
+ joinStr = Jim_GetString(argv[2], &joinStrLen);
+ }
+ Jim_SetResult(interp, Jim_ListJoin(interp, argv[1], joinStr, joinStrLen));
+ return JIM_OK;
+}
+
+
+static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
+ return JIM_ERR;
+ }
+ objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2);
+ if (objPtr == NULL)
+ return JIM_ERR;
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listPtr, **outVec;
+ int outc, i;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?");
+ return JIM_ERR;
+ }
+ if (argv[2]->typePtr != &scanFmtStringObjType)
+ SetScanFmtFromAny(interp, argv[2]);
+ if (FormatGetError(argv[2]) != 0) {
+ Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
+ return JIM_ERR;
+ }
+ if (argc > 3) {
+ int maxPos = FormatGetMaxPos(argv[2]);
+ int count = FormatGetCnvCount(argv[2]);
+
+ if (maxPos > argc - 3) {
+ Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
+ return JIM_ERR;
+ }
+ else if (count > argc - 3) {
+ Jim_SetResultString(interp, "different numbers of variable names and "
+ "field specifiers", -1);
+ return JIM_ERR;
+ }
+ else if (count < argc - 3) {
+ Jim_SetResultString(interp, "variable is not assigned by any "
+ "conversion specifiers", -1);
+ return JIM_ERR;
+ }
+ }
+ listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
+ if (listPtr == 0)
+ return JIM_ERR;
+ if (argc > 3) {
+ int rc = JIM_OK;
+ int count = 0;
+
+ if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) {
+ int len = Jim_ListLength(interp, listPtr);
+
+ if (len != 0) {
+ JimListGetElements(interp, listPtr, &outc, &outVec);
+ for (i = 0; i < outc; ++i) {
+ if (Jim_Length(outVec[i]) > 0) {
+ ++count;
+ if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) {
+ rc = JIM_ERR;
+ }
+ }
+ }
+ }
+ Jim_FreeNewObj(interp, listPtr);
+ }
+ else {
+ count = -1;
+ }
+ if (rc == JIM_OK) {
+ Jim_SetResultInt(interp, count);
+ }
+ return rc;
+ }
+ else {
+ if (listPtr == (Jim_Obj *)EOF) {
+ Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
+ return JIM_OK;
+ }
+ Jim_SetResult(interp, listPtr);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?");
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, argv[1]);
+ if (argc == 3) {
+ JimSetStackTrace(interp, argv[2]);
+ return JIM_ERR;
+ }
+ return JIM_ERR;
+}
+
+
+static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+
+ if (argc != 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "list first last");
+ return JIM_ERR;
+ }
+ if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
+ return JIM_ERR;
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ jim_wide count;
+
+ if (argc < 2 || Jim_GetWideExpr(interp, argv[1], &count) != JIM_OK || count < 0) {
+ Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?");
+ return JIM_ERR;
+ }
+ if (count == 0 || argc == 2) {
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+ }
+
+ argc -= 2;
+ argv += 2;
+
+ objPtr = Jim_NewListObj(interp, NULL, 0);
+ ListEnsureLength(objPtr, argc * count);
+ while (count--) {
+ ListInsertElements(objPtr, -1, argc, argv);
+ }
+
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+char **Jim_GetEnviron(void)
+{
+#if defined(HAVE__NSGETENVIRON)
+ return *_NSGetEnviron();
+#elif defined(_environ)
+ return _environ;
+#else
+ #if !defined(NO_ENVIRON_EXTERN)
+ extern char **environ;
+ #endif
+ return environ;
+#endif
+}
+
+void Jim_SetEnviron(char **env)
+{
+#if defined(HAVE__NSGETENVIRON)
+ *_NSGetEnviron() = env;
+#elif defined(_environ)
+ _environ = env;
+#else
+ #if !defined(NO_ENVIRON_EXTERN)
+ extern char **environ;
+ #endif
+
+ environ = env;
+#endif
+}
+
+
+static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *key;
+ const char *val;
+
+ if (argc == 1) {
+ char **e = Jim_GetEnviron();
+
+ int i;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; e[i]; i++) {
+ const char *equals = strchr(e[i], '=');
+
+ if (equals) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i],
+ equals - e[i]));
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
+ }
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+ }
+
+ if (argc > 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?default?");
+ return JIM_ERR;
+ }
+ key = Jim_String(argv[1]);
+ val = getenv(key);
+ if (val == NULL) {
+ if (argc < 3) {
+ Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]);
+ return JIM_ERR;
+ }
+ val = Jim_String(argv[2]);
+ }
+ Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
+ return JIM_OK;
+}
+
+
+static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retval;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "fileName");
+ return JIM_ERR;
+ }
+ retval = Jim_EvalFile(interp, Jim_String(argv[1]));
+ if (retval == JIM_RETURN)
+ return JIM_OK;
+ return retval;
+}
+
+
+static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *revObjPtr, **ele;
+ int len;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "list");
+ return JIM_ERR;
+ }
+ JimListGetElements(interp, argv[1], &len, &ele);
+ revObjPtr = Jim_NewListObj(interp, NULL, 0);
+ ListEnsureLength(revObjPtr, len);
+ len--;
+ while (len >= 0)
+ ListAppendElement(revObjPtr, ele[len--]);
+ Jim_SetResult(interp, revObjPtr);
+ return JIM_OK;
+}
+
+static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
+{
+ jim_wide len;
+
+ if (step == 0)
+ return -1;
+ if (start == end)
+ return 0;
+ else if (step > 0 && start > end)
+ return -1;
+ else if (step < 0 && end > start)
+ return -1;
+ len = end - start;
+ if (len < 0)
+ len = -len;
+ if (step < 0)
+ step = -step;
+ len = 1 + ((len - 1) / step);
+ if (len > INT_MAX)
+ len = INT_MAX;
+ return (int)((len < 0) ? -1 : len);
+}
+
+
+static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_wide start = 0, end, step = 1;
+ int len, i;
+ Jim_Obj *objPtr;
+
+ if (argc < 2 || argc > 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ if (Jim_GetWideExpr(interp, argv[1], &end) != JIM_OK)
+ return JIM_ERR;
+ }
+ else {
+ if (Jim_GetWideExpr(interp, argv[1], &start) != JIM_OK ||
+ Jim_GetWideExpr(interp, argv[2], &end) != JIM_OK)
+ return JIM_ERR;
+ if (argc == 4 && Jim_GetWideExpr(interp, argv[3], &step) != JIM_OK)
+ return JIM_ERR;
+ }
+ if ((len = JimRangeLen(start, end, step)) == -1) {
+ Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
+ return JIM_ERR;
+ }
+ objPtr = Jim_NewListObj(interp, NULL, 0);
+ ListEnsureLength(objPtr, len);
+ for (i = 0; i < len; i++)
+ ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_wide min = 0, max = 0, len, maxMul;
+
+ if (argc < 1 || argc > 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "?min? max");
+ return JIM_ERR;
+ }
+ if (argc == 1) {
+ max = JIM_WIDE_MAX;
+ } else if (argc == 2) {
+ if (Jim_GetWideExpr(interp, argv[1], &max) != JIM_OK)
+ return JIM_ERR;
+ } else if (argc == 3) {
+ if (Jim_GetWideExpr(interp, argv[1], &min) != JIM_OK ||
+ Jim_GetWideExpr(interp, argv[2], &max) != JIM_OK)
+ return JIM_ERR;
+ }
+ len = max-min;
+ if (len < 0) {
+ Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
+ return JIM_ERR;
+ }
+ maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
+ while (1) {
+ jim_wide r;
+
+ JimRandomBytes(interp, &r, sizeof(jim_wide));
+ if (r < 0 || r >= maxMul) continue;
+ r = (len == 0) ? 0 : r%len;
+ Jim_SetResultInt(interp, min+r);
+ return JIM_OK;
+ }
+}
+
+static const struct {
+ const char *name;
+ Jim_CmdProc *cmdProc;
+} Jim_CoreCommandsTable[] = {
+ {"alias", Jim_AliasCoreCommand},
+ {"set", Jim_SetCoreCommand},
+ {"unset", Jim_UnsetCoreCommand},
+ {"puts", Jim_PutsCoreCommand},
+ {"+", Jim_AddCoreCommand},
+ {"*", Jim_MulCoreCommand},
+ {"-", Jim_SubCoreCommand},
+ {"/", Jim_DivCoreCommand},
+ {"incr", Jim_IncrCoreCommand},
+ {"while", Jim_WhileCoreCommand},
+ {"loop", Jim_LoopCoreCommand},
+ {"for", Jim_ForCoreCommand},
+ {"foreach", Jim_ForeachCoreCommand},
+ {"lmap", Jim_LmapCoreCommand},
+ {"lassign", Jim_LassignCoreCommand},
+ {"if", Jim_IfCoreCommand},
+ {"switch", Jim_SwitchCoreCommand},
+ {"list", Jim_ListCoreCommand},
+ {"lindex", Jim_LindexCoreCommand},
+ {"lset", Jim_LsetCoreCommand},
+ {"lsearch", Jim_LsearchCoreCommand},
+ {"llength", Jim_LlengthCoreCommand},
+ {"lappend", Jim_LappendCoreCommand},
+ {"linsert", Jim_LinsertCoreCommand},
+ {"lreplace", Jim_LreplaceCoreCommand},
+ {"lsort", Jim_LsortCoreCommand},
+ {"append", Jim_AppendCoreCommand},
+ {"eval", Jim_EvalCoreCommand},
+ {"uplevel", Jim_UplevelCoreCommand},
+ {"expr", Jim_ExprCoreCommand},
+ {"break", Jim_BreakCoreCommand},
+ {"continue", Jim_ContinueCoreCommand},
+ {"proc", Jim_ProcCoreCommand},
+ {"xtrace", Jim_XtraceCoreCommand},
+ {"concat", Jim_ConcatCoreCommand},
+ {"return", Jim_ReturnCoreCommand},
+ {"upvar", Jim_UpvarCoreCommand},
+ {"global", Jim_GlobalCoreCommand},
+ {"string", Jim_StringCoreCommand},
+ {"time", Jim_TimeCoreCommand},
+ {"timerate", Jim_TimeRateCoreCommand},
+ {"exit", Jim_ExitCoreCommand},
+ {"catch", Jim_CatchCoreCommand},
+ {"try", Jim_TryCoreCommand},
+#ifdef JIM_REFERENCES
+ {"ref", Jim_RefCoreCommand},
+ {"getref", Jim_GetrefCoreCommand},
+ {"setref", Jim_SetrefCoreCommand},
+ {"finalize", Jim_FinalizeCoreCommand},
+ {"collect", Jim_CollectCoreCommand},
+#endif
+ {"rename", Jim_RenameCoreCommand},
+ {"dict", Jim_DictCoreCommand},
+ {"subst", Jim_SubstCoreCommand},
+ {"info", Jim_InfoCoreCommand},
+ {"exists", Jim_ExistsCoreCommand},
+ {"split", Jim_SplitCoreCommand},
+ {"join", Jim_JoinCoreCommand},
+ {"format", Jim_FormatCoreCommand},
+ {"scan", Jim_ScanCoreCommand},
+ {"error", Jim_ErrorCoreCommand},
+ {"lrange", Jim_LrangeCoreCommand},
+ {"lrepeat", Jim_LrepeatCoreCommand},
+ {"env", Jim_EnvCoreCommand},
+ {"source", Jim_SourceCoreCommand},
+ {"lreverse", Jim_LreverseCoreCommand},
+ {"range", Jim_RangeCoreCommand},
+ {"rand", Jim_RandCoreCommand},
+ {"tailcall", Jim_TailcallCoreCommand},
+ {"local", Jim_LocalCoreCommand},
+ {"upcall", Jim_UpcallCoreCommand},
+ {"apply", Jim_ApplyCoreCommand},
+ {"stacktrace", Jim_StacktraceCoreCommand},
+ {NULL, NULL},
+};
+
+void Jim_RegisterCoreCommands(Jim_Interp *interp)
+{
+ int i = 0;
+
+ while (Jim_CoreCommandsTable[i].name != NULL) {
+ Jim_CreateCommand(interp,
+ Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL);
+ i++;
+ }
+}
+
+void Jim_MakeErrorMessage(Jim_Interp *interp)
+{
+ Jim_Obj *argv[2];
+
+ argv[0] = Jim_NewStringObj(interp, "errorInfo", -1);
+ argv[1] = interp->result;
+
+ Jim_EvalObjVector(interp, 2, argv);
+}
+
+static char **JimSortStringTable(const char *const *tablePtr)
+{
+ int count;
+ char **tablePtrSorted;
+
+
+ for (count = 0; tablePtr[count]; count++) {
+ }
+
+
+ tablePtrSorted = Jim_Alloc(sizeof(char *) * (count + 1));
+ memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
+ qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
+ tablePtrSorted[count] = NULL;
+
+ return tablePtrSorted;
+}
+
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+ const char *prefix, const char *const *tablePtr, const char *name)
+{
+ char **tablePtrSorted;
+ int i;
+
+ if (name == NULL) {
+ name = "option";
+ }
+
+ Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
+ tablePtrSorted = JimSortStringTable(tablePtr);
+ for (i = 0; tablePtrSorted[i]; i++) {
+ if (tablePtrSorted[i + 1] == NULL && i > 0) {
+ Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
+ }
+ Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
+ if (tablePtrSorted[i + 1]) {
+ Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
+ }
+ }
+ Jim_Free(tablePtrSorted);
+}
+
+
+int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr)
+{
+ if (Jim_CompareStringImmediate(interp, objPtr, "-commands")) {
+ int i;
+ char **tablePtrSorted = JimSortStringTable(tablePtr);
+ Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+ for (i = 0; tablePtrSorted[i]; i++) {
+ Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, tablePtrSorted[i], -1));
+ }
+ Jim_Free(tablePtrSorted);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+static const Jim_ObjType getEnumObjType = {
+ "get-enum",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES
+};
+
+int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
+ const char *const *tablePtr, int *indexPtr, const char *name, int flags)
+{
+ const char *bad = "bad ";
+ const char *const *entryPtr = NULL;
+ int i;
+ int match = -1;
+ int arglen;
+ const char *arg;
+
+ if (objPtr->typePtr == &getEnumObjType) {
+ if (objPtr->internalRep.ptrIntValue.ptr == tablePtr && objPtr->internalRep.ptrIntValue.int1 == flags) {
+ *indexPtr = objPtr->internalRep.ptrIntValue.int2;
+ return JIM_OK;
+ }
+ }
+
+ arg = Jim_GetString(objPtr, &arglen);
+
+ *indexPtr = -1;
+
+ for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
+ if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
+
+ match = i;
+ goto found;
+ }
+ if (flags & JIM_ENUM_ABBREV) {
+ if (strncmp(arg, *entryPtr, arglen) == 0) {
+ if (*arg == '-' && arglen == 1) {
+ break;
+ }
+ if (match >= 0) {
+ bad = "ambiguous ";
+ goto ambiguous;
+ }
+ match = i;
+ }
+ }
+ }
+
+
+ if (match >= 0) {
+ found:
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &getEnumObjType;
+ objPtr->internalRep.ptrIntValue.ptr = (void *)tablePtr;
+ objPtr->internalRep.ptrIntValue.int1 = flags;
+ objPtr->internalRep.ptrIntValue.int2 = match;
+
+ *indexPtr = match;
+ return JIM_OK;
+ }
+
+ ambiguous:
+ if (flags & JIM_ERRMSG) {
+ JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name);
+ }
+ return JIM_ERR;
+}
+
+int Jim_FindByName(const char *name, const char * const array[], size_t len)
+{
+ int i;
+
+ for (i = 0; i < (int)len; i++) {
+ if (array[i] && strcmp(array[i], name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int Jim_IsDict(Jim_Obj *objPtr)
+{
+ return objPtr->typePtr == &dictObjType;
+}
+
+int Jim_IsList(Jim_Obj *objPtr)
+{
+ return objPtr->typePtr == &listObjType;
+}
+
+void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
+{
+
+ int len = strlen(format);
+ int extra = 0;
+ int n = 0;
+ const char *params[5];
+ int nobjparam = 0;
+ Jim_Obj *objparam[5];
+ char *buf;
+ va_list args;
+ int i;
+
+ va_start(args, format);
+
+ for (i = 0; i < len && n < 5; i++) {
+ int l;
+
+ if (strncmp(format + i, "%s", 2) == 0) {
+ params[n] = va_arg(args, char *);
+
+ l = strlen(params[n]);
+ }
+ else if (strncmp(format + i, "%#s", 3) == 0) {
+ Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
+
+ params[n] = Jim_GetString(objPtr, &l);
+ objparam[nobjparam++] = objPtr;
+ Jim_IncrRefCount(objPtr);
+ }
+ else {
+ if (format[i] == '%') {
+ i++;
+ }
+ continue;
+ }
+ n++;
+ extra += l;
+ }
+
+ len += extra;
+ buf = Jim_Alloc(len + 1);
+ len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
+
+ va_end(args);
+
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+
+ for (i = 0; i < nobjparam; i++) {
+ Jim_DecrRefCount(interp, objparam[i]);
+ }
+}
+
+int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version)
+{
+ if (abi_version != JIM_ABI_VERSION) {
+ Jim_SetResultString(interp, "ABI version mismatch", -1);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+
+#ifndef jim_ext_package
+int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
+{
+ return JIM_OK;
+}
+#endif
+#ifndef jim_ext_aio
+int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
+{
+ return -1;
+}
+#endif
+
+
+#include <stdio.h>
+#include <string.h>
+
+
+static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+
+ return JIM_OK;
+}
+
+static const jim_subcmd_type dummy_subcmd = {
+ "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
+};
+
+static Jim_Obj *subcmd_cmd_list(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
+{
+
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_Obj *sortCmd[2];
+
+ for (; ct->cmd; ct++) {
+ if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, ct->cmd, -1));
+ }
+ }
+
+
+ sortCmd[0] = Jim_NewStringObj(interp, "lsort", -1);
+ sortCmd[1] = listObj;
+
+ if (Jim_EvalObjVector(interp, 2, sortCmd) == JIM_OK) {
+ return Jim_ListJoin(interp, Jim_GetResult(interp), sep, strlen(sep));
+ }
+
+ return Jim_GetResult(interp);
+}
+
+static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
+ Jim_Obj *cmd, Jim_Obj *subcmd)
+{
+ Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be %#s", cmd, type,
+ subcmd, subcmd_cmd_list(interp, command_table, ", "));
+}
+
+static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
+ Jim_Obj *const *argv)
+{
+ Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: %#s",
+ argv[0], subcmd_cmd_list(interp, command_table, ", "));
+}
+
+static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
+{
+ if (cmd) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL);
+ }
+ Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL);
+ if (ct->args && *ct->args) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
+ }
+}
+
+void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *subcmd)
+{
+ Jim_SetResultString(interp, "wrong # args: should be \"", -1);
+ add_cmd_usage(interp, ct, subcmd);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+}
+
+static const Jim_ObjType subcmdLookupObjType = {
+ "subcmd-lookup",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES
+};
+
+const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
+ int argc, Jim_Obj *const *argv)
+{
+ const jim_subcmd_type *ct;
+ const jim_subcmd_type *partial = 0;
+ int cmdlen;
+ Jim_Obj *cmd;
+ const char *cmdstr;
+ int help = 0;
+ int argsok = 1;
+
+ if (argc < 2) {
+ Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s command ...\"\n"
+ "Use \"%#s -help ?command?\" for help", argv[0], argv[0]);
+ return 0;
+ }
+
+ cmd = argv[1];
+
+
+ if (cmd->typePtr == &subcmdLookupObjType) {
+ if (cmd->internalRep.ptrIntValue.ptr == command_table) {
+ ct = command_table + cmd->internalRep.ptrIntValue.int1;
+ goto found;
+ }
+ }
+
+
+ if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
+ if (argc == 2) {
+
+ show_cmd_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+ help = 1;
+
+
+ cmd = argv[2];
+ }
+
+
+ if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
+ Jim_SetResult(interp, subcmd_cmd_list(interp, command_table, " "));
+ return &dummy_subcmd;
+ }
+
+ cmdstr = Jim_GetString(cmd, &cmdlen);
+
+ for (ct = command_table; ct->cmd; ct++) {
+ if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
+
+ break;
+ }
+ if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
+ if (partial) {
+
+ if (help) {
+
+ show_cmd_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+ bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
+ return 0;
+ }
+ partial = ct;
+ }
+ continue;
+ }
+
+
+ if (partial && !ct->cmd) {
+ ct = partial;
+ }
+
+ if (!ct->cmd) {
+
+ if (help) {
+
+ show_cmd_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+ bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
+ return 0;
+ }
+
+ if (help) {
+ Jim_SetResultString(interp, "Usage: ", -1);
+
+ add_cmd_usage(interp, ct, argv[0]);
+ return &dummy_subcmd;
+ }
+
+
+ Jim_FreeIntRep(interp, cmd);
+ cmd->typePtr = &subcmdLookupObjType;
+ cmd->internalRep.ptrIntValue.ptr = (void *)command_table;
+ cmd->internalRep.ptrIntValue.int1 = ct - command_table;
+
+found:
+
+
+ if (argc - 2 < ct->minargs) {
+ argsok = 0;
+ }
+ else if (ct->maxargs >= 0 && argc - 2 > ct->maxargs) {
+ argsok = 0;
+ }
+ else if (ct->maxargs < -1 && (argc - 2) % -ct->maxargs != 0) {
+
+ argsok = 0;
+ }
+ if (!argsok) {
+ Jim_SetResultString(interp, "wrong # args: should be \"", -1);
+
+ add_cmd_usage(interp, ct, argv[0]);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+
+ return 0;
+ }
+
+
+ return ct;
+}
+
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
+{
+ int ret = JIM_ERR;
+
+ if (ct) {
+ if (ct->flags & JIM_MODFLAG_FULLARGV) {
+ ret = ct->function(interp, argc, argv);
+ }
+ else {
+ ret = ct->function(interp, argc - 2, argv + 2);
+ }
+ if (ret < 0) {
+ Jim_SubCmdArgError(interp, ct, argv[0]);
+ ret = JIM_ERR;
+ }
+ }
+ return ret;
+}
+
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const jim_subcmd_type *ct =
+ Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
+
+ return Jim_CallSubCmd(interp, ct, argc, argv);
+}
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+
+int utf8_fromunicode(char *p, unsigned uc)
+{
+ if (uc <= 0x7f) {
+ *p = uc;
+ return 1;
+ }
+ else if (uc <= 0x7ff) {
+ *p++ = 0xc0 | ((uc & 0x7c0) >> 6);
+ *p = 0x80 | (uc & 0x3f);
+ return 2;
+ }
+ else if (uc <= 0xffff) {
+ *p++ = 0xe0 | ((uc & 0xf000) >> 12);
+ *p++ = 0x80 | ((uc & 0xfc0) >> 6);
+ *p = 0x80 | (uc & 0x3f);
+ return 3;
+ }
+
+ else {
+ *p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
+ *p++ = 0x80 | ((uc & 0x3f000) >> 12);
+ *p++ = 0x80 | ((uc & 0xfc0) >> 6);
+ *p = 0x80 | (uc & 0x3f);
+ return 4;
+ }
+}
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#define JIM_INTEGER_SPACE 24
+#define MAX_FLOAT_WIDTH 320
+
+Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
+{
+ const char *span, *format, *formatEnd, *msg;
+ int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
+ static const char * const mixedXPG =
+ "cannot mix \"%\" and \"%n$\" conversion specifiers";
+ static const char * const badIndex[2] = {
+ "not enough arguments for all format specifiers",
+ "\"%n$\" argument index out of range"
+ };
+ int formatLen;
+ Jim_Obj *resultPtr;
+
+ char *num_buffer = NULL;
+ int num_buffer_size = 0;
+
+ span = format = Jim_GetString(fmtObjPtr, &formatLen);
+ formatEnd = format + formatLen;
+ resultPtr = Jim_NewEmptyStringObj(interp);
+
+ while (format != formatEnd) {
+ char *end;
+ int gotMinus, sawFlag;
+ int gotPrecision, useShort;
+ long width, precision;
+ int newXpg;
+ int ch;
+ int step;
+ int doubleType;
+ char pad = ' ';
+ char spec[2*JIM_INTEGER_SPACE + 12];
+ char *p;
+
+ int formatted_chars;
+ int formatted_bytes;
+ const char *formatted_buf;
+
+ step = utf8_tounicode(format, &ch);
+ format += step;
+ if (ch != '%') {
+ numBytes += step;
+ continue;
+ }
+ if (numBytes) {
+ Jim_AppendString(interp, resultPtr, span, numBytes);
+ numBytes = 0;
+ }
+
+
+ step = utf8_tounicode(format, &ch);
+ if (ch == '%') {
+ span = format;
+ numBytes = step;
+ format += step;
+ continue;
+ }
+
+
+ newXpg = 0;
+ if (isdigit(ch)) {
+ int position = strtoul(format, &end, 10);
+ if (*end == '$') {
+ newXpg = 1;
+ objIndex = position - 1;
+ format = end + 1;
+ step = utf8_tounicode(format, &ch);
+ }
+ }
+ if (newXpg) {
+ if (gotSequential) {
+ msg = mixedXPG;
+ goto errorMsg;
+ }
+ gotXpg = 1;
+ } else {
+ if (gotXpg) {
+ msg = mixedXPG;
+ goto errorMsg;
+ }
+ gotSequential = 1;
+ }
+ if ((objIndex < 0) || (objIndex >= objc)) {
+ msg = badIndex[gotXpg];
+ goto errorMsg;
+ }
+
+ p = spec;
+ *p++ = '%';
+
+ gotMinus = 0;
+ sawFlag = 1;
+ do {
+ switch (ch) {
+ case '-':
+ gotMinus = 1;
+ break;
+ case '0':
+ pad = ch;
+ break;
+ case ' ':
+ case '+':
+ case '#':
+ break;
+ default:
+ sawFlag = 0;
+ continue;
+ }
+ *p++ = ch;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+
+ } while (sawFlag && (p - spec <= 5));
+
+
+ width = 0;
+ if (isdigit(ch)) {
+ width = strtoul(format, &end, 10);
+ format = end;
+ step = utf8_tounicode(format, &ch);
+ } else if (ch == '*') {
+ if (objIndex >= objc - 1) {
+ msg = badIndex[gotXpg];
+ goto errorMsg;
+ }
+ if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
+ goto error;
+ }
+ if (width < 0) {
+ width = -width;
+ if (!gotMinus) {
+ *p++ = '-';
+ gotMinus = 1;
+ }
+ }
+ objIndex++;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+
+
+ gotPrecision = precision = 0;
+ if (ch == '.') {
+ gotPrecision = 1;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+ if (isdigit(ch)) {
+ precision = strtoul(format, &end, 10);
+ format = end;
+ step = utf8_tounicode(format, &ch);
+ } else if (ch == '*') {
+ if (objIndex >= objc - 1) {
+ msg = badIndex[gotXpg];
+ goto errorMsg;
+ }
+ if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
+ goto error;
+ }
+
+
+ if (precision < 0) {
+ precision = 0;
+ }
+ objIndex++;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+
+
+ useShort = 0;
+ if (ch == 'h') {
+ useShort = 1;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ } else if (ch == 'l') {
+
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ if (ch == 'l') {
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+ }
+
+ format += step;
+ span = format;
+
+
+ if (ch == 'i') {
+ ch = 'd';
+ }
+
+ doubleType = 0;
+
+ switch (ch) {
+ case '\0':
+ msg = "format string ended in middle of field specifier";
+ goto errorMsg;
+ case 's': {
+ formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
+ formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
+ if (gotPrecision && (precision < formatted_chars)) {
+
+ formatted_chars = precision;
+ formatted_bytes = utf8_index(formatted_buf, precision);
+ }
+ break;
+ }
+ case 'c': {
+ jim_wide code;
+
+ if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
+ goto error;
+ }
+
+ formatted_bytes = utf8_getchars(spec, code);
+ formatted_buf = spec;
+ formatted_chars = 1;
+ break;
+ }
+ case 'b': {
+ unsigned jim_wide w;
+ int length;
+ int i;
+ int j;
+
+ if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) {
+ goto error;
+ }
+ length = sizeof(w) * 8;
+
+
+
+ if (num_buffer_size < length + 1) {
+ num_buffer_size = length + 1;
+ num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
+ }
+
+ j = 0;
+ for (i = length; i > 0; ) {
+ i--;
+ if (w & ((unsigned jim_wide)1 << i)) {
+ num_buffer[j++] = '1';
+ }
+ else if (j || i == 0) {
+ num_buffer[j++] = '0';
+ }
+ }
+ num_buffer[j] = 0;
+ formatted_chars = formatted_bytes = j;
+ formatted_buf = num_buffer;
+ break;
+ }
+
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ doubleType = 1;
+
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X': {
+ jim_wide w;
+ double d;
+ int length;
+
+
+ if (width) {
+ p += sprintf(p, "%ld", width);
+ }
+ if (gotPrecision) {
+ p += sprintf(p, ".%ld", precision);
+ }
+
+
+ if (doubleType) {
+ if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
+ goto error;
+ }
+ length = MAX_FLOAT_WIDTH;
+ }
+ else {
+ if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
+ goto error;
+ }
+ length = JIM_INTEGER_SPACE;
+ if (useShort) {
+ if (ch == 'd') {
+ w = (short)w;
+ }
+ else {
+ w = (unsigned short)w;
+ }
+ }
+ *p++ = 'l';
+#ifdef HAVE_LONG_LONG
+ if (sizeof(long long) == sizeof(jim_wide)) {
+ *p++ = 'l';
+ }
+#endif
+ }
+
+ *p++ = (char) ch;
+ *p = '\0';
+
+
+ if (width > 10000 || length > 10000 || precision > 10000) {
+ Jim_SetResultString(interp, "format too long", -1);
+ goto error;
+ }
+
+
+
+ if (width > length) {
+ length = width;
+ }
+ if (gotPrecision) {
+ length += precision;
+ }
+
+
+ if (num_buffer_size < length + 1) {
+ num_buffer_size = length + 1;
+ num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
+ }
+
+ if (doubleType) {
+ snprintf(num_buffer, length + 1, spec, d);
+ }
+ else {
+ formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
+ }
+ formatted_chars = formatted_bytes = strlen(num_buffer);
+ formatted_buf = num_buffer;
+ break;
+ }
+
+ default: {
+
+ spec[0] = ch;
+ spec[1] = '\0';
+ Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
+ goto error;
+ }
+ }
+
+ if (!gotMinus) {
+ while (formatted_chars < width) {
+ Jim_AppendString(interp, resultPtr, &pad, 1);
+ formatted_chars++;
+ }
+ }
+
+ Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
+
+ while (formatted_chars < width) {
+ Jim_AppendString(interp, resultPtr, &pad, 1);
+ formatted_chars++;
+ }
+
+ objIndex += gotSequential;
+ }
+ if (numBytes) {
+ Jim_AppendString(interp, resultPtr, span, numBytes);
+ }
+
+ Jim_Free(num_buffer);
+ return resultPtr;
+
+ errorMsg:
+ Jim_SetResultString(interp, msg, -1);
+ error:
+ Jim_FreeNewObj(interp, resultPtr);
+ Jim_Free(num_buffer);
+ return NULL;
+}
+
+
+#if defined(JIM_REGEXP)
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+#define REG_MAX_PAREN 100
+
+
+
+#define END 0
+#define BOL 1
+#define EOL 2
+#define ANY 3
+#define ANYOF 4
+#define ANYBUT 5
+#define BRANCH 6
+#define BACK 7
+#define EXACTLY 8
+#define NOTHING 9
+#define REP 10
+#define REPMIN 11
+#define REPX 12
+#define REPXMIN 13
+#define BOLX 14
+#define EOLX 15
+#define WORDA 16
+#define WORDZ 17
+
+#define OPENNC 1000
+#define OPEN 1001
+
+
+
+
+#define CLOSENC 2000
+#define CLOSE 2001
+#define CLOSE_END (CLOSE+REG_MAX_PAREN)
+
+#define REG_MAGIC 0xFADED00D
+
+
+#define OP(preg, p) (preg->program[p])
+#define NEXT(preg, p) (preg->program[p + 1])
+#define OPERAND(p) ((p) + 2)
+
+
+
+
+#define FAIL(R,M) { (R)->err = (M); return (M); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
+#define META "^$.[()|?{+*"
+
+#define HASWIDTH 1
+#define SIMPLE 2
+#define SPSTART 4
+#define WORST 0
+
+#define MAX_REP_COUNT 1000000
+
+static int reg(regex_t *preg, int paren, int *flagp );
+static int regpiece(regex_t *preg, int *flagp );
+static int regbranch(regex_t *preg, int *flagp );
+static int regatom(regex_t *preg, int *flagp );
+static int regnode(regex_t *preg, int op );
+static int regnext(regex_t *preg, int p );
+static void regc(regex_t *preg, int b );
+static int reginsert(regex_t *preg, int op, int size, int opnd );
+static void regtail(regex_t *preg, int p, int val);
+static void regoptail(regex_t *preg, int p, int val );
+static int regopsize(regex_t *preg, int p );
+
+static int reg_range_find(const int *string, int c);
+static const char *str_find(const char *string, int c, int nocase);
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
+
+
+#ifdef DEBUG
+static int regnarrate = 0;
+static void regdump(regex_t *preg);
+static const char *regprop( int op );
+#endif
+
+
+static int str_int_len(const int *seq)
+{
+ int n = 0;
+ while (*seq++) {
+ n++;
+ }
+ return n;
+}
+
+int jim_regcomp(regex_t *preg, const char *exp, int cflags)
+{
+ int scan;
+ int longest;
+ unsigned len;
+ int flags;
+
+#ifdef DEBUG
+ fprintf(stderr, "Compiling: '%s'\n", exp);
+#endif
+ memset(preg, 0, sizeof(*preg));
+
+ if (exp == NULL)
+ FAIL(preg, REG_ERR_NULL_ARGUMENT);
+
+
+ preg->cflags = cflags;
+ preg->regparse = exp;
+
+
+ preg->proglen = (strlen(exp) + 1) * 5;
+ preg->program = malloc(preg->proglen * sizeof(int));
+ if (preg->program == NULL)
+ FAIL(preg, REG_ERR_NOMEM);
+
+ regc(preg, REG_MAGIC);
+ if (reg(preg, 0, &flags) == 0) {
+ return preg->err;
+ }
+
+
+ if (preg->re_nsub >= REG_MAX_PAREN)
+ FAIL(preg,REG_ERR_TOO_BIG);
+
+
+ preg->regstart = 0;
+ preg->reganch = 0;
+ preg->regmust = 0;
+ preg->regmlen = 0;
+ scan = 1;
+ if (OP(preg, regnext(preg, scan)) == END) {
+ scan = OPERAND(scan);
+
+
+ if (OP(preg, scan) == EXACTLY) {
+ preg->regstart = preg->program[OPERAND(scan)];
+ }
+ else if (OP(preg, scan) == BOL)
+ preg->reganch++;
+
+ if (flags&SPSTART) {
+ longest = 0;
+ len = 0;
+ for (; scan != 0; scan = regnext(preg, scan)) {
+ if (OP(preg, scan) == EXACTLY) {
+ int plen = str_int_len(preg->program + OPERAND(scan));
+ if (plen >= len) {
+ longest = OPERAND(scan);
+ len = plen;
+ }
+ }
+ }
+ preg->regmust = longest;
+ preg->regmlen = len;
+ }
+ }
+
+#ifdef DEBUG
+ regdump(preg);
+#endif
+
+ return 0;
+}
+
+static int reg(regex_t *preg, int paren, int *flagp )
+{
+ int ret;
+ int br;
+ int ender;
+ int parno = 0;
+ int flags;
+
+ *flagp = HASWIDTH;
+
+
+ if (paren) {
+ if (preg->regparse[0] == '?' && preg->regparse[1] == ':') {
+
+ preg->regparse += 2;
+ parno = -1;
+ }
+ else {
+ parno = ++preg->re_nsub;
+ }
+ ret = regnode(preg, OPEN+parno);
+ } else
+ ret = 0;
+
+
+ br = regbranch(preg, &flags);
+ if (br == 0)
+ return 0;
+ if (ret != 0)
+ regtail(preg, ret, br);
+ else
+ ret = br;
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ while (*preg->regparse == '|') {
+ preg->regparse++;
+ br = regbranch(preg, &flags);
+ if (br == 0)
+ return 0;
+ regtail(preg, ret, br);
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ }
+
+
+ ender = regnode(preg, (paren) ? CLOSE+parno : END);
+ regtail(preg, ret, ender);
+
+
+ for (br = ret; br != 0; br = regnext(preg, br))
+ regoptail(preg, br, ender);
+
+
+ if (paren && *preg->regparse++ != ')') {
+ preg->err = REG_ERR_UNMATCHED_PAREN;
+ return 0;
+ } else if (!paren && *preg->regparse != '\0') {
+ if (*preg->regparse == ')') {
+ preg->err = REG_ERR_UNMATCHED_PAREN;
+ return 0;
+ } else {
+ preg->err = REG_ERR_JUNK_ON_END;
+ return 0;
+ }
+ }
+
+ return(ret);
+}
+
+static int regbranch(regex_t *preg, int *flagp )
+{
+ int ret;
+ int chain;
+ int latest;
+ int flags;
+
+ *flagp = WORST;
+
+ ret = regnode(preg, BRANCH);
+ chain = 0;
+ while (*preg->regparse != '\0' && *preg->regparse != ')' &&
+ *preg->regparse != '|') {
+ latest = regpiece(preg, &flags);
+ if (latest == 0)
+ return 0;
+ *flagp |= flags&HASWIDTH;
+ if (chain == 0) {
+ *flagp |= flags&SPSTART;
+ }
+ else {
+ regtail(preg, chain, latest);
+ }
+ chain = latest;
+ }
+ if (chain == 0)
+ (void) regnode(preg, NOTHING);
+
+ return(ret);
+}
+
+static int regpiece(regex_t *preg, int *flagp)
+{
+ int ret;
+ char op;
+ int next;
+ int flags;
+ int min;
+ int max;
+
+ ret = regatom(preg, &flags);
+ if (ret == 0)
+ return 0;
+
+ op = *preg->regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+
+ if (!(flags&HASWIDTH) && op != '?') {
+ preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
+ return 0;
+ }
+
+
+ if (op == '{') {
+ char *end;
+
+ min = strtoul(preg->regparse + 1, &end, 10);
+ if (end == preg->regparse + 1) {
+ preg->err = REG_ERR_BAD_COUNT;
+ return 0;
+ }
+ if (*end == '}') {
+ max = min;
+ }
+ else if (*end == '\0') {
+ preg->err = REG_ERR_UNMATCHED_BRACES;
+ return 0;
+ }
+ else {
+ preg->regparse = end;
+ max = strtoul(preg->regparse + 1, &end, 10);
+ if (*end != '}') {
+ preg->err = REG_ERR_UNMATCHED_BRACES;
+ return 0;
+ }
+ }
+ if (end == preg->regparse + 1) {
+ max = MAX_REP_COUNT;
+ }
+ else if (max < min || max >= 100) {
+ preg->err = REG_ERR_BAD_COUNT;
+ return 0;
+ }
+ if (min >= 100) {
+ preg->err = REG_ERR_BAD_COUNT;
+ return 0;
+ }
+
+ preg->regparse = strchr(preg->regparse, '}');
+ }
+ else {
+ min = (op == '+');
+ max = (op == '?' ? 1 : MAX_REP_COUNT);
+ }
+
+ if (preg->regparse[1] == '?') {
+ preg->regparse++;
+ next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
+ }
+ else {
+ next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
+ }
+ preg->program[ret + 2] = max;
+ preg->program[ret + 3] = min;
+ preg->program[ret + 4] = 0;
+
+ *flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
+
+ if (!(flags & SIMPLE)) {
+ int back = regnode(preg, BACK);
+ regtail(preg, back, ret);
+ regtail(preg, next, back);
+ }
+
+ preg->regparse++;
+ if (ISMULT(*preg->regparse)) {
+ preg->err = REG_ERR_NESTED_COUNT;
+ return 0;
+ }
+
+ return ret;
+}
+
+static void reg_addrange(regex_t *preg, int lower, int upper)
+{
+ if (lower > upper) {
+ reg_addrange(preg, upper, lower);
+ }
+
+ regc(preg, upper - lower + 1);
+ regc(preg, lower);
+}
+
+static void reg_addrange_str(regex_t *preg, const char *str)
+{
+ while (*str) {
+ reg_addrange(preg, *str, *str);
+ str++;
+ }
+}
+
+static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+ int l = utf8_tounicode(s, uc);
+ if (upper) {
+ *uc = utf8_upper(*uc);
+ }
+ return l;
+}
+
+static int hexdigitval(int 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;
+}
+
+static int parse_hex(const char *s, int n, int *uc)
+{
+ int val = 0;
+ int k;
+
+ for (k = 0; k < n; k++) {
+ int c = hexdigitval(*s++);
+ if (c == -1) {
+ break;
+ }
+ val = (val << 4) | c;
+ }
+ if (k) {
+ *uc = val;
+ }
+ return k;
+}
+
+static int reg_decode_escape(const char *s, int *ch)
+{
+ int n;
+ const char *s0 = s;
+
+ *ch = *s++;
+
+ switch (*ch) {
+ case 'b': *ch = '\b'; break;
+ case 'e': *ch = 27; break;
+ case 'f': *ch = '\f'; break;
+ case 'n': *ch = '\n'; break;
+ case 'r': *ch = '\r'; break;
+ case 't': *ch = '\t'; break;
+ case 'v': *ch = '\v'; break;
+ case 'u':
+ if (*s == '{') {
+
+ n = parse_hex(s + 1, 6, ch);
+ if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) {
+ s += n + 2;
+ }
+ else {
+
+ *ch = 'u';
+ }
+ }
+ else if ((n = parse_hex(s, 4, ch)) > 0) {
+ s += n;
+ }
+ break;
+ case 'U':
+ if ((n = parse_hex(s, 8, ch)) > 0) {
+ s += n;
+ }
+ break;
+ case 'x':
+ if ((n = parse_hex(s, 2, ch)) > 0) {
+ s += n;
+ }
+ break;
+ case '\0':
+ s--;
+ *ch = '\\';
+ break;
+ }
+ return s - s0;
+}
+
+static int regatom(regex_t *preg, int *flagp)
+{
+ int ret;
+ int flags;
+ int nocase = (preg->cflags & REG_ICASE);
+
+ int ch;
+ int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
+
+ *flagp = WORST;
+
+ preg->regparse += n;
+ switch (ch) {
+
+ case '^':
+ ret = regnode(preg, BOL);
+ break;
+ case '$':
+ ret = regnode(preg, EOL);
+ break;
+ case '.':
+ ret = regnode(preg, ANY);
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '[': {
+ const char *pattern = preg->regparse;
+
+ if (*pattern == '^') {
+ ret = regnode(preg, ANYBUT);
+ pattern++;
+ } else
+ ret = regnode(preg, ANYOF);
+
+
+ if (*pattern == ']' || *pattern == '-') {
+ reg_addrange(preg, *pattern, *pattern);
+ pattern++;
+ }
+
+ while (*pattern != ']') {
+
+ int start;
+ int end;
+
+ enum {
+ CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER,
+ CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT,
+ CC_NUM
+ };
+ int cc;
+
+ if (!*pattern) {
+ preg->err = REG_ERR_UNMATCHED_BRACKET;
+ return 0;
+ }
+
+ pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
+ if (start == '\\') {
+
+ switch (*pattern) {
+ case 's':
+ pattern++;
+ cc = CC_SPACE;
+ goto cc_switch;
+ case 'd':
+ pattern++;
+ cc = CC_DIGIT;
+ goto cc_switch;
+ case 'w':
+ pattern++;
+ reg_addrange(preg, '_', '_');
+ cc = CC_ALNUM;
+ goto cc_switch;
+ }
+ pattern += reg_decode_escape(pattern, &start);
+ if (start == 0) {
+ preg->err = REG_ERR_NULL_CHAR;
+ return 0;
+ }
+ if (start == '\\' && *pattern == 0) {
+ preg->err = REG_ERR_INVALID_ESCAPE;
+ return 0;
+ }
+ }
+ if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {
+
+ pattern += utf8_tounicode(pattern, &end);
+ pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
+ if (end == '\\') {
+ pattern += reg_decode_escape(pattern, &end);
+ if (end == 0) {
+ preg->err = REG_ERR_NULL_CHAR;
+ return 0;
+ }
+ if (end == '\\' && *pattern == 0) {
+ preg->err = REG_ERR_INVALID_ESCAPE;
+ return 0;
+ }
+ }
+
+ reg_addrange(preg, start, end);
+ continue;
+ }
+ if (start == '[' && pattern[0] == ':') {
+ static const char *character_class[] = {
+ ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
+ ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
+ };
+
+ for (cc = 0; cc < CC_NUM; cc++) {
+ n = strlen(character_class[cc]);
+ if (strncmp(pattern, character_class[cc], n) == 0) {
+ if (pattern[n] != ']') {
+ preg->err = REG_ERR_UNMATCHED_BRACKET;
+ return 0;
+ }
+
+ pattern += n + 1;
+ break;
+ }
+ }
+ if (cc != CC_NUM) {
+cc_switch:
+ switch (cc) {
+ case CC_ALNUM:
+ reg_addrange(preg, '0', '9');
+
+ case CC_ALPHA:
+ if ((preg->cflags & REG_ICASE) == 0) {
+ reg_addrange(preg, 'a', 'z');
+ }
+ reg_addrange(preg, 'A', 'Z');
+ break;
+ case CC_SPACE:
+ reg_addrange_str(preg, " \t\r\n\f\v");
+ break;
+ case CC_BLANK:
+ reg_addrange_str(preg, " \t");
+ break;
+ case CC_UPPER:
+ reg_addrange(preg, 'A', 'Z');
+ break;
+ case CC_LOWER:
+ reg_addrange(preg, 'a', 'z');
+ break;
+ case CC_XDIGIT:
+ reg_addrange(preg, 'a', 'f');
+ reg_addrange(preg, 'A', 'F');
+
+ case CC_DIGIT:
+ reg_addrange(preg, '0', '9');
+ break;
+ case CC_CNTRL:
+ reg_addrange(preg, 0, 31);
+ reg_addrange(preg, 127, 127);
+ break;
+ case CC_PRINT:
+ reg_addrange(preg, ' ', '~');
+ break;
+ case CC_GRAPH:
+ reg_addrange(preg, '!', '~');
+ break;
+ case CC_PUNCT:
+ reg_addrange(preg, '!', '/');
+ reg_addrange(preg, ':', '@');
+ reg_addrange(preg, '[', '`');
+ reg_addrange(preg, '{', '~');
+ break;
+ }
+ continue;
+ }
+ }
+
+ reg_addrange(preg, start, start);
+ }
+ regc(preg, '\0');
+
+ if (*pattern) {
+ pattern++;
+ }
+ preg->regparse = pattern;
+
+ *flagp |= HASWIDTH|SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(preg, 1, &flags);
+ if (ret == 0)
+ return 0;
+ *flagp |= flags&(HASWIDTH|SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case ')':
+ preg->err = REG_ERR_INTERNAL;
+ return 0;
+ case '?':
+ case '+':
+ case '*':
+ case '{':
+ preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
+ return 0;
+ case '\\':
+ ch = *preg->regparse++;
+ switch (ch) {
+ case '\0':
+ preg->err = REG_ERR_INVALID_ESCAPE;
+ return 0;
+ case 'A':
+ ret = regnode(preg, BOLX);
+ break;
+ case 'Z':
+ ret = regnode(preg, EOLX);
+ break;
+ case '<':
+ case 'm':
+ ret = regnode(preg, WORDA);
+ break;
+ case '>':
+ case 'M':
+ ret = regnode(preg, WORDZ);
+ break;
+ case 'd':
+ case 'D':
+ ret = regnode(preg, ch == 'd' ? ANYOF : ANYBUT);
+ reg_addrange(preg, '0', '9');
+ regc(preg, '\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case 'w':
+ case 'W':
+ ret = regnode(preg, ch == 'w' ? ANYOF : ANYBUT);
+ if ((preg->cflags & REG_ICASE) == 0) {
+ reg_addrange(preg, 'a', 'z');
+ }
+ reg_addrange(preg, 'A', 'Z');
+ reg_addrange(preg, '0', '9');
+ reg_addrange(preg, '_', '_');
+ regc(preg, '\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case 's':
+ case 'S':
+ ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT);
+ reg_addrange_str(preg," \t\r\n\f\v");
+ regc(preg, '\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+
+ default:
+
+
+ preg->regparse--;
+ goto de_fault;
+ }
+ break;
+ de_fault:
+ default: {
+ int added = 0;
+
+
+ preg->regparse -= n;
+
+ ret = regnode(preg, EXACTLY);
+
+
+
+ while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
+ n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
+ if (ch == '\\' && preg->regparse[n]) {
+ if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) {
+
+ break;
+ }
+ n += reg_decode_escape(preg->regparse + n, &ch);
+ if (ch == 0) {
+ preg->err = REG_ERR_NULL_CHAR;
+ return 0;
+ }
+ }
+
+
+ if (ISMULT(preg->regparse[n])) {
+
+ if (added) {
+
+ break;
+ }
+
+ regc(preg, ch);
+ added++;
+ preg->regparse += n;
+ break;
+ }
+
+
+ regc(preg, ch);
+ added++;
+ preg->regparse += n;
+ }
+ regc(preg, '\0');
+
+ *flagp |= HASWIDTH;
+ if (added == 1)
+ *flagp |= SIMPLE;
+ break;
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+static void reg_grow(regex_t *preg, int n)
+{
+ if (preg->p + n >= preg->proglen) {
+ preg->proglen = (preg->p + n) * 2;
+ preg->program = realloc(preg->program, preg->proglen * sizeof(int));
+ }
+}
+
+
+static int regnode(regex_t *preg, int op)
+{
+ reg_grow(preg, 2);
+
+
+ preg->program[preg->p++] = op;
+ preg->program[preg->p++] = 0;
+
+
+ return preg->p - 2;
+}
+
+static void regc(regex_t *preg, int b )
+{
+ reg_grow(preg, 1);
+ preg->program[preg->p++] = b;
+}
+
+static int reginsert(regex_t *preg, int op, int size, int opnd )
+{
+ reg_grow(preg, size);
+
+
+ memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
+
+ memset(preg->program + opnd, 0, sizeof(int) * size);
+
+ preg->program[opnd] = op;
+
+ preg->p += size;
+
+ return opnd + size;
+}
+
+static void regtail(regex_t *preg, int p, int val)
+{
+ int scan;
+ int temp;
+ int offset;
+
+
+ scan = p;
+ for (;;) {
+ temp = regnext(preg, scan);
+ if (temp == 0)
+ break;
+ scan = temp;
+ }
+
+ if (OP(preg, scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+
+ preg->program[scan + 1] = offset;
+}
+
+
+static void regoptail(regex_t *preg, int p, int val )
+{
+
+ if (p != 0 && OP(preg, p) == BRANCH) {
+ regtail(preg, OPERAND(p), val);
+ }
+}
+
+
+static int regtry(regex_t *preg, const char *string );
+static int regmatch(regex_t *preg, int prog);
+static int regrepeat(regex_t *preg, int p, int max);
+
+int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+ const char *s;
+ int scan;
+
+
+ if (preg == NULL || preg->program == NULL || string == NULL) {
+ return REG_ERR_NULL_ARGUMENT;
+ }
+
+
+ if (*preg->program != REG_MAGIC) {
+ return REG_ERR_CORRUPTED;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "regexec: %s\n", string);
+ regdump(preg);
+#endif
+
+ preg->eflags = eflags;
+ preg->pmatch = pmatch;
+ preg->nmatch = nmatch;
+ preg->start = string;
+
+
+ for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
+ int op = OP(preg, scan);
+ if (op == END)
+ break;
+ if (op == REPX || op == REPXMIN)
+ preg->program[scan + 4] = 0;
+ }
+
+
+ if (preg->regmust != 0) {
+ s = string;
+ while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
+ if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
+ break;
+ }
+ s++;
+ }
+ if (s == NULL)
+ return REG_NOMATCH;
+ }
+
+
+ preg->regbol = string;
+
+
+ if (preg->reganch) {
+ if (eflags & REG_NOTBOL) {
+
+ goto nextline;
+ }
+ while (1) {
+ if (regtry(preg, string)) {
+ return REG_NOERROR;
+ }
+ if (*string) {
+nextline:
+ if (preg->cflags & REG_NEWLINE) {
+
+ string = strchr(string, '\n');
+ if (string) {
+ preg->regbol = ++string;
+ continue;
+ }
+ }
+ }
+ return REG_NOMATCH;
+ }
+ }
+
+
+ s = string;
+ if (preg->regstart != '\0') {
+
+ while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
+ if (regtry(preg, s))
+ return REG_NOERROR;
+ s++;
+ }
+ }
+ else
+
+ while (1) {
+ if (regtry(preg, s))
+ return REG_NOERROR;
+ if (*s == '\0') {
+ break;
+ }
+ else {
+ int c;
+ s += utf8_tounicode(s, &c);
+ }
+ }
+
+
+ return REG_NOMATCH;
+}
+
+
+static int regtry( regex_t *preg, const char *string )
+{
+ int i;
+
+ preg->reginput = string;
+
+ for (i = 0; i < preg->nmatch; i++) {
+ preg->pmatch[i].rm_so = -1;
+ preg->pmatch[i].rm_eo = -1;
+ }
+ if (regmatch(preg, 1)) {
+ preg->pmatch[0].rm_so = string - preg->start;
+ preg->pmatch[0].rm_eo = preg->reginput - preg->start;
+ return(1);
+ } else
+ return(0);
+}
+
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
+{
+ const char *s = string;
+ while (proglen && *s) {
+ int ch;
+ int n = reg_utf8_tounicode_case(s, &ch, nocase);
+ if (ch != *prog) {
+ return -1;
+ }
+ prog++;
+ s += n;
+ proglen--;
+ }
+ if (proglen == 0) {
+ return s - string;
+ }
+ return -1;
+}
+
+static int reg_range_find(const int *range, int c)
+{
+ while (*range) {
+
+ if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
+ return 1;
+ }
+ range += 2;
+ }
+ return 0;
+}
+
+static const char *str_find(const char *string, int c, int nocase)
+{
+ if (nocase) {
+
+ c = utf8_upper(c);
+ }
+ while (*string) {
+ int ch;
+ int n = reg_utf8_tounicode_case(string, &ch, nocase);
+ if (c == ch) {
+ return string;
+ }
+ string += n;
+ }
+ return NULL;
+}
+
+static int reg_iseol(regex_t *preg, int ch)
+{
+ if (preg->cflags & REG_NEWLINE) {
+ return ch == '\0' || ch == '\n';
+ }
+ else {
+ return ch == '\0';
+ }
+}
+
+static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
+{
+ int nextch = '\0';
+ const char *save;
+ int no;
+ int c;
+
+ int max = preg->program[scan + 2];
+ int min = preg->program[scan + 3];
+ int next = regnext(preg, scan);
+
+ if (OP(preg, next) == EXACTLY) {
+ nextch = preg->program[OPERAND(next)];
+ }
+ save = preg->reginput;
+ no = regrepeat(preg, scan + 5, max);
+ if (no < min) {
+ return 0;
+ }
+ if (matchmin) {
+
+ max = no;
+ no = min;
+ }
+
+ while (1) {
+ if (matchmin) {
+ if (no > max) {
+ break;
+ }
+ }
+ else {
+ if (no < min) {
+ break;
+ }
+ }
+ preg->reginput = save + utf8_index(save, no);
+ reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+
+ if (reg_iseol(preg, nextch) || c == nextch) {
+ if (regmatch(preg, next)) {
+ return(1);
+ }
+ }
+ if (matchmin) {
+
+ no++;
+ }
+ else {
+
+ no--;
+ }
+ }
+ return(0);
+}
+
+static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
+{
+ int *scanpt = preg->program + scan;
+
+ int max = scanpt[2];
+ int min = scanpt[3];
+
+
+ if (scanpt[4] < min) {
+
+ scanpt[4]++;
+ if (regmatch(preg, scan + 5)) {
+ return 1;
+ }
+ scanpt[4]--;
+ return 0;
+ }
+ if (scanpt[4] > max) {
+ return 0;
+ }
+
+ if (matchmin) {
+
+ if (regmatch(preg, regnext(preg, scan))) {
+ return 1;
+ }
+
+ scanpt[4]++;
+ if (regmatch(preg, scan + 5)) {
+ return 1;
+ }
+ scanpt[4]--;
+ return 0;
+ }
+
+ if (scanpt[4] < max) {
+ scanpt[4]++;
+ if (regmatch(preg, scan + 5)) {
+ return 1;
+ }
+ scanpt[4]--;
+ }
+
+ return regmatch(preg, regnext(preg, scan));
+}
+
+
+static int regmatch(regex_t *preg, int prog)
+{
+ int scan;
+ int next;
+ const char *save;
+
+ scan = prog;
+
+#ifdef DEBUG
+ if (scan != 0 && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != 0) {
+ int n;
+ int c;
+#ifdef DEBUG
+ if (regnarrate) {
+ fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
+ }
+#endif
+ next = regnext(preg, scan);
+ n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+
+ switch (OP(preg, scan)) {
+ case BOLX:
+ if ((preg->eflags & REG_NOTBOL)) {
+ return(0);
+ }
+
+ case BOL:
+ if (preg->reginput != preg->regbol) {
+ return(0);
+ }
+ break;
+ case EOLX:
+ if (c != 0) {
+
+ return 0;
+ }
+ break;
+ case EOL:
+ if (!reg_iseol(preg, c)) {
+ return(0);
+ }
+ break;
+ case WORDA:
+
+ if ((!isalnum(UCHAR(c))) && c != '_')
+ return(0);
+
+ if (preg->reginput > preg->regbol &&
+ (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
+ return(0);
+ break;
+ case WORDZ:
+
+ if (preg->reginput > preg->regbol) {
+
+ if (reg_iseol(preg, c) || !(isalnum(UCHAR(c)) || c == '_')) {
+ c = preg->reginput[-1];
+
+ if (isalnum(UCHAR(c)) || c == '_') {
+ break;
+ }
+ }
+ }
+
+ return(0);
+
+ case ANY:
+ if (reg_iseol(preg, c))
+ return 0;
+ preg->reginput += n;
+ break;
+ case EXACTLY: {
+ int opnd;
+ int len;
+ int slen;
+
+ opnd = OPERAND(scan);
+ len = str_int_len(preg->program + opnd);
+
+ slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
+ if (slen < 0) {
+ return(0);
+ }
+ preg->reginput += slen;
+ }
+ break;
+ case ANYOF:
+ if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
+ return(0);
+ }
+ preg->reginput += n;
+ break;
+ case ANYBUT:
+ if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
+ return(0);
+ }
+ preg->reginput += n;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case BRANCH:
+ if (OP(preg, next) != BRANCH)
+ next = OPERAND(scan);
+ else {
+ do {
+ save = preg->reginput;
+ if (regmatch(preg, OPERAND(scan))) {
+ return(1);
+ }
+ preg->reginput = save;
+ scan = regnext(preg, scan);
+ } while (scan != 0 && OP(preg, scan) == BRANCH);
+ return(0);
+
+ }
+ break;
+ case REP:
+ case REPMIN:
+ return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
+
+ case REPX:
+ case REPXMIN:
+ return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
+
+ case END:
+ return 1;
+
+ case OPENNC:
+ case CLOSENC:
+ return regmatch(preg, next);
+
+ default:
+ if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
+ save = preg->reginput;
+ if (regmatch(preg, next)) {
+ if (OP(preg, scan) < CLOSE) {
+ int no = OP(preg, scan) - OPEN;
+ if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
+ preg->pmatch[no].rm_so = save - preg->start;
+ }
+ }
+ else {
+ int no = OP(preg, scan) - CLOSE;
+ if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
+ preg->pmatch[no].rm_eo = save - preg->start;
+ }
+ }
+ return(1);
+ }
+
+ preg->reginput = save;
+ return(0);
+ }
+ return REG_ERR_INTERNAL;
+ }
+
+ scan = next;
+ }
+
+ return REG_ERR_INTERNAL;
+}
+
+static int regrepeat(regex_t *preg, int p, int max)
+{
+ int count = 0;
+ const char *scan;
+ int opnd;
+ int ch;
+ int n;
+
+ scan = preg->reginput;
+ opnd = OPERAND(p);
+ switch (OP(preg, p)) {
+ case ANY:
+ while (!reg_iseol(preg, *scan) && count < max) {
+ count++;
+ scan += utf8_charlen(*scan);
+ }
+ break;
+ case EXACTLY:
+ while (count < max) {
+ n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+ if (preg->program[opnd] != ch) {
+ break;
+ }
+ count++;
+ scan += n;
+ }
+ break;
+ case ANYOF:
+ while (count < max) {
+ n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+ if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
+ break;
+ }
+ count++;
+ scan += n;
+ }
+ break;
+ case ANYBUT:
+ while (count < max) {
+ n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+ if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
+ break;
+ }
+ count++;
+ scan += n;
+ }
+ break;
+ default:
+ preg->err = REG_ERR_INTERNAL;
+ count = 0;
+ break;
+ }
+ preg->reginput = scan;
+
+ return(count);
+}
+
+static int regnext(regex_t *preg, int p )
+{
+ int offset;
+
+ offset = NEXT(preg, p);
+
+ if (offset == 0)
+ return 0;
+
+ if (OP(preg, p) == BACK)
+ return(p-offset);
+ else
+ return(p+offset);
+}
+
+static int regopsize(regex_t *preg, int p )
+{
+
+ switch (OP(preg, p)) {
+ case REP:
+ case REPMIN:
+ case REPX:
+ case REPXMIN:
+ return 5;
+
+ case ANYOF:
+ case ANYBUT:
+ case EXACTLY: {
+ int s = p + 2;
+ while (preg->program[s++]) {
+ }
+ return s - p;
+ }
+ }
+ return 2;
+}
+
+
+size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+ static const char *error_strings[] = {
+ "success",
+ "no match",
+ "bad pattern",
+ "null argument",
+ "unknown error",
+ "too big",
+ "out of memory",
+ "too many ()",
+ "parentheses () not balanced",
+ "braces {} not balanced",
+ "invalid repetition count(s)",
+ "extra characters",
+ "*+ of empty atom",
+ "nested count",
+ "internal error",
+ "count follows nothing",
+ "invalid escape \\ sequence",
+ "corrupted program",
+ "contains null char",
+ "brackets [] not balanced",
+ };
+ const char *err;
+
+ if (errcode < 0 || errcode >= REG_ERR_NUM) {
+ err = "Bad error code";
+ }
+ else {
+ err = error_strings[errcode];
+ }
+
+ return snprintf(errbuf, errbuf_size, "%s", err);
+}
+
+void jim_regfree(regex_t *preg)
+{
+ free(preg->program);
+}
+
+#endif
+#include <string.h>
+
+void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
+{
+ Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
+}
+
+#if defined(_WIN32) || defined(WIN32)
+#include <sys/stat.h>
+
+int Jim_Errno(void)
+{
+ switch (GetLastError()) {
+ case ERROR_FILE_NOT_FOUND: return ENOENT;
+ case ERROR_PATH_NOT_FOUND: return ENOENT;
+ case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
+ case ERROR_ACCESS_DENIED: return EACCES;
+ case ERROR_INVALID_HANDLE: return EBADF;
+ case ERROR_BAD_ENVIRONMENT: return E2BIG;
+ case ERROR_BAD_FORMAT: return ENOEXEC;
+ case ERROR_INVALID_ACCESS: return EACCES;
+ case ERROR_INVALID_DRIVE: return ENOENT;
+ case ERROR_CURRENT_DIRECTORY: return EACCES;
+ case ERROR_NOT_SAME_DEVICE: return EXDEV;
+ case ERROR_NO_MORE_FILES: return ENOENT;
+ case ERROR_WRITE_PROTECT: return EROFS;
+ case ERROR_BAD_UNIT: return ENXIO;
+ case ERROR_NOT_READY: return EBUSY;
+ case ERROR_BAD_COMMAND: return EIO;
+ case ERROR_CRC: return EIO;
+ case ERROR_BAD_LENGTH: return EIO;
+ case ERROR_SEEK: return EIO;
+ case ERROR_WRITE_FAULT: return EIO;
+ case ERROR_READ_FAULT: return EIO;
+ case ERROR_GEN_FAILURE: return EIO;
+ case ERROR_SHARING_VIOLATION: return EACCES;
+ case ERROR_LOCK_VIOLATION: return EACCES;
+ case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
+ case ERROR_HANDLE_DISK_FULL: return ENOSPC;
+ case ERROR_NOT_SUPPORTED: return ENODEV;
+ case ERROR_REM_NOT_LIST: return EBUSY;
+ case ERROR_DUP_NAME: return EEXIST;
+ case ERROR_BAD_NETPATH: return ENOENT;
+ case ERROR_NETWORK_BUSY: return EBUSY;
+ case ERROR_DEV_NOT_EXIST: return ENODEV;
+ case ERROR_TOO_MANY_CMDS: return EAGAIN;
+ case ERROR_ADAP_HDW_ERR: return EIO;
+ case ERROR_BAD_NET_RESP: return EIO;
+ case ERROR_UNEXP_NET_ERR: return EIO;
+ case ERROR_NETNAME_DELETED: return ENOENT;
+ case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
+ case ERROR_BAD_DEV_TYPE: return ENODEV;
+ case ERROR_BAD_NET_NAME: return ENOENT;
+ case ERROR_TOO_MANY_NAMES: return ENFILE;
+ case ERROR_TOO_MANY_SESS: return EIO;
+ case ERROR_SHARING_PAUSED: return EAGAIN;
+ case ERROR_REDIR_PAUSED: return EAGAIN;
+ case ERROR_FILE_EXISTS: return EEXIST;
+ case ERROR_CANNOT_MAKE: return ENOSPC;
+ case ERROR_OUT_OF_STRUCTURES: return ENFILE;
+ case ERROR_ALREADY_ASSIGNED: return EEXIST;
+ case ERROR_INVALID_PASSWORD: return EPERM;
+ case ERROR_NET_WRITE_FAULT: return EIO;
+ case ERROR_NO_PROC_SLOTS: return EAGAIN;
+ case ERROR_DISK_CHANGE: return EXDEV;
+ case ERROR_BROKEN_PIPE: return EPIPE;
+ case ERROR_OPEN_FAILED: return ENOENT;
+ case ERROR_DISK_FULL: return ENOSPC;
+ case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
+ case ERROR_INVALID_TARGET_HANDLE: return EBADF;
+ case ERROR_INVALID_NAME: return ENOENT;
+ case ERROR_PROC_NOT_FOUND: return ESRCH;
+ case ERROR_WAIT_NO_CHILDREN: return ECHILD;
+ case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
+ case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
+ case ERROR_SEEK_ON_DEVICE: return ESPIPE;
+ case ERROR_BUSY_DRIVE: return EAGAIN;
+ case ERROR_DIR_NOT_EMPTY: return EEXIST;
+ case ERROR_NOT_LOCKED: return EACCES;
+ case ERROR_BAD_PATHNAME: return ENOENT;
+ case ERROR_LOCK_FAILED: return EACCES;
+ case ERROR_ALREADY_EXISTS: return EEXIST;
+ case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
+ case ERROR_BAD_PIPE: return EPIPE;
+ case ERROR_PIPE_BUSY: return EAGAIN;
+ case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
+ case ERROR_DIRECTORY: return ENOTDIR;
+ }
+ return EINVAL;
+}
+
+long JimProcessPid(phandle_t pid)
+{
+ if (pid == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+ return GetProcessId(pid);
+}
+
+phandle_t JimWaitPid(long pid, int *status, int nohang)
+{
+ if (pid > 0) {
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid);
+ if (h) {
+ long pid = waitpid(h, status, nohang);
+ CloseHandle(h);
+ if (pid > 0) {
+ return h;
+ }
+ }
+ }
+ return JIM_BAD_PHANDLE;
+}
+
+long waitpid(phandle_t phandle, int *status, int nohang)
+{
+ long pid;
+ DWORD ret = WaitForSingleObject(phandle, nohang ? 0 : INFINITE);
+ if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
+
+ return -1;
+ }
+ GetExitCodeProcess(phandle, &ret);
+ *status = ret;
+
+ pid = GetProcessId(phandle);
+ CloseHandle(phandle);
+ return pid;
+}
+
+int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
+{
+ char name[MAX_PATH];
+ HANDLE handle;
+
+ if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) {
+ return -1;
+ }
+
+ handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0),
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ goto error;
+ }
+
+ Jim_SetResultString(interp, name, -1);
+ return _open_osfhandle((intptr_t)handle, _O_RDWR | _O_TEXT);
+
+ error:
+ Jim_SetResultErrno(interp, name);
+ DeleteFile(name);
+ return -1;
+}
+
+int Jim_OpenForWrite(const char *filename, int append)
+{
+ if (strcmp(filename, "/dev/null") == 0) {
+ filename = "nul:";
+ }
+ int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE);
+ if (fd >= 0 && append) {
+
+ _lseek(fd, 0L, SEEK_END);
+ }
+ return fd;
+}
+
+int Jim_OpenForRead(const char *filename)
+{
+ if (strcmp(filename, "/dev/null") == 0) {
+ filename = "nul:";
+ }
+ return _open(filename, _O_RDONLY | _O_TEXT, 0);
+}
+
+#elif defined(HAVE_UNISTD_H)
+
+
+
+int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
+{
+ int fd;
+ mode_t mask;
+ Jim_Obj *filenameObj;
+
+ if (filename_template == NULL) {
+ const char *tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
+ tmpdir = "/tmp/";
+ }
+ filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
+ if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
+ Jim_AppendString(interp, filenameObj, "/", 1);
+ }
+ Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
+ }
+ else {
+ filenameObj = Jim_NewStringObj(interp, filename_template, -1);
+ }
+
+
+#ifdef HAVE_UMASK
+ mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+#endif
+#ifdef HAVE_MKSTEMP
+ fd = mkstemp(filenameObj->bytes);
+#else
+ if (mktemp(filenameObj->bytes) == NULL) {
+ fd = -1;
+ }
+ else {
+ fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
+ }
+#endif
+#ifdef HAVE_UMASK
+ umask(mask);
+#endif
+ if (fd < 0) {
+ Jim_SetResultErrno(interp, Jim_String(filenameObj));
+ Jim_FreeNewObj(interp, filenameObj);
+ return -1;
+ }
+ if (unlink_file) {
+ remove(Jim_String(filenameObj));
+ }
+
+ Jim_SetResult(interp, filenameObj);
+ return fd;
+}
+
+int Jim_OpenForWrite(const char *filename, int append)
+{
+ return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
+}
+
+int Jim_OpenForRead(const char *filename)
+{
+ return open(filename, O_RDONLY, 0);
+}
+
+#endif
+
+#if defined(_WIN32) || defined(WIN32)
+#ifndef STRICT
+#define STRICT
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#if defined(HAVE_DLOPEN_COMPAT)
+void *dlopen(const char *path, int mode)
+{
+ JIM_NOTUSED(mode);
+
+ return (void *)LoadLibraryA(path);
+}
+
+int dlclose(void *handle)
+{
+ FreeLibrary((HANDLE)handle);
+ return 0;
+}
+
+void *dlsym(void *handle, const char *symbol)
+{
+ return GetProcAddress((HMODULE)handle, symbol);
+}
+
+char *dlerror(void)
+{
+ static char msg[121];
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
+ LANG_NEUTRAL, msg, sizeof(msg) - 1, NULL);
+ return msg;
+}
+#endif
+
+#ifdef _MSC_VER
+
+#include <sys/timeb.h>
+
+
+int gettimeofday(struct timeval *tv, void *unused)
+{
+ struct _timeb tb;
+
+ _ftime(&tb);
+ tv->tv_sec = tb.time;
+ tv->tv_usec = tb.millitm * 1000;
+
+ return 0;
+}
+
+
+DIR *opendir(const char *name)
+{
+ DIR *dir = 0;
+
+ if (name && name[0]) {
+ size_t base_length = strlen(name);
+ const char *all =
+ strchr("/\\", name[base_length - 1]) ? "*" : "/*";
+
+ if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
+ (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
+ strcat(strcpy(dir->name, name), all);
+
+ if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
+ dir->result.d_name = 0;
+ else {
+ Jim_Free(dir->name);
+ Jim_Free(dir);
+ dir = 0;
+ }
+ }
+ else {
+ Jim_Free(dir);
+ dir = 0;
+ errno = ENOMEM;
+ }
+ }
+ else {
+ errno = EINVAL;
+ }
+ return dir;
+}
+
+int closedir(DIR * dir)
+{
+ int result = -1;
+
+ if (dir) {
+ if (dir->handle != -1)
+ result = _findclose(dir->handle);
+ Jim_Free(dir->name);
+ Jim_Free(dir);
+ }
+ if (result == -1)
+ errno = EBADF;
+ return result;
+}
+
+struct dirent *readdir(DIR * dir)
+{
+ struct dirent *result = 0;
+
+ if (dir && dir->handle != -1) {
+ if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
+ result = &dir->result;
+ result->d_name = dir->info.name;
+ }
+ }
+ else {
+ errno = EBADF;
+ }
+ return result;
+}
+#endif
+#endif
+#include <stdio.h>
+#include <signal.h>
+
+
+
+
+
+
+#ifndef SIGPIPE
+#define SIGPIPE 13
+#endif
+#ifndef SIGINT
+#define SIGINT 2
+#endif
+
+const char *Jim_SignalId(int sig)
+{
+ static char buf[10];
+ switch (sig) {
+ case SIGINT: return "SIGINT";
+ case SIGPIPE: return "SIGPIPE";
+
+ }
+ snprintf(buf, sizeof(buf), "%d", sig);
+ return buf;
+}
+#ifndef JIM_BOOTSTRAP_LIB_ONLY
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#ifdef USE_LINENOISE
+#ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+ #include <sys/stat.h>
+#endif
+#include "linenoise.h"
+#else
+#define MAX_LINE_LEN 512
+#endif
+
+#ifdef USE_LINENOISE
+struct JimCompletionInfo {
+ Jim_Interp *interp;
+ Jim_Obj *completion_command;
+ Jim_Obj *hints_command;
+
+};
+
+static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp);
+static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata);
+static const char completion_callback_assoc_key[] = "interactive-completion";
+static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata);
+static void JimFreeHintsCallback(void *hint, void *userdata);
+#endif
+
+char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
+{
+#ifdef USE_LINENOISE
+ struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
+ char *result;
+ Jim_Obj *objPtr;
+ long mlmode = 0;
+ if (compinfo->completion_command) {
+ linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
+ }
+ if (compinfo->hints_command) {
+ linenoiseSetHintsCallback(JimHintsCallback, compinfo);
+ linenoiseSetFreeHintsCallback(JimFreeHintsCallback);
+ }
+ objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
+ if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
+ linenoiseSetMultiLine(mlmode);
+ }
+
+ result = linenoise(prompt);
+
+ linenoiseSetCompletionCallback(NULL, NULL);
+ linenoiseSetHintsCallback(NULL, NULL);
+ linenoiseSetFreeHintsCallback(NULL);
+ return result;
+#else
+ int len;
+ char *line = Jim_Alloc(MAX_LINE_LEN);
+
+ fputs(prompt, stdout);
+ fflush(stdout);
+
+ if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
+ Jim_Free(line);
+ return NULL;
+ }
+ len = strlen(line);
+ if (len && line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ }
+ return line;
+#endif
+}
+
+void Jim_HistoryLoad(const char *filename)
+{
+#ifdef USE_LINENOISE
+ linenoiseHistoryLoad(filename);
+#endif
+}
+
+void Jim_HistoryAdd(const char *line)
+{
+#ifdef USE_LINENOISE
+ linenoiseHistoryAdd(line);
+#endif
+}
+
+void Jim_HistorySave(const char *filename)
+{
+#ifdef USE_LINENOISE
+#ifdef HAVE_UMASK
+ mode_t mask;
+
+ mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+#endif
+ linenoiseHistorySave(filename);
+#ifdef HAVE_UMASK
+ umask(mask);
+#endif
+#endif
+}
+
+void Jim_HistoryShow(void)
+{
+#ifdef USE_LINENOISE
+
+ int i;
+ int len;
+ char **history = linenoiseHistory(&len);
+ for (i = 0; i < len; i++) {
+ printf("%4d %s\n", i + 1, history[i]);
+ }
+#endif
+}
+
+void Jim_HistorySetMaxLen(int length)
+{
+#ifdef USE_LINENOISE
+ linenoiseHistorySetMaxLen(length);
+#endif
+}
+
+int Jim_HistoryGetMaxLen(void)
+{
+#ifdef USE_LINENOISE
+ return linenoiseHistoryGetMaxLen();
+#endif
+ return 0;
+}
+
+#ifdef USE_LINENOISE
+static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
+{
+ struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
+ Jim_Obj *objv[2];
+ int ret;
+
+ objv[0] = info->completion_command;
+ objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
+
+ ret = Jim_EvalObjVector(info->interp, 2, objv);
+
+
+ if (ret == JIM_OK) {
+ int i;
+ Jim_Obj *listObj = Jim_GetResult(info->interp);
+ int len = Jim_ListLength(info->interp, listObj);
+ for (i = 0; i < len; i++) {
+ linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
+ }
+ }
+}
+
+static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata)
+{
+ struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
+ Jim_Obj *objv[2];
+ int ret;
+ char *result = NULL;
+
+ objv[0] = info->hints_command;
+ objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
+
+ ret = Jim_EvalObjVector(info->interp, 2, objv);
+
+
+ if (ret == JIM_OK) {
+ Jim_Obj *listObj = Jim_GetResult(info->interp);
+ Jim_IncrRefCount(listObj);
+
+ int len = Jim_ListLength(info->interp, listObj);
+ if (len >= 1) {
+ long x;
+ result = Jim_StrDup(Jim_String(Jim_ListGetIndex(info->interp, listObj, 0)));
+ if (len >= 2 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 1), &x) == JIM_OK) {
+ *color = x;
+ }
+ if (len >= 3 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 2), &x) == JIM_OK) {
+ *bold = x;
+ }
+ }
+ Jim_DecrRefCount(info->interp, listObj);
+ }
+ return result;
+}
+
+static void JimFreeHintsCallback(void *hint, void *userdata)
+{
+ Jim_Free(hint);
+}
+
+static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data)
+{
+ struct JimCompletionInfo *compinfo = data;
+
+ if (compinfo->completion_command) {
+ Jim_DecrRefCount(interp, compinfo->completion_command);
+ }
+ if (compinfo->hints_command) {
+ Jim_DecrRefCount(interp, compinfo->hints_command);
+ }
+
+ Jim_Free(compinfo);
+}
+
+static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp)
+{
+ struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
+ if (compinfo == NULL) {
+ compinfo = Jim_Alloc(sizeof(*compinfo));
+ compinfo->interp = interp;
+ compinfo->completion_command = NULL;
+ compinfo->hints_command = NULL;
+ Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
+ }
+ return compinfo;
+}
+#endif
+
+void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj)
+{
+#ifdef USE_LINENOISE
+ struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
+
+ if (completionCommandObj) {
+
+ Jim_IncrRefCount(completionCommandObj);
+ }
+ if (compinfo->completion_command) {
+ Jim_DecrRefCount(interp, compinfo->completion_command);
+ }
+ compinfo->completion_command = completionCommandObj;
+#endif
+}
+
+void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj)
+{
+#ifdef USE_LINENOISE
+ struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
+
+ if (hintsCommandObj) {
+
+ Jim_IncrRefCount(hintsCommandObj);
+ }
+ if (compinfo->hints_command) {
+ Jim_DecrRefCount(interp, compinfo->hints_command);
+ }
+ compinfo->hints_command = hintsCommandObj;
+#endif
+}
+
+int Jim_InteractivePrompt(Jim_Interp *interp)
+{
+ int retcode = JIM_OK;
+ char *history_file = NULL;
+#ifdef USE_LINENOISE
+ const char *home;
+
+ home = getenv("HOME");
+ if (home && isatty(STDIN_FILENO)) {
+ int history_len = strlen(home) + sizeof("/.jim_history");
+ history_file = Jim_Alloc(history_len);
+ snprintf(history_file, history_len, "%s/.jim_history", home);
+ Jim_HistoryLoad(history_file);
+ }
+
+ Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
+ Jim_HistorySetHints(interp, Jim_NewStringObj(interp, "tcl::stdhint", -1));
+#endif
+
+ printf("Welcome to Jim version %d.%d\n",
+ JIM_VERSION / 100, JIM_VERSION % 100);
+ Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
+
+ while (1) {
+ Jim_Obj *scriptObjPtr;
+ const char *result;
+ int reslen;
+ char prompt[20];
+
+ if (retcode != JIM_OK) {
+ const char *retcodestr = Jim_ReturnCode(retcode);
+
+ if (*retcodestr == '?') {
+ snprintf(prompt, sizeof(prompt) - 3, "[%d] . ", retcode);
+ }
+ else {
+ snprintf(prompt, sizeof(prompt) - 3, "[%s] . ", retcodestr);
+ }
+ }
+ else {
+ strcpy(prompt, ". ");
+ }
+
+ scriptObjPtr = Jim_NewStringObj(interp, "", 0);
+ Jim_IncrRefCount(scriptObjPtr);
+ while (1) {
+ char state;
+ char *line;
+
+ line = Jim_HistoryGetline(interp, prompt);
+ if (line == NULL) {
+ if (errno == EINTR) {
+ continue;
+ }
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ retcode = JIM_OK;
+ goto out;
+ }
+ if (Jim_Length(scriptObjPtr) != 0) {
+
+ Jim_AppendString(interp, scriptObjPtr, "\n", 1);
+ }
+ Jim_AppendString(interp, scriptObjPtr, line, -1);
+ Jim_Free(line);
+ if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
+ break;
+
+ snprintf(prompt, sizeof(prompt), "%c> ", state);
+ }
+#ifdef USE_LINENOISE
+ if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
+
+ Jim_HistoryShow();
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ continue;
+ }
+
+ Jim_HistoryAdd(Jim_String(scriptObjPtr));
+ if (history_file) {
+ Jim_HistorySave(history_file);
+ }
+#endif
+ retcode = Jim_EvalObj(interp, scriptObjPtr);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+
+ if (retcode == JIM_EXIT) {
+ break;
+ }
+ if (retcode == JIM_ERR) {
+ Jim_MakeErrorMessage(interp);
+ }
+ result = Jim_GetString(Jim_GetResult(interp), &reslen);
+ if (reslen) {
+ if (fwrite(result, reslen, 1, stdout) == 0) {
+
+ }
+ putchar('\n');
+ }
+ }
+ out:
+ Jim_Free(history_file);
+
+ return retcode;
+}
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+extern int Jim_initjimshInit(Jim_Interp *interp);
+
+static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
+{
+ int n;
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+
+ for (n = 0; n < argc; n++) {
+ Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
+
+ Jim_ListAppendElement(interp, listObj, obj);
+ }
+
+ Jim_SetVariableStr(interp, "argv", listObj);
+ Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
+}
+
+static void JimPrintErrorMessage(Jim_Interp *interp)
+{
+ Jim_MakeErrorMessage(interp);
+ fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+}
+
+void usage(const char* executable_name)
+{
+ printf("jimsh version %d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
+ printf("Usage: %s\n", executable_name);
+ printf("or : %s [options] [filename]\n", executable_name);
+ printf("\n");
+ printf("Without options: Interactive mode\n");
+ printf("\n");
+ printf("Options:\n");
+ printf(" --version : prints the version string\n");
+ printf(" --help : prints this text\n");
+ printf(" -e CMD : executes command CMD\n");
+ printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
+ printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n");
+ printf(" NOTE: all subsequent options will be passed to the script\n\n");
+}
+
+int main(int argc, char *const argv[])
+{
+ int retcode;
+ Jim_Interp *interp;
+ char *const orig_argv0 = argv[0];
+
+
+ if (argc > 1 && strcmp(argv[1], "--version") == 0) {
+ printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
+ return 0;
+ }
+ else if (argc > 1 && strcmp(argv[1], "--help") == 0) {
+ usage(argv[0]);
+ return 0;
+ }
+
+
+ interp = Jim_CreateInterp();
+ Jim_RegisterCoreCommands(interp);
+
+
+ if (Jim_InitStaticExtensions(interp) != JIM_OK) {
+ JimPrintErrorMessage(interp);
+ }
+
+ Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
+ Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
+#ifdef USE_LINENOISE
+ Jim_SetVariableStrWithStr(interp, "jim::lineedit", "1");
+#else
+ Jim_SetVariableStrWithStr(interp, "jim::lineedit", "0");
+#endif
+ retcode = Jim_initjimshInit(interp);
+
+ if (argc == 1) {
+
+ if (retcode == JIM_ERR) {
+ JimPrintErrorMessage(interp);
+ }
+ if (retcode != JIM_EXIT) {
+ JimSetArgv(interp, 0, NULL);
+ if (!isatty(STDIN_FILENO)) {
+
+ goto eval_stdin;
+ }
+ retcode = Jim_InteractivePrompt(interp);
+ }
+ }
+ else {
+
+ if (argc > 2 && strcmp(argv[1], "-e") == 0) {
+
+ JimSetArgv(interp, argc - 3, argv + 3);
+ retcode = Jim_Eval(interp, argv[2]);
+ if (retcode != JIM_ERR) {
+ int len;
+ const char *msg = Jim_GetString(Jim_GetResult(interp), &len);
+ if (fwrite(msg, len, 1, stdout) == 0) {
+
+ }
+ putchar('\n');
+ }
+ }
+ else {
+ Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
+ JimSetArgv(interp, argc - 2, argv + 2);
+ if (strcmp(argv[1], "-") == 0) {
+eval_stdin:
+ retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
+ } else {
+ retcode = Jim_EvalFile(interp, argv[1]);
+ }
+ }
+ if (retcode == JIM_ERR) {
+ JimPrintErrorMessage(interp);
+ }
+ }
+ if (retcode == JIM_EXIT) {
+ retcode = Jim_GetExitCode(interp);
+ }
+ else if (retcode == JIM_ERR) {
+ retcode = 1;
+ }
+ else {
+ retcode = 0;
+ }
+ Jim_FreeInterp(interp);
+ return retcode;
+}
+#endif
diff --git a/contrib/sqlite3/autosetup/pkg-config.tcl b/contrib/sqlite3/autosetup/pkg-config.tcl
new file mode 100644
index 000000000000..9ce7111f55c1
--- /dev/null
+++ b/contrib/sqlite3/autosetup/pkg-config.tcl
@@ -0,0 +1,168 @@
+# Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'pkg-config' module allows package information to be found via 'pkg-config'.
+#
+# If not cross-compiling, the package path should be determined automatically
+# by 'pkg-config'.
+# If cross-compiling, the default package path is the compiler sysroot.
+# If the C compiler doesn't support '-print-sysroot', the path can be supplied
+# by the '--sysroot' option or by defining 'SYSROOT'.
+#
+# 'PKG_CONFIG' may be set to use an alternative to 'pkg-config'.
+
+use cc
+
+options {
+ sysroot:dir => "Override compiler sysroot for pkg-config search path"
+}
+
+# @pkg-config-init ?required?
+#
+# Initialises the 'pkg-config' system. Unless '$required' is set to 0,
+# it is a fatal error if a usable 'pkg-config' is not found .
+#
+# This command will normally be called automatically as required,
+# but it may be invoked explicitly if lack of 'pkg-config' is acceptable.
+#
+# Returns 1 if ok, or 0 if 'pkg-config' not found/usable (only if '$required' is 0).
+#
+proc pkg-config-init {{required 1}} {
+ if {[is-defined HAVE_PKG_CONFIG]} {
+ return [get-define HAVE_PKG_CONFIG]
+ }
+ set found 0
+
+ define PKG_CONFIG [get-env PKG_CONFIG pkg-config]
+ msg-checking "Checking for pkg-config..."
+
+ if {[catch {exec [get-define PKG_CONFIG] --version} version]} {
+ msg-result "[get-define PKG_CONFIG] (not found)"
+ if {$required} {
+ user-error "No usable pkg-config"
+ }
+ } else {
+ msg-result $version
+ define PKG_CONFIG_VERSION $version
+
+ set found 1
+
+ if {[opt-str sysroot o]} {
+ define SYSROOT [file-normalize $o]
+ msg-result "Using specified sysroot [get-define SYSROOT]"
+ } elseif {[get-define build] ne [get-define host]} {
+ if {[catch {exec-with-stderr {*}[get-define CC] -print-sysroot} result errinfo] == 0} {
+ # Use the compiler sysroot, if there is one
+ define SYSROOT $result
+ msg-result "Found compiler sysroot $result"
+ } else {
+ configlog "[get-define CC] -print-sysroot: $result"
+ set msg "pkg-config: Cross compiling, but no compiler sysroot and no --sysroot supplied"
+ if {$required} {
+ user-error $msg
+ } else {
+ msg-result $msg
+ }
+ set found 0
+ }
+ }
+ if {[is-defined SYSROOT]} {
+ set sysroot [get-define SYSROOT]
+
+ # XXX: It's possible that these should be set only when invoking pkg-config
+ global env
+ set env(PKG_CONFIG_DIR) ""
+ # Supposedly setting PKG_CONFIG_LIBDIR means that PKG_CONFIG_PATH is ignored,
+ # but it doesn't seem to work that way in practice
+ set env(PKG_CONFIG_PATH) ""
+ # Do we need to try /usr/local as well or instead?
+ set env(PKG_CONFIG_LIBDIR) $sysroot/usr/lib/pkgconfig:$sysroot/usr/share/pkgconfig
+ set env(PKG_CONFIG_SYSROOT_DIR) $sysroot
+ }
+ }
+ define HAVE_PKG_CONFIG $found
+ return $found
+}
+
+# @pkg-config module ?requirements?
+#
+# Use 'pkg-config' to find the given module meeting the given requirements.
+# e.g.
+#
+## pkg-config pango >= 1.37.0
+#
+# If found, returns 1 and sets 'HAVE_PKG_PANGO' to 1 along with:
+#
+## PKG_PANGO_VERSION to the found version
+## PKG_PANGO_LIBS to the required libs (--libs-only-l)
+## PKG_PANGO_LDFLAGS to the required linker flags (--libs-only-L)
+## PKG_PANGO_CFLAGS to the required compiler flags (--cflags)
+#
+# If not found, returns 0.
+#
+proc pkg-config {module args} {
+ set ok [pkg-config-init]
+
+ msg-checking "Checking for $module $args..."
+
+ if {!$ok} {
+ msg-result "no pkg-config"
+ return 0
+ }
+
+ set pkgconfig [get-define PKG_CONFIG]
+
+ set ret [catch {exec $pkgconfig --modversion "$module $args"} version]
+ configlog "$pkgconfig --modversion $module $args: $version"
+ if {$ret} {
+ msg-result "not found"
+ return 0
+ }
+ # Sometimes --modversion succeeds but because of dependencies it isn't usable
+ # This seems to show up with --cflags
+ set ret [catch {exec $pkgconfig --cflags $module} cflags]
+ if {$ret} {
+ msg-result "unusable ($version - see config.log)"
+ configlog "$pkgconfig --cflags $module"
+ configlog $cflags
+ return 0
+ }
+ msg-result $version
+ set prefix [feature-define-name $module PKG_]
+ define HAVE_${prefix}
+ define ${prefix}_VERSION $version
+ define ${prefix}_CFLAGS $cflags
+ define ${prefix}_LIBS [exec $pkgconfig --libs-only-l $module]
+ define ${prefix}_LDFLAGS [exec $pkgconfig --libs-only-L $module]
+ return 1
+}
+
+# @pkg-config-get module setting
+#
+# Convenience access to the results of 'pkg-config'.
+#
+# For example, '[pkg-config-get pango CFLAGS]' returns
+# the value of 'PKG_PANGO_CFLAGS', or '""' if not defined.
+proc pkg-config-get {module name} {
+ set prefix [feature-define-name $module PKG_]
+ get-define ${prefix}_${name} ""
+}
+
+# @pkg-config-get-var module variable
+#
+# Return the value of the given variable from the given pkg-config module.
+# The module must already have been successfully detected with pkg-config.
+# e.g.
+#
+## if {[pkg-config harfbuzz >= 2.5]} {
+## define harfbuzz_libdir [pkg-config-get-var harfbuzz libdir]
+## }
+#
+# Returns the empty string if the variable isn't defined.
+proc pkg-config-get-var {module variable} {
+ set pkgconfig [get-define PKG_CONFIG]
+ set prefix [feature-define-name $module HAVE_PKG_]
+ exec $pkgconfig $module --variable $variable
+}
diff --git a/contrib/sqlite3/autosetup/proj.tcl b/contrib/sqlite3/autosetup/proj.tcl
new file mode 100644
index 000000000000..1335567064ee
--- /dev/null
+++ b/contrib/sqlite3/autosetup/proj.tcl
@@ -0,0 +1,2236 @@
+########################################################################
+# 2024 September 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.
+#
+
+#
+# ----- @module proj.tcl -----
+# @section Project-agnostic Helper APIs
+#
+
+#
+# Routines for Steve Bennett's autosetup which are common to trees
+# managed in and around the umbrella of the SQLite project.
+#
+# The intent is that these routines be relatively generic, independent
+# of a given project.
+#
+# For practical purposes, the copy of this file hosted in the SQLite
+# project is the "canonical" one:
+#
+# https://sqlite.org/src/file/autosetup/proj.tcl
+#
+# This file was initially derived from one used in the libfossil
+# project, authored by the same person who ported it here, and this is
+# noted here only as an indication that there are no licensing issues
+# despite this code having a handful of near-twins running around a
+# handful of third-party source trees.
+#
+# Design notes:
+#
+# - Symbols with _ separators are intended for internal use within
+# this file, and are not part of the API which auto.def files should
+# rely on. Symbols with - separators are public APIs.
+#
+# - By and large, autosetup prefers to update global state with the
+# results of feature checks, e.g. whether the compiler supports flag
+# --X. In this developer's opinion that (A) causes more confusion
+# than it solves[^1] and (B) adds an unnecessary layer of "voodoo"
+# between the autosetup user and its internals. This module, in
+# contrast, instead injects the results of its own tests into
+# well-defined variables and leaves the integration of those values
+# to the caller's discretion.
+#
+# [1]: As an example: testing for the -rpath flag, using
+# cc-check-flags, can break later checks which use
+# [cc-check-function-in-lib ...] because the resulting -rpath flag
+# implicitly becomes part of those tests. In the case of an rpath
+# test, downstream tests may not like the $prefix/lib path added by
+# the rpath test. To avoid such problems, we avoid (intentionally)
+# updating global state via feature tests.
+#
+
+#
+# $proj__Config is an internal-use-only array for storing whatever generic
+# internal stuff we need stored.
+#
+array set ::proj__Config {
+ self-tests 1
+}
+
+
+#
+# List of dot-in files to filter in the final stages of
+# configuration. Some configuration steps may append to this. Each
+# one in this list which exists will trigger the generation of a
+# file with that same name, minus the ".in", in the build directory
+# (which differ from the source dir in out-of-tree builds).
+#
+# See: proj-dot-ins-append and proj-dot-ins-process
+#
+set ::proj__Config(dot-in-files) [list]
+set ::proj__Config(isatty) [isatty? stdout]
+
+#
+# @proj-warn msg
+#
+# Emits a warning message to stderr. All args are appended with a
+# space between each.
+#
+proc proj-warn {args} {
+ show-notices
+ puts stderr [join [list "WARNING: \[[proj-scope 1]\]: " {*}$args] " "]
+}
+
+
+# Internal impl of [proj-fatal] and [proj-error]. It must be called
+# using tailcall.
+proc proj__faterr {failMode argv} {
+ show-notices
+ set lvl 1
+ while {"-up" eq [lindex $argv 0]} {
+ set argv [lassign $argv -]
+ incr lvl
+ }
+ if {$failMode} {
+ puts stderr [join [list "FATAL: \[[proj-scope $lvl]]: " {*}$argv]]
+ exit 1
+ } else {
+ error [join [list "\[[proj-scope $lvl]]:" {*}$argv]]
+ }
+}
+
+
+#
+# @proj-fatal ?-up...? msg...
+#
+# Emits an error message to stderr and exits with non-0. All args are
+# appended with a space between each.
+#
+# The calling scope's name is used in the error message. To instead
+# use the name of a call higher up in the stack, use -up once for each
+# additional level.
+#
+proc proj-fatal {args} {
+ tailcall proj__faterr 1 $args
+}
+
+#
+# @proj-error ?-up...? msg...
+#
+# Works like proj-fatal but uses [error] intead of [exit].
+#
+proc proj-error {args} {
+ tailcall proj__faterr 0 $args
+}
+
+set ::proj__Config(verbose-assert) [get-env proj-assert-verbose 0]
+#
+# @proj-assert script ?message?
+#
+# Kind of like a C assert: if uplevel of [list expr $script] is false,
+# a fatal error is triggered. The error message, by default, includes
+# the body of the failed assertion, but if $msg is set then that is
+# used instead.
+#
+proc proj-assert {script {msg ""}} {
+ if {1 eq $::proj__Config(verbose-assert)} {
+ msg-result [proj-bold "asserting: $script"]
+ }
+ if {![uplevel 1 [list expr $script]]} {
+ if {"" eq $msg} {
+ set msg $script
+ }
+ proj-fatal "Assertion failed in \[[proj-scope 1]\]: $msg"
+ }
+}
+
+#
+# @proj-bold str
+#
+# If this function believes that the current console might support
+# ANSI escape sequences then this returns $str wrapped in a sequence
+# to bold that text, else it returns $str as-is.
+#
+proc proj-bold {args} {
+ if {$::autosetup(iswin) || !$::proj__Config(isatty)} {
+ return [join $args]
+ }
+ return "\033\[1m${args}\033\[0m"
+}
+
+#
+# @proj-indented-notice ?-error? ?-notice? msg
+#
+# Takes a multi-line message and emits it with consistent indentation.
+# It does not perform any line-wrapping of its own. Which output
+# routine it uses depends on its flags, defaulting to msg-result.
+# For -error and -notice it uses user-notice.
+#
+# If the -notice flag it used then it emits using [user-notice], which
+# means its rendering will (A) go to stderr and (B) be delayed until
+# the next time autosetup goes to output a message.
+#
+# If the -error flag is provided then it renders the message
+# immediately to stderr and then exits.
+#
+# If neither -notice nor -error are used, the message will be sent to
+# stdout without delay.
+#
+proc proj-indented-notice {args} {
+ set fErr ""
+ set outFunc "msg-result"
+ while {[llength $args] > 1} {
+ switch -exact -- [lindex $args 0] {
+ -error {
+ set args [lassign $args fErr]
+ set outFunc "user-notice"
+ }
+ -notice {
+ set args [lassign $args -]
+ set outFunc "user-notice"
+ }
+ default {
+ break
+ }
+ }
+ }
+ set lines [split [join $args] \n]
+ foreach line $lines {
+ set line [string trimleft $line]
+ if {"" eq $line} {
+ $outFunc $line
+ } else {
+ $outFunc " $line"
+ }
+ }
+ if {"" ne $fErr} {
+ show-notices
+ exit 1
+ }
+}
+
+#
+# @proj-is-cross-compiling
+#
+# Returns 1 if cross-compiling, else 0.
+#
+proc proj-is-cross-compiling {} {
+ expr {[get-define host] ne [get-define build]}
+}
+
+#
+# @proj-strip-hash-comments value
+#
+# Expects to receive string input, which it splits on newlines, strips
+# out any lines which begin with any number of whitespace followed by
+# a '#', and returns a value containing the [append]ed results of each
+# remaining line with a \n between each. It does not strip out
+# comments which appear after the first non-whitespace character.
+#
+proc proj-strip-hash-comments {val} {
+ set x {}
+ foreach line [split $val \n] {
+ if {![string match "#*" [string trimleft $line]]} {
+ append x $line \n
+ }
+ }
+ return $x
+}
+
+#
+# @proj-cflags-without-werror
+#
+# Fetches [define $var], strips out any -Werror entries, and returns
+# the new value. This is intended for temporarily stripping -Werror
+# from CFLAGS or CPPFLAGS within the scope of a [define-push] block.
+#
+proc proj-cflags-without-werror {{var CFLAGS}} {
+ set rv {}
+ foreach f [get-define $var ""] {
+ switch -exact -- $f {
+ -Werror {}
+ default { lappend rv $f }
+ }
+ }
+ join $rv " "
+}
+
+#
+# @proj-check-function-in-lib
+#
+# A proxy for cc-check-function-in-lib with the following differences:
+#
+# - Does not make any global changes to the LIBS define.
+#
+# - Strips out the -Werror flag from CFLAGS before running the test,
+# as these feature tests will often fail if -Werror is used.
+#
+# Returns the result of cc-check-function-in-lib (i.e. true or false).
+# The resulting linker flags are stored in the [define] named
+# lib_${function}.
+#
+proc proj-check-function-in-lib {function libs {otherlibs {}}} {
+ set found 0
+ define-push {LIBS CFLAGS} {
+ #puts "CFLAGS before=[get-define CFLAGS]"
+ define CFLAGS [proj-cflags-without-werror]
+ #puts "CFLAGS after =[get-define CFLAGS]"
+ set found [cc-check-function-in-lib $function $libs $otherlibs]
+ }
+ return $found
+}
+
+#
+# @proj-search-for-header-dir ?-dirs LIST? ?-subdirs LIST? header
+#
+# Searches for $header in a combination of dirs and subdirs, specified
+# by the -dirs {LIST} and -subdirs {LIST} flags (each of which have
+# sane defaults). Returns either the first matching dir or an empty
+# string. The return value does not contain the filename part.
+#
+proc proj-search-for-header-dir {header args} {
+ set subdirs {include}
+ set dirs {/usr /usr/local /mingw}
+# Debatable:
+# if {![proj-is-cross-compiling]} {
+# lappend dirs [get-define prefix]
+# }
+ while {[llength $args]} {
+ switch -exact -- [lindex $args 0] {
+ -dirs { set args [lassign $args - dirs] }
+ -subdirs { set args [lassign $args - subdirs] }
+ default {
+ proj-error "Unhandled argument: $args"
+ }
+ }
+ }
+ foreach dir $dirs {
+ foreach sub $subdirs {
+ if {[file exists $dir/$sub/$header]} {
+ return "$dir/$sub"
+ }
+ }
+ }
+ return ""
+}
+
+#
+# @proj-find-executable-path ?-v? binaryName
+#
+# Works similarly to autosetup's [find-executable-path $binName] but:
+#
+# - If the first arg is -v, it's verbose about searching, else it's quiet.
+#
+# Returns the full path to the result or an empty string.
+#
+proc proj-find-executable-path {args} {
+ set binName $args
+ set verbose 0
+ if {[lindex $args 0] eq "-v"} {
+ set verbose 1
+ set args [lassign $args - binName]
+ msg-checking "Looking for $binName ... "
+ }
+ set check [find-executable-path $binName]
+ if {$verbose} {
+ if {"" eq $check} {
+ msg-result "not found"
+ } else {
+ msg-result $check
+ }
+ }
+ return $check
+}
+
+#
+# @proj-bin-define binName ?defName?
+#
+# Uses [proj-find-executable-path $binName] to (verbosely) search for
+# a binary, sets a define (see below) to the result, and returns the
+# result (an empty string if not found).
+#
+# The define'd name is: If $defName is not empty, it is used as-is. If
+# $defName is empty then "BIN_X" is used, where X is the upper-case
+# form of $binName with any '-' characters replaced with '_'.
+#
+proc proj-bin-define {binName {defName {}}} {
+ set check [proj-find-executable-path -v $binName]
+ if {"" eq $defName} {
+ set defName "BIN_[string toupper [string map {- _} $binName]]"
+ }
+ define $defName $check
+ return $check
+}
+
+#
+# @proj-first-bin-of bin...
+#
+# Looks for the first binary found of the names passed to this
+# function. If a match is found, the full path to that binary is
+# returned, else "" is returned.
+#
+# Despite using cc-path-progs to do the search, this function clears
+# any define'd name that function stores for the result (because the
+# caller has no sensible way of knowing which result it was unless
+# they pass only a single argument).
+#
+proc proj-first-bin-of {args} {
+ set rc ""
+ foreach b $args {
+ set u [string toupper $b]
+ # Note that cc-path-progs defines $u to "false" if it finds no
+ # match.
+ if {[cc-path-progs $b]} {
+ set rc [get-define $u]
+ }
+ undefine $u
+ if {"" ne $rc} break
+ }
+ return $rc
+}
+
+#
+# @proj-opt-was-provided key
+#
+# Returns 1 if the user specifically provided the given configure flag
+# or if it was specifically set using proj-opt-set, else 0. This can
+# be used to distinguish between options which have a default value
+# and those which were explicitly provided by the user, even if the
+# latter is done in a way which uses the default value.
+#
+# For example, with a configure flag defined like:
+#
+# { foo-bar:=baz => {its help text} }
+#
+# This function will, when passed foo-bar, return 1 only if the user
+# passes --foo-bar to configure, even if that invocation would resolve
+# to the default value of baz. If the user does not explicitly pass in
+# --foo-bar (with or without a value) then this returns 0.
+#
+# Calling [proj-opt-set] is, for purposes of the above, equivalent to
+# explicitly passing in the flag.
+#
+# Note: unlike most functions which deal with configure --flags, this
+# one does not validate that $key refers to a pre-defined flag. i.e.
+# it accepts arbitrary keys, even those not defined via an [options]
+# call. [proj-opt-set] manipulates the internal list of flags, such
+# that new options set via that function will cause this function to
+# return true. (That's an unintended and unavoidable side-effect, not
+# specifically a feature which should be made use of.)
+#
+proc proj-opt-was-provided {key} {
+ dict exists $::autosetup(optset) $key
+}
+
+#
+# @proj-opt-set flag ?val?
+#
+# Force-set autosetup option $flag to $val. The value can be fetched
+# later with [opt-val], [opt-bool], and friends.
+#
+# Returns $val.
+#
+proc proj-opt-set {flag {val 1}} {
+ if {$flag ni $::autosetup(options)} {
+ # We have to add this to autosetup(options) or else future calls
+ # to [opt-bool $flag] will fail validation of $flag.
+ lappend ::autosetup(options) $flag
+ }
+ dict set ::autosetup(optset) $flag $val
+ return $val
+}
+
+#
+# @proj-opt-exists flag
+#
+# Returns 1 if the given flag has been defined as a legal configure
+# option, else returns 0.
+#
+proc proj-opt-exists {flag} {
+ expr {$flag in $::autosetup(options)};
+}
+
+#
+# @proj-val-truthy val
+#
+# Returns 1 if $val appears to be a truthy value, else returns
+# 0. Truthy values are any of {1 on true yes enabled}
+#
+proc proj-val-truthy {val} {
+ expr {$val in {1 on true yes enabled}}
+}
+
+#
+# @proj-opt-truthy flag
+#
+# Returns 1 if [opt-val $flag] appears to be a truthy value or
+# [opt-bool $flag] is true. See proj-val-truthy.
+#
+proc proj-opt-truthy {flag} {
+ if {[proj-val-truthy [opt-val $flag]]} { return 1 }
+ set rc 0
+ catch {
+ # opt-bool will throw if $flag is not a known boolean flag
+ set rc [opt-bool $flag]
+ }
+ return $rc
+}
+
+#
+# @proj-if-opt-truthy boolFlag thenScript ?elseScript?
+#
+# If [proj-opt-truthy $flag] is true, eval $then, else eval $else.
+#
+proc proj-if-opt-truthy {boolFlag thenScript {elseScript {}}} {
+ if {[proj-opt-truthy $boolFlag]} {
+ uplevel 1 $thenScript
+ } else {
+ uplevel 1 $elseScript
+ }
+}
+
+#
+# @proj-define-for-opt flag def ?msg? ?iftrue? ?iffalse?
+#
+# If [proj-opt-truthy $flag] then [define $def $iftrue] else [define
+# $def $iffalse]. If $msg is not empty, output [msg-checking $msg] and
+# a [msg-results ...] which corresponds to the result. Returns 1 if
+# the opt-truthy check passes, else 0.
+#
+proc proj-define-for-opt {flag def {msg ""} {iftrue 1} {iffalse 0}} {
+ if {"" ne $msg} {
+ msg-checking "$msg "
+ }
+ set rcMsg ""
+ set rc 0
+ if {[proj-opt-truthy $flag]} {
+ define $def $iftrue
+ set rc 1
+ } else {
+ define $def $iffalse
+ }
+ switch -- [proj-val-truthy [get-define $def]] {
+ 0 { set rcMsg no }
+ 1 { set rcMsg yes }
+ }
+ if {"" ne $msg} {
+ msg-result $rcMsg
+ }
+ return $rc
+}
+
+#
+# @proj-opt-define-bool ?-v? optName defName ?descr?
+#
+# Checks [proj-opt-truthy $optName] and calls [define $defName X]
+# where X is 0 for false and 1 for true. $descr is an optional
+# [msg-checking] argument which defaults to $defName. Returns X.
+#
+# If args[0] is -v then the boolean semantics are inverted: if
+# the option is set, it gets define'd to 0, else 1. Returns the
+# define'd value.
+#
+proc proj-opt-define-bool {args} {
+ set invert 0
+ if {[lindex $args 0] eq "-v"} {
+ incr invert
+ lassign $args - optName defName descr
+ } else {
+ lassign $args optName defName descr
+ }
+ if {"" eq $descr} {
+ set descr $defName
+ }
+ #puts "optName=$optName defName=$defName descr=$descr"
+ set rc 0
+ msg-checking "[join $descr] ... "
+ set rc [proj-opt-truthy $optName]
+ if {$invert} {
+ set rc [expr {!$rc}]
+ }
+ msg-result $rc
+ define $defName $rc
+ return $rc
+}
+
+#
+# @proj-check-module-loader
+#
+# Check for module-loading APIs (libdl/libltdl)...
+#
+# Looks for libltdl or dlopen(), the latter either in -ldl or built in
+# to libc (as it is on some platforms). Returns 1 if found, else
+# 0. Either way, it `define`'s:
+#
+# - HAVE_LIBLTDL to 1 or 0 if libltdl is found/not found
+# - HAVE_LIBDL to 1 or 0 if dlopen() is found/not found
+# - LDFLAGS_MODULE_LOADER one of ("-lltdl", "-ldl", or ""), noting
+# that -ldl may legally be empty on some platforms even if
+# HAVE_LIBDL is true (indicating that dlopen() is available without
+# extra link flags). LDFLAGS_MODULE_LOADER also gets "-rdynamic" appended
+# to it because otherwise trying to open DLLs will result in undefined
+# symbol errors.
+#
+# Note that if it finds LIBLTDL it does not look for LIBDL, so will
+# report only that is has LIBLTDL.
+#
+proc proj-check-module-loader {} {
+ msg-checking "Looking for module-loader APIs... "
+ if {99 ne [get-define LDFLAGS_MODULE_LOADER 99]} {
+ if {1 eq [get-define HAVE_LIBLTDL 0]} {
+ msg-result "(cached) libltdl"
+ return 1
+ } elseif {1 eq [get-define HAVE_LIBDL 0]} {
+ msg-result "(cached) libdl"
+ return 1
+ }
+ # else: wha???
+ }
+ set HAVE_LIBLTDL 0
+ set HAVE_LIBDL 0
+ set LDFLAGS_MODULE_LOADER ""
+ set rc 0
+ puts "" ;# cosmetic kludge for cc-check-XXX
+ if {[cc-check-includes ltdl.h] && [cc-check-function-in-lib lt_dlopen ltdl]} {
+ set HAVE_LIBLTDL 1
+ set LDFLAGS_MODULE_LOADER "-lltdl -rdynamic"
+ msg-result " - Got libltdl."
+ set rc 1
+ } elseif {[cc-with {-includes dlfcn.h} {
+ cctest -link 1 -declare "extern char* dlerror(void);" -code "dlerror();"}]} {
+ msg-result " - This system can use dlopen() without -ldl."
+ set HAVE_LIBDL 1
+ set LDFLAGS_MODULE_LOADER ""
+ set rc 1
+ } elseif {[cc-check-includes dlfcn.h]} {
+ set HAVE_LIBDL 1
+ set rc 1
+ if {[cc-check-function-in-lib dlopen dl]} {
+ msg-result " - dlopen() needs libdl."
+ set LDFLAGS_MODULE_LOADER "-ldl -rdynamic"
+ } else {
+ msg-result " - dlopen() not found in libdl. Assuming dlopen() is built-in."
+ set LDFLAGS_MODULE_LOADER "-rdynamic"
+ }
+ }
+ define HAVE_LIBLTDL $HAVE_LIBLTDL
+ define HAVE_LIBDL $HAVE_LIBDL
+ define LDFLAGS_MODULE_LOADER $LDFLAGS_MODULE_LOADER
+ return $rc
+}
+
+#
+# @proj-no-check-module-loader
+#
+# Sets all flags which would be set by proj-check-module-loader to
+# empty/falsy values, as if those checks had failed to find a module
+# loader. Intended to be called in place of that function when
+# a module loader is explicitly not desired.
+#
+proc proj-no-check-module-loader {} {
+ define HAVE_LIBDL 0
+ define HAVE_LIBLTDL 0
+ define LDFLAGS_MODULE_LOADER ""
+}
+
+#
+# @proj-file-content ?-trim? filename
+#
+# Opens the given file, reads all of its content, and returns it. If
+# the first arg is -trim, the contents of the file named by the second
+# argument are trimmed before returning them.
+#
+proc proj-file-content {args} {
+ set trim 0
+ set fname $args
+ if {"-trim" eq [lindex $args 0]} {
+ set trim 1
+ lassign $args - fname
+ }
+ set fp [open $fname rb]
+ set rc [read $fp]
+ close $fp
+ if {$trim} { return [string trim $rc] }
+ return $rc
+}
+
+#
+# @proj-file-conent filename
+#
+# Returns the contents of the given file as an array of lines, with
+# the EOL stripped from each input line.
+#
+proc proj-file-content-list {fname} {
+ set fp [open $fname rb]
+ set rc {}
+ while { [gets $fp line] >= 0 } {
+ lappend rc $line
+ }
+ close $fp
+ return $rc
+}
+
+#
+# @proj-file-write ?-ro? fname content
+#
+# Works like autosetup's [writefile] but explicitly uses binary mode
+# to avoid EOL translation on Windows. If $fname already exists, it is
+# overwritten, even if it's flagged as read-only.
+#
+proc proj-file-write {args} {
+ if {"-ro" eq [lindex $args 0]} {
+ lassign $args ro fname content
+ } else {
+ set ro ""
+ lassign $args fname content
+ }
+ file delete -force -- $fname; # in case it's read-only
+ set f [open $fname wb]
+ puts -nonewline $f $content
+ close $f
+ if {"" ne $ro} {
+ catch {
+ exec chmod -w $fname
+ #file attributes -w $fname; #jimtcl has no 'attributes'
+ }
+ }
+}
+
+#
+# @proj-check-compile-commands ?configFlag?
+#
+# Checks the compiler for compile_commands.json support. If passed an
+# argument it is assumed to be the name of an autosetup boolean config
+# which controls whether to run/skip this check.
+#
+# Returns 1 if supported, else 0, and defines HAVE_COMPILE_COMMANDS to
+# that value. Defines MAKE_COMPILATION_DB to "yes" if supported, "no"
+# if not. The use of MAKE_COMPILATION_DB is deprecated/discouraged:
+# HAVE_COMPILE_COMMANDS is preferred.
+#
+# ACHTUNG: this test has a long history of false positive results
+# because of compilers reacting differently to the -MJ flag.
+#
+proc proj-check-compile-commands {{configFlag {}}} {
+ msg-checking "compile_commands.json support... "
+ if {"" ne $configFlag && ![proj-opt-truthy $configFlag]} {
+ msg-result "explicitly disabled"
+ define HAVE_COMPILE_COMMANDS 0
+ define MAKE_COMPILATION_DB no
+ return 0
+ } else {
+ if {[cctest -lang c -cflags {/dev/null -MJ} -source {}]} {
+ # This test reportedly incorrectly succeeds on one of
+ # Martin G.'s older systems. drh also reports a false
+ # positive on an unspecified older Mac system.
+ msg-result "compiler supports compile_commands.json"
+ define MAKE_COMPILATION_DB yes; # deprecated
+ define HAVE_COMPILE_COMMANDS 1
+ return 1
+ } else {
+ msg-result "compiler does not support compile_commands.json"
+ define MAKE_COMPILATION_DB no
+ define HAVE_COMPILE_COMMANDS 0
+ return 0
+ }
+ }
+}
+
+#
+# @proj-touch filename
+#
+# Runs the 'touch' external command on one or more files, ignoring any
+# errors.
+#
+proc proj-touch {filename} {
+ catch { exec touch {*}$filename }
+}
+
+#
+# @proj-make-from-dot-in ?-touch? infile ?outfile?
+#
+# Uses [make-template] to create makefile(-like) file(s) $outfile from
+# $infile but explicitly makes the output read-only, to avoid
+# inadvertent editing (who, me?).
+#
+# If $outfile is empty then:
+#
+# - If $infile is a 2-element list, it is assumed to be an in/out pair,
+# and $outfile is set from the 2nd entry in that list. Else...
+#
+# - $outfile is set to $infile stripped of its extension.
+#
+# If the first argument is -touch then the generated file is touched
+# to update its timestamp. This can be used as a workaround for
+# cases where (A) autosetup does not update the file because it was
+# not really modified and (B) the file *really* needs to be updated to
+# please the build process.
+#
+# Failures when running chmod or touch are silently ignored.
+#
+proc proj-make-from-dot-in {args} {
+ set fIn ""
+ set fOut ""
+ set touch 0
+ if {[lindex $args 0] eq "-touch"} {
+ set touch 1
+ lassign $args - fIn fOut
+ } else {
+ lassign $args fIn fOut
+ }
+ if {"" eq $fOut} {
+ if {[llength $fIn]>1} {
+ lassign $fIn fIn fOut
+ } else {
+ set fOut [file rootname $fIn]
+ }
+ }
+ #puts "filenames=$filename"
+ if {[file exists $fOut]} {
+ catch { exec chmod u+w $fOut }
+ }
+ #puts "making template: $fIn ==> $fOut"
+ #define-push {top_srcdir} {
+ #puts "--- $fIn $fOut top_srcdir=[get-define top_srcdir]"
+ make-template $fIn $fOut
+ #puts "--- $fIn $fOut top_srcdir=[get-define top_srcdir]"
+ # make-template modifies top_srcdir
+ #}
+ if {$touch} {
+ proj-touch $fOut
+ }
+ catch {
+ exec chmod -w $fOut
+ #file attributes -w $f; #jimtcl has no 'attributes'
+ }
+}
+
+#
+# @proj-check-profile-flag ?flagname?
+#
+# Checks for the boolean configure option named by $flagname. If set,
+# it checks if $CC seems to refer to gcc. If it does (or appears to)
+# then it defines CC_PROFILE_FLAG to "-pg" and returns 1, else it
+# defines CC_PROFILE_FLAG to "" and returns 0.
+#
+# Note that the resulting flag must be added to both CFLAGS and
+# LDFLAGS in order for binaries to be able to generate "gmon.out". In
+# order to avoid potential problems with escaping, space-containing
+# tokens, and interfering with autosetup's use of these vars, this
+# routine does not directly modify CFLAGS or LDFLAGS.
+#
+proc proj-check-profile-flag {{flagname profile}} {
+ #puts "flagname=$flagname ?[proj-opt-truthy $flagname]?"
+ if {[proj-opt-truthy $flagname]} {
+ set CC [get-define CC]
+ regsub {.*ccache *} $CC "" CC
+ # ^^^ if CC="ccache gcc" then [exec] treats "ccache gcc" as a
+ # single binary name and fails. So strip any leading ccache part
+ # for this purpose.
+ if { ![catch { exec $CC --version } msg]} {
+ if {[string first gcc $CC] != -1} {
+ define CC_PROFILE_FLAG "-pg"
+ return 1
+ }
+ }
+ }
+ define CC_PROFILE_FLAG ""
+ return 0
+}
+
+#
+# @proj-looks-like-windows ?key?
+#
+# Returns 1 if this appears to be a Windows environment (MinGw,
+# Cygwin, MSys), else returns 0. The optional argument is the name of
+# an autosetup define which contains platform name info, defaulting to
+# "host" (meaning, somewhat counterintuitively, the target system, not
+# the current host). The other legal value is "build" (the build
+# machine, i.e. the local host). If $key == "build" then some
+# additional checks may be performed which are not applicable when
+# $key == "host".
+#
+proc proj-looks-like-windows {{key host}} {
+ global autosetup
+ switch -glob -- [get-define $key] {
+ *-*-ming* - *-*-cygwin - *-*-msys - *windows* {
+ return 1
+ }
+ }
+ if {$key eq "build"} {
+ # These apply only to the local OS, not a cross-compilation target,
+ # as the above check potentially can.
+ if {$::autosetup(iswin)} { return 1 }
+ if {[find-an-executable cygpath] ne "" || $::tcl_platform(os) eq "Windows NT"} {
+ return 1
+ }
+ }
+ return 0
+}
+
+#
+# @proj-looks-like-mac ?key?
+#
+# Looks at either the 'host' (==compilation target platform) or
+# 'build' (==the being-built-on platform) define value and returns if
+# if that value seems to indicate that it represents a Mac platform,
+# else returns 0.
+#
+proc proj-looks-like-mac {{key host}} {
+ switch -glob -- [get-define $key] {
+ *apple* {
+ return 1
+ }
+ default {
+ return 0
+ }
+ }
+}
+
+#
+# @proj-exe-extension
+#
+# Checks autosetup's "host" and "build" defines to see if the build
+# host and target are Windows-esque (Cygwin, MinGW, MSys). If the
+# build environment is then BUILD_EXEEXT is [define]'d to ".exe", else
+# "". If the target, a.k.a. "host", is then TARGET_EXEEXT is
+# [define]'d to ".exe", else "".
+#
+proc proj-exe-extension {} {
+ set rH ""
+ set rB ""
+ if {[proj-looks-like-windows host]} {
+ set rH ".exe"
+ }
+ if {[proj-looks-like-windows build]} {
+ set rB ".exe"
+ }
+ define BUILD_EXEEXT $rB
+ define TARGET_EXEEXT $rH
+}
+
+#
+# @proj-dll-extension
+#
+# Works like proj-exe-extension except that it defines BUILD_DLLEXT
+# and TARGET_DLLEXT to one of (.so, ,dll, .dylib).
+#
+# Trivia: for .dylib files, the linker needs the -dynamiclib flag
+# instead of -shared.
+#
+proc proj-dll-extension {} {
+ set inner {{key} {
+ switch -glob -- [get-define $key] {
+ *apple* {
+ return ".dylib"
+ }
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ return ".dll"
+ }
+ default {
+ return ".so"
+ }
+ }
+ }}
+ define BUILD_DLLEXT [apply $inner build]
+ define TARGET_DLLEXT [apply $inner host]
+}
+
+#
+# @proj-lib-extension
+#
+# Static-library counterpart of proj-dll-extension. Defines
+# BUILD_LIBEXT and TARGET_LIBEXT to the conventional static library
+# extension for the being-built-on resp. the target platform.
+#
+proc proj-lib-extension {} {
+ set inner {{key} {
+ switch -glob -- [get-define $key] {
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ return ".a"
+ # ^^^ this was ".lib" until 2025-02-07. See
+ # https://sqlite.org/forum/forumpost/02db2d4240
+ }
+ default {
+ return ".a"
+ }
+ }
+ }}
+ define BUILD_LIBEXT [apply $inner build]
+ define TARGET_LIBEXT [apply $inner host]
+}
+
+#
+# @proj-file-extensions
+#
+# Calls all of the proj-*-extension functions.
+#
+proc proj-file-extensions {} {
+ proj-exe-extension
+ proj-dll-extension
+ proj-lib-extension
+}
+
+#
+# @proj-affirm-files-exist ?-v? filename...
+#
+# Expects a list of file names. If any one of them does not exist in
+# the filesystem, it fails fatally with an informative message.
+# Returns the last file name it checks. If the first argument is -v
+# then it emits msg-checking/msg-result messages for each file.
+#
+proc proj-affirm-files-exist {args} {
+ set rc ""
+ set verbose 0
+ if {[lindex $args 0] eq "-v"} {
+ set verbose 1
+ set args [lrange $args 1 end]
+ }
+ foreach f $args {
+ if {$verbose} { msg-checking "Looking for $f ... " }
+ if {![file exists $f]} {
+ user-error "not found: $f"
+ }
+ if {$verbose} { msg-result "" }
+ set rc $f
+ }
+ return rc
+}
+
+#
+# @proj-check-emsdk
+#
+# Emscripten is used for doing in-tree builds of web-based WASM stuff,
+# as opposed to WASI-based WASM or WASM binaries we import from other
+# places. This is only set up for Unix-style OSes and is untested
+# anywhere but Linux. Requires that the --with-emsdk flag be
+# registered with autosetup.
+#
+# It looks for the SDK in the location specified by --with-emsdk.
+# Values of "" or "auto" mean to check for the environment var EMSDK
+# (which gets set by the emsdk_env.sh script from the SDK) or that
+# same var passed to configure.
+#
+# If the given directory is found, it expects to find emsdk_env.sh in
+# that directory, as well as the emcc compiler somewhere under there.
+#
+# If the --with-emsdk[=DIR] flag is explicitly provided and the SDK is
+# not found then a fatal error is generated, otherwise failure to find
+# the SDK is not fatal.
+#
+# Defines the following:
+#
+# - HAVE_EMSDK = 0 or 1 (this function's return value)
+# - EMSDK_HOME = "" or top dir of the emsdk
+# - EMSDK_ENV_SH = "" or $EMSDK_HOME/emsdk_env.sh
+# - BIN_EMCC = "" or $EMSDK_HOME/upstream/emscripten/emcc
+#
+# Returns 1 if EMSDK_ENV_SH is found, else 0. If EMSDK_HOME is not empty
+# but BIN_EMCC is then emcc was not found in the EMSDK_HOME, in which
+# case we have to rely on the fact that sourcing $EMSDK_ENV_SH from a
+# shell will add emcc to the $PATH.
+#
+proc proj-check-emsdk {} {
+ set emsdkHome [opt-val with-emsdk]
+ define EMSDK_HOME ""
+ define EMSDK_ENV_SH ""
+ define BIN_EMCC ""
+ set hadValue [llength $emsdkHome]
+ msg-checking "Emscripten SDK? "
+ if {$emsdkHome in {"" "auto"}} {
+ # Check the environment. $EMSDK gets set by sourcing emsdk_env.sh.
+ set emsdkHome [get-env EMSDK ""]
+ }
+ set rc 0
+ if {$emsdkHome ne ""} {
+ define EMSDK_HOME $emsdkHome
+ set emsdkEnv "$emsdkHome/emsdk_env.sh"
+ if {[file exists $emsdkEnv]} {
+ msg-result "$emsdkHome"
+ define EMSDK_ENV_SH $emsdkEnv
+ set rc 1
+ set emcc "$emsdkHome/upstream/emscripten/emcc"
+ if {[file exists $emcc]} {
+ define BIN_EMCC $emcc
+ }
+ } else {
+ msg-result "emsdk_env.sh not found in $emsdkHome"
+ }
+ } else {
+ msg-result "not found"
+ }
+ if {$hadValue && 0 == $rc} {
+ # Fail if it was explicitly requested but not found
+ proj-fatal "Cannot find the Emscripten SDK"
+ }
+ define HAVE_EMSDK $rc
+ return $rc
+}
+
+#
+# @proj-cc-check-Wl-flag ?flag ?args??
+#
+# Checks whether the given linker flag (and optional arguments) can be
+# passed from the compiler to the linker using one of these formats:
+#
+# - -Wl,flag[,arg1[,...argN]]
+# - -Wl,flag -Wl,arg1 ...-Wl,argN
+#
+# If so, that flag string is returned, else an empty string is
+# returned.
+#
+proc proj-cc-check-Wl-flag {args} {
+ cc-with {-link 1} {
+ # Try -Wl,flag,...args
+ set fli "-Wl"
+ foreach f $args { append fli ",$f" }
+ if {[cc-check-flags $fli]} {
+ return $fli
+ }
+ # Try -Wl,flag -Wl,arg1 ...-Wl,argN
+ set fli ""
+ foreach f $args { append fli "-Wl,$f " }
+ if {[cc-check-flags $fli]} {
+ return [string trim $fli]
+ }
+ return ""
+ }
+}
+
+#
+# @proj-check-rpath
+#
+# Tries various approaches to handling the -rpath link-time
+# flag. Defines LDFLAGS_RPATH to that/those flag(s) or an empty
+# string. Returns 1 if it finds an option, else 0.
+#
+# By default, the rpath is set to $prefix/lib. However, if either of
+# --exec-prefix=... or --libdir=... are explicitly passed to
+# configure then [get-define libdir] is used (noting that it derives
+# from exec-prefix by default).
+#
+proc proj-check-rpath {} {
+ if {[proj-opt-was-provided libdir]
+ || [proj-opt-was-provided exec-prefix]} {
+ set lp "[get-define libdir]"
+ } else {
+ set lp "[get-define prefix]/lib"
+ }
+ # If we _don't_ use cc-with {} here (to avoid updating the global
+ # CFLAGS or LIBS or whatever it is that cc-check-flags updates) then
+ # downstream tests may fail because the resulting rpath gets
+ # implicitly injected into them.
+ cc-with {-link 1} {
+ if {[cc-check-flags "-rpath $lp"]} {
+ define LDFLAGS_RPATH "-rpath $lp"
+ } else {
+ set wl [proj-cc-check-Wl-flag -rpath $lp]
+ if {"" eq $wl} {
+ set wl [proj-cc-check-Wl-flag -R$lp]
+ }
+ define LDFLAGS_RPATH $wl
+ }
+ }
+ expr {"" ne [get-define LDFLAGS_RPATH]}
+}
+
+#
+# @proj-check-soname ?libname?
+#
+# Checks whether CC supports the -Wl,soname,lib... flag. If so, it
+# returns 1 and defines LDFLAGS_SONAME_PREFIX to the flag's prefix, to
+# which the client would need to append "libwhatever.N". If not, it
+# returns 0 and defines LDFLAGS_SONAME_PREFIX to an empty string.
+#
+# The libname argument is only for purposes of running the flag
+# compatibility test, and is not included in the resulting
+# LDFLAGS_SONAME_PREFIX. It is provided so that clients may
+# potentially avoid some end-user confusion by using their own lib's
+# name here (which shows up in the "checking..." output).
+#
+proc proj-check-soname {{libname "libfoo.so.0"}} {
+ cc-with {-link 1} {
+ if {[cc-check-flags "-Wl,-soname,${libname}"]} {
+ define LDFLAGS_SONAME_PREFIX "-Wl,-soname,"
+ return 1
+ } else {
+ define LDFLAGS_SONAME_PREFIX ""
+ return 0
+ }
+ }
+}
+
+#
+# @proj-check-fsanitize ?list-of-opts?
+#
+# Checks whether CC supports -fsanitize=X, where X is each entry of
+# the given list of flags. If any of those flags are supported, it
+# returns the string "-fsanitize=X..." where X... is a comma-separated
+# list of all flags from the original set which are supported. If none
+# of the given options are supported then it returns an empty string.
+#
+# Example:
+#
+# set f [proj-check-fsanitize {address bounds-check just-testing}]
+#
+# Will, on many systems, resolve to "-fsanitize=address,bounds-check",
+# but may also resolve to "-fsanitize=address".
+#
+proc proj-check-fsanitize {{opts {address bounds-strict}}} {
+ set sup {}
+ foreach opt $opts {
+ # -nooutput is used because -fsanitize=hwaddress will otherwise
+ # pass this test on x86_64, but then warn at build time that
+ # "hwaddress is not supported for this target".
+ cc-with {-nooutput 1} {
+ if {[cc-check-flags "-fsanitize=$opt"]} {
+ lappend sup $opt
+ }
+ }
+ }
+ if {[llength $sup] > 0} {
+ return "-fsanitize=[join $sup ,]"
+ }
+ return ""
+}
+
+#
+# Internal helper for proj-dump-defs-json. Expects to be passed a
+# [define] name and the variadic $args which are passed to
+# proj-dump-defs-json. If it finds a pattern match for the given
+# $name in the various $args, it returns the type flag for that $name,
+# e.g. "-str" or "-bare", else returns an empty string.
+#
+proc proj-defs-type_ {name spec} {
+ foreach {type patterns} $spec {
+ foreach pattern $patterns {
+ if {[string match $pattern $name]} {
+ return $type
+ }
+ }
+ }
+ return ""
+}
+
+#
+# Internal helper for proj-defs-format_: returns a JSON-ish quoted
+# form of the given string-type values. It only performs the most
+# basic of escaping. The input must not contain any control
+# characters.
+#
+proc proj-quote-str_ {value} {
+ return \"[string map [list \\ \\\\ \" \\\"] $value]\"
+}
+
+#
+# An internal impl detail of proj-dump-defs-json. Requires a data
+# type specifier, as used by make-config-header, and a value. Returns
+# the formatted value or the value $::proj__Config(defs-skip) if the caller
+# should skip emitting that value.
+#
+set ::proj__Config(defs-skip) "-proj-defs-format_ sentinel"
+proc proj-defs-format_ {type value} {
+ switch -exact -- $type {
+ -bare {
+ # Just output the value unchanged
+ }
+ -none {
+ set value $::proj__Config(defs-skip)
+ }
+ -str {
+ set value [proj-quote-str_ $value]
+ }
+ -auto {
+ # Automatically determine the type
+ if {![string is integer -strict $value]} {
+ set value [proj-quote-str_ $value]
+ }
+ }
+ -array {
+ set ar {}
+ foreach v $value {
+ set v [proj-defs-format_ -auto $v]
+ if {$::proj__Config(defs-skip) ne $v} {
+ lappend ar $v
+ }
+ }
+ set value "\[ [join $ar {, }] \]"
+ }
+ "" {
+ set value $::proj__Config(defs-skip)
+ }
+ default {
+ proj-fatal "Unknown type in proj-dump-defs-json: $type"
+ }
+ }
+ return $value
+}
+
+#
+# @proj-dump-defs-json outfile ...flags
+#
+# This function works almost identically to autosetup's
+# make-config-header but emits its output in JSON form. It is not a
+# fully-functional JSON emitter, and will emit broken JSON for
+# complicated outputs, but should be sufficient for purposes of
+# emitting most configure vars (numbers and simple strings).
+#
+# In addition to the formatting flags supported by make-config-header,
+# it also supports:
+#
+# -array {patterns...}
+#
+# Any defines matching the given patterns will be treated as a list of
+# values, each of which will be formatted as if it were in an -auto {...}
+# set, and the define will be emitted to JSON in the form:
+#
+# "ITS_NAME": [ "value1", ...valueN ]
+#
+# Achtung: if a given -array pattern contains values which themselves
+# contains spaces...
+#
+# define-append foo {"-DFOO=bar baz" -DBAR="baz barre"}
+#
+# will lead to:
+#
+# ["-DFOO=bar baz", "-DBAR=\"baz", "barre\""]
+#
+# Neither is especially satisfactory (and the second is useless), and
+# handling of such values is subject to change if any such values ever
+# _really_ need to be processed by our source trees.
+#
+proc proj-dump-defs-json {file args} {
+ file mkdir [file dirname $file]
+ set lines {}
+ lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
+ foreach n [lsort [dict keys [all-defines]]] {
+ set type [proj-defs-type_ $n $args]
+ set value [proj-defs-format_ $type [get-define $n]]
+ if {$::proj__Config(defs-skip) ne $value} {
+ lappend lines "\"$n\": ${value}"
+ }
+ }
+ set buf {}
+ lappend buf [join $lines ",\n"]
+ write-if-changed $file $buf {
+ msg-result "Created $file"
+ }
+}
+
+#
+# @proj-xfer-option-aliases map
+#
+# Expects a list of pairs of configure flags which have been
+# registered with autosetup, in this form:
+#
+# { alias1 => canonical1
+# aliasN => canonicalN ... }
+#
+# The names must not have their leading -- part and must be in the
+# form which autosetup will expect for passing to [opt-val NAME] and
+# friends.
+#
+# Comment lines are permitted in the input.
+#
+# For each pair of ALIAS and CANONICAL, if --ALIAS is provided but
+# --CANONICAL is not, the value of the former is copied to the
+# latter. If --ALIAS is not provided, this is a no-op. If both have
+# explicitly been provided a fatal usage error is triggered.
+#
+# Motivation: autosetup enables "hidden aliases" in [options] lists,
+# and elides the aliases from --help output but does no further
+# handling of them. For example, when --alias is a hidden alias of
+# --canonical and a user passes --alias=X, [opt-val canonical] returns
+# no value. i.e. the script must check both [opt-val alias] and
+# [opt-val canonical]. The intent here is that this function be
+# passed such mappings immediately after [options] is called, to carry
+# over any values from hidden aliases into their canonical names, such
+# that [opt-value canonical] will return X if --alias=X is passed to
+# configure.
+#
+# That said: autosetup's [opt-str] does support alias forms, but it
+# requires that the caller know all possible aliases. It's simpler, in
+# terms of options handling, if there's only a single canonical name
+# which each down-stream call of [opt-...] has to know.
+#
+proc proj-xfer-options-aliases {mapping} {
+ foreach {hidden - canonical} [proj-strip-hash-comments $mapping] {
+ if {[proj-opt-was-provided $hidden]} {
+ if {[proj-opt-was-provided $canonical]} {
+ proj-fatal "both --$canonical and its alias --$hidden were used. Use only one or the other."
+ } else {
+ proj-opt-set $canonical [opt-val $hidden]
+ }
+ }
+ }
+}
+
+#
+# Arguable/debatable...
+#
+# When _not_ cross-compiling and CC_FOR_BUILD is _not_ explicitly
+# specified, force CC_FOR_BUILD to be the same as CC, so that:
+#
+# ./configure CC=clang
+#
+# will use CC_FOR_BUILD=clang, instead of cc, for building in-tree
+# tools. This is based off of an email discussion and is thought to
+# be likely to cause less confusion than seeing 'cc' invocations
+# when when the user passes CC=clang.
+#
+# Sidebar: if we do this before the cc package is installed, it gets
+# reverted by that package. Ergo, the cc package init will tell the
+# user "Build C compiler...cc" shortly before we tell them otherwise.
+#
+proc proj-redefine-cc-for-build {} {
+ if {![proj-is-cross-compiling]
+ && [get-define CC] ne [get-define CC_FOR_BUILD]
+ && "nope" eq [get-env CC_FOR_BUILD "nope"]} {
+ user-notice "Re-defining CC_FOR_BUILD to CC=[get-define CC]. To avoid this, explicitly pass CC_FOR_BUILD=..."
+ define CC_FOR_BUILD [get-define CC]
+ }
+}
+
+#
+# @proj-which-linenoise headerFile
+#
+# Attempts to determine whether the given linenoise header file is of
+# the "antirez" or "msteveb" flavor. It returns 2 for msteveb, else 1
+# (it does not validate that the header otherwise contains the
+# linenoise API).
+#
+proc proj-which-linenoise {dotH} {
+ set srcHeader [proj-file-content $dotH]
+ if {[string match *userdata* $srcHeader]} {
+ return 2
+ } else {
+ return 1
+ }
+}
+
+#
+# @proj-remap-autoconf-dir-vars
+#
+# "Re-map" the autoconf-conventional --XYZdir flags into something
+# which is more easily overridable from a make invocation.
+#
+# Based off of notes in <https://sqlite.org/forum/forumpost/00d12a41f7>.
+#
+# Consider:
+#
+# $ ./configure --prefix=/foo
+# $ make install prefix=/blah
+#
+# In that make invocation, $(libdir) would, at make-time, normally be
+# hard-coded to /foo/lib, rather than /blah/lib. That happens because
+# autosetup exports conventional $prefix-based values for the numerous
+# autoconfig-compatible XYZdir vars at configure-time. What we would
+# normally want, however, is that --libdir derives from the make-time
+# $(prefix). The distinction between configure-time and make-time is
+# the significant factor there.
+#
+# This function attempts to reconcile those vars in such a way that
+# they will derive, at make-time, from $(prefix) in a conventional
+# manner unless they are explicitly overridden at configure-time, in
+# which case those overrides takes precedence.
+#
+# Each autoconf-relvant --XYZ flag which is explicitly passed to
+# configure is exported as-is, as are those which default to some
+# top-level system directory, e.g. /etc or /var. All which derive
+# from either $prefix or $exec_prefix are exported in the form of a
+# Makefile var reference, e.g. libdir=${exec_prefix}/lib. Ergo, if
+# --exec-prefix=FOO is passed to configure, libdir will still derive,
+# at make-time, from whatever exec_prefix is passed to make, and will
+# use FOO if exec_prefix is not overridden at make-time. Without this
+# post-processing, libdir would be cemented in as FOO/lib at
+# configure-time, so could be tedious to override properly via a make
+# invocation.
+#
+proc proj-remap-autoconf-dir-vars {} {
+ set prefix [get-define prefix]
+ set exec_prefix [get-define exec_prefix $prefix]
+ # The following var derefs must be formulated such that they are
+ # legal for use in (A) makefiles, (B) pkgconfig files, and (C) TCL's
+ # [subst] command. i.e. they must use the form ${X}.
+ foreach {flag makeVar makeDeref} {
+ exec-prefix exec_prefix ${prefix}
+ datadir datadir ${prefix}/share
+ mandir mandir ${datadir}/man
+ includedir includedir ${prefix}/include
+ bindir bindir ${exec_prefix}/bin
+ libdir libdir ${exec_prefix}/lib
+ sbindir sbindir ${exec_prefix}/sbin
+ sysconfdir sysconfdir /etc
+ sharedstatedir sharedstatedir ${prefix}/com
+ localstatedir localstatedir /var
+ runstatedir runstatedir /run
+ infodir infodir ${datadir}/info
+ libexecdir libexecdir ${exec_prefix}/libexec
+ } {
+ if {[proj-opt-was-provided $flag]} {
+ define $makeVar [join [opt-val $flag]]
+ } else {
+ define $makeVar [join $makeDeref]
+ }
+ # Maintenance reminder: the [join] call is to avoid {braces}
+ # around the output when someone passes in,
+ # e.g. --libdir=\${prefix}/foo/bar. Debian's SQLite package build
+ # script does that.
+ }
+}
+
+#
+# @proj-env-file flag ?default?
+#
+# If a file named .env-$flag exists, this function returns a
+# trimmed copy of its contents, else it returns $dflt. The intended
+# usage is that things like developer-specific CFLAGS preferences can
+# be stored in .env-CFLAGS.
+#
+proc proj-env-file {flag {dflt ""}} {
+ set fn ".env-${flag}"
+ if {[file readable $fn]} {
+ return [proj-file-content -trim $fn]
+ }
+ return $dflt
+}
+
+#
+# @proj-get-env var ?default?
+#
+# Extracts the value of "environment" variable $var from the first of
+# the following places where it's defined:
+#
+# - Passed to configure as $var=...
+# - Exists as an environment variable
+# - A file named .env-$var (see [proj-env-file])
+#
+# If none of those are set, $dflt is returned.
+#
+proc proj-get-env {var {dflt ""}} {
+ get-env $var [proj-env-file $var $dflt]
+}
+
+#
+# @proj-scope ?lvl?
+#
+# Returns the name of the _calling_ proc from ($lvl + 1) levels up the
+# call stack (where the caller's level will be 1 up from _this_
+# call). If $lvl would resolve to global scope "global scope" is
+# returned and if it would be negative then a string indicating such
+# is returned (as opposed to throwing an error).
+#
+proc proj-scope {{lvl 0}} {
+ #uplevel [expr {$lvl + 1}] {lindex [info level 0] 0}
+ set ilvl [info level]
+ set offset [expr {$ilvl - $lvl - 1}]
+ if { $offset < 0} {
+ return "invalid scope ($offset)"
+ } elseif { $offset == 0} {
+ return "global scope"
+ } else {
+ return [lindex [info level $offset] 0]
+ }
+}
+
+#
+# Deprecated name of [proj-scope].
+#
+proc proj-current-scope {{lvl 0}} {
+ puts stderr \
+ "Deprecated proj-current-scope called from [proj-scope 1]. Use proj-scope instead."
+ proj-scope [incr lvl]
+}
+
+#
+# Converts parts of tclConfig.sh to autosetup [define]s.
+#
+# Expects to be passed the name of a value tclConfig.sh or an empty
+# string. It converts certain parts of that file's contents to
+# [define]s (see the code for the whole list). If $tclConfigSh is an
+# empty string then it [define]s the various vars as empty strings.
+#
+proc proj-tclConfig-sh-to-autosetup {tclConfigSh} {
+ set shBody {}
+ set tclVars {
+ TCL_INCLUDE_SPEC
+ TCL_LIBS
+ TCL_LIB_SPEC
+ TCL_STUB_LIB_SPEC
+ TCL_EXEC_PREFIX
+ TCL_PREFIX
+ TCL_VERSION
+ TCL_MAJOR_VERSION
+ TCL_MINOR_VERSION
+ TCL_PACKAGE_PATH
+ TCL_PATCH_LEVEL
+ TCL_SHLIB_SUFFIX
+ }
+ # Build a small shell script which proxies the $tclVars from
+ # $tclConfigSh into autosetup code...
+ lappend shBody "if test x = \"x${tclConfigSh}\"; then"
+ foreach v $tclVars {
+ lappend shBody "$v= ;"
+ }
+ lappend shBody "else . \"${tclConfigSh}\"; fi"
+ foreach v $tclVars {
+ lappend shBody "echo define $v {\$$v} ;"
+ }
+ lappend shBody "exit"
+ set shBody [join $shBody "\n"]
+ #puts "shBody=$shBody\n"; exit
+ eval [exec echo $shBody | sh]
+}
+
+#
+# @proj-tweak-default-env-dirs
+#
+# This function is not useful before [use system] is called to set up
+# --prefix and friends. It should be called as soon after [use system]
+# as feasible.
+#
+# For certain target environments, if --prefix is _not_ passed in by
+# the user, set the prefix to an environment-specific default. For
+# such environments its does [define prefix ...] and [proj-opt-set
+# prefix ...], but it does not process vars derived from the prefix,
+# e.g. exec-prefix. To do so it is generally necessary to also call
+# proj-remap-autoconf-dir-vars late in the config process (immediately
+# before ".in" files are filtered).
+#
+# Similar modifications may be made for --mandir.
+#
+# Returns 1 if it modifies the environment, else 0.
+#
+proc proj-tweak-default-env-dirs {} {
+ set rc 0
+ switch -glob -- [get-define host] {
+ *-haiku {
+ if {![proj-opt-was-provided prefix]} {
+ set hdir /boot/home/config/non-packaged
+ proj-opt-set prefix $hdir
+ define prefix $hdir
+ incr rc
+ }
+ if {![proj-opt-was-provided mandir]} {
+ set hdir /boot/system/documentation/man
+ proj-opt-set mandir $hdir
+ define mandir $hdir
+ incr rc
+ }
+ }
+ }
+ return $rc
+}
+
+#
+# @proj-dot-ins-append file ?fileOut ?postProcessScript??
+#
+# Queues up an autosetup [make-template]-style file to be processed
+# at a later time using [proj-dot-ins-process].
+#
+# $file is the input file. If $fileOut is empty then this function
+# derives $fileOut from $file, stripping both its directory and
+# extension parts. i.e. it defaults to writing the output to the
+# current directory (typically $::autosetup(builddir)).
+#
+# If $postProcessScript is not empty then, during
+# [proj-dot-ins-process], it will be eval'd immediately after
+# processing the file. In the context of that script, the vars
+# $dotInsIn and $dotInsOut will be set to the input and output file
+# names. This can be used, for example, to make the output file
+# executable or perform validation on its contents.
+#
+# See [proj-dot-ins-process], [proj-dot-ins-list]
+#
+proc proj-dot-ins-append {fileIn args} {
+ set srcdir $::autosetup(srcdir)
+ switch -exact -- [llength $args] {
+ 0 {
+ lappend fileIn [file rootname [file tail $fileIn]] ""
+ }
+ 1 {
+ lappend fileIn [join $args] ""
+ }
+ 2 {
+ lappend fileIn {*}$args
+ }
+ default {
+ proj-fatal "Too many arguments: $fileIn $args"
+ }
+ }
+ #puts "******* [proj-scope]: adding $fileIn"
+ lappend ::proj__Config(dot-in-files) $fileIn
+}
+
+#
+# @proj-dot-ins-list
+#
+# Returns the current list of [proj-dot-ins-append]'d files, noting
+# that each entry is a 3-element list of (inputFileName,
+# outputFileName, postProcessScript).
+#
+proc proj-dot-ins-list {} {
+ return $::proj__Config(dot-in-files)
+}
+
+#
+# @proj-dot-ins-process ?-touch? ?-validate? ?-clear?
+#
+# Each file which has previously been passed to [proj-dot-ins-append]
+# is processed, with its passing its in-file out-file names to
+# [proj-make-from-dot-in].
+#
+# The intent is that a project accumulate any number of files to
+# filter and delay their actual filtering until the last stage of the
+# configure script, calling this function at that time.
+#
+# Optional flags:
+#
+# -touch: gets passed on to [proj-make-from-dot-in]
+#
+# -validate: after processing each file, before running the file's
+# associated script, if any, it runs the file through
+# proj-validate-no-unresolved-ats, erroring out if that does.
+#
+# -clear: after processing, empty the dot-ins list. This effectively
+# makes proj-dot-ins-append available for re-use.
+#
+proc proj-dot-ins-process {args} {
+ proj-parse-simple-flags args flags {
+ -touch "" {return "-touch"}
+ -clear 0 {expr 1}
+ -validate 0 {expr 1}
+ }
+ if {[llength $args] > 0} {
+ error "Invalid argument to [proj-scope]: $args"
+ }
+ foreach f $::proj__Config(dot-in-files) {
+ proj-assert {3==[llength $f]} \
+ "Expecting proj-dot-ins-list to be stored in 3-entry lists"
+ lassign $f fIn fOut fScript
+ #puts "DOING $fIn ==> $fOut"
+ proj-make-from-dot-in {*}$flags(-touch) $fIn $fOut
+ if {$flags(-validate)} {
+ proj-validate-no-unresolved-ats $fOut
+ }
+ if {"" ne $fScript} {
+ uplevel 1 [join [list set dotInsIn $fIn \; \
+ set dotInsOut $fOut \; \
+ eval \{${fScript}\} \; \
+ unset dotInsIn dotInsOut]]
+ }
+ }
+ if {$flags(-clear)} {
+ set ::proj__Config(dot-in-files) [list]
+ }
+}
+
+#
+# @proj-validate-no-unresolved-ats filenames...
+#
+# For each filename given to it, it validates that the file has no
+# unresolved @VAR@ references. If it finds any, it produces an error
+# with location information.
+#
+# Exception: if a filename matches the pattern {*[Mm]ake*} AND a given
+# line begins with a # (not including leading whitespace) then that
+# line is ignored for purposes of this validation. The intent is that
+# @VAR@ inside of makefile comments should not (necessarily) cause
+# validation to fail, as it's sometimes convenient to comment out
+# sections during development of a configure script and its
+# corresponding makefile(s).
+#
+proc proj-validate-no-unresolved-ats {args} {
+ foreach f $args {
+ set lnno 1
+ set isMake [string match {*[Mm]ake*} $f]
+ foreach line [proj-file-content-list $f] {
+ if {!$isMake || ![string match "#*" [string trimleft $line]]} {
+ if {[regexp {(@[A-Za-z0-9_]+@)} $line match]} {
+ error "Unresolved reference to $match at line $lnno of $f"
+ }
+ }
+ incr lnno
+ }
+ }
+}
+
+#
+# @proj-first-file-found tgtVar fileList
+#
+# Searches $fileList for an existing file. If one is found, its name
+# is assigned to tgtVar and 1 is returned, else tgtVar is set to ""
+# and 0 is returned.
+#
+proc proj-first-file-found {tgtVar fileList} {
+ upvar $tgtVar tgt
+ foreach f $fileList {
+ if {[file exists $f]} {
+ set tgt $f
+ return 1
+ }
+ }
+ set tgt ""
+ return 0
+}
+
+#
+# Defines $defName to contain makefile recipe commands for re-running
+# the configure script with its current set of $::argv flags. This
+# can be used to automatically reconfigure.
+#
+proc proj-setup-autoreconfig {defName} {
+ define $defName \
+ [join [list \
+ cd \"$::autosetup(builddir)\" \
+ && [get-define AUTOREMAKE "error - missing @AUTOREMAKE@"]]]
+}
+
+#
+# @prop-append-to defineName args...
+#
+# A proxy for Autosetup's [define-append]. Appends all non-empty $args
+# to [define-append $defineName].
+#
+proc proj-define-append {defineName args} {
+ foreach a $args {
+ if {"" ne $a} {
+ define-append $defineName {*}$a
+ }
+ }
+}
+
+#
+# @prod-define-amend ?-p|-prepend? ?-d|-define? defineName args...
+#
+# A proxy for Autosetup's [define-append].
+#
+# Appends all non-empty $args to the define named by $defineName. If
+# one of (-p | -prepend) are used it instead prepends them, in their
+# given order, to $defineName.
+#
+# If -define is used then each argument is assumed to be a [define]'d
+# flag and [get-define X ""] is used to fetch it.
+#
+# Re. linker flags: typically, -lXYZ flags need to be in "reverse"
+# order, with each -lY resolving symbols for -lX's to its left. This
+# order is largely historical, and not relevant on all environments,
+# but it is technically correct and still relevant on some
+# environments.
+#
+# See: proj-append-to
+#
+proc proj-define-amend {args} {
+ set defName ""
+ set prepend 0
+ set isdefs 0
+ set xargs [list]
+ foreach arg $args {
+ switch -exact -- $arg {
+ "" {}
+ -p - -prepend { incr prepend }
+ -d - -define { incr isdefs }
+ default {
+ if {"" eq $defName} {
+ set defName $arg
+ } else {
+ lappend xargs $arg
+ }
+ }
+ }
+ }
+ if {"" eq $defName} {
+ proj-error "Missing defineName argument in call from [proj-scope 1]"
+ }
+ if {$isdefs} {
+ set args $xargs
+ set xargs [list]
+ foreach arg $args {
+ lappend xargs [get-define $arg ""]
+ }
+ set args $xargs
+ }
+# puts "**** args=$args"
+# puts "**** xargs=$xargs"
+
+ set args $xargs
+ if {$prepend} {
+ lappend args {*}[get-define $defName ""]
+ define $defName [join $args]; # join to eliminate {} entries
+ } else {
+ proj-define-append $defName {*}$args
+ }
+}
+
+#
+# @proj-define-to-cflag ?-list? ?-quote? ?-zero-undef? defineName...
+#
+# Treat each argument as the name of a [define] and renders it like a
+# CFLAGS value in one of the following forms:
+#
+# -D$name
+# -D$name=integer (strict integer matches only)
+# '-D$name=value' (without -quote)
+# '-D$name="value"' (with -quote)
+#
+# It treats integers as numbers and everything else as a quoted
+# string, noting that it does not handle strings which themselves
+# contain quotes.
+#
+# The -zero-undef flag causes no -D to be emitted for integer values
+# of 0.
+#
+# By default it returns the result as string of all -D... flags,
+# but if passed the -list flag it will return a list of the
+# individual CFLAGS.
+#
+proc proj-define-to-cflag {args} {
+ set rv {}
+ proj-parse-simple-flags args flags {
+ -list 0 {expr 1}
+ -quote 0 {expr 1}
+ -zero-undef 0 {expr 1}
+ }
+ foreach d $args {
+ set v [get-define $d ""]
+ set li {}
+ if {"" eq $d} {
+ set v "-D${d}"
+ } elseif {[string is integer -strict $v]} {
+ if {!$flags(-zero-undef) || $v ne "0"} {
+ set v "-D${d}=$v"
+ }
+ } elseif {$flags(-quote)} {
+ set v "'-D${d}=\"$v\"'"
+ } else {
+ set v "'-D${d}=$v'"
+ }
+ lappend rv $v
+ }
+ expr {$flags(-list) ? $rv : [join $rv]}
+}
+
+
+if {0} {
+ # Turns out that autosetup's [options-add] essentially does exactly
+ # this...
+
+ # A list of lists of Autosetup [options]-format --flags definitions.
+ # Append to this using [proj-options-add] and use
+ # [proj-options-combine] to merge them into a single list for passing
+ # to [options].
+ #
+ set ::proj__Config(extra-options) {}
+
+ # @proj-options-add list
+ #
+ # Adds a list of options to the pending --flag processing. It must be
+ # in the format used by Autosetup's [options] function.
+ #
+ # This will have no useful effect if called from after [options]
+ # is called.
+ #
+ # Use [proj-options-combine] to get a combined list of all added
+ # options.
+ #
+ # PS: when writing this i wasn't aware of autosetup's [options-add],
+ # works quite similarly. Only the timing is different.
+ proc proj-options-add {list} {
+ lappend ::proj__Config(extra-options) $list
+ }
+
+ # @proj-options-combine list1 ?...listN?
+ #
+ # Expects each argument to be a list of options compatible with
+ # autosetup's [options] function. This function concatenates the
+ # contents of each list into a new top-level list, stripping the outer
+ # list part of each argument, and returning that list
+ #
+ # If passed no arguments, it uses the list generated by calls to
+ # [proj-options-add].
+ proc proj-options-combine {args} {
+ set rv [list]
+ if {0 == [llength $args]} {
+ set args $::proj__Config(extra-options)
+ }
+ foreach e $args {
+ lappend rv {*}$e
+ }
+ return $rv
+ }
+}; # proj-options-*
+
+# Internal cache for use via proj-cache-*.
+array set proj__Cache {}
+
+#
+# @proj-cache-key arg {addLevel 0}
+#
+# Helper to generate cache keys for [proj-cache-*].
+#
+# $addLevel should almost always be 0.
+#
+# Returns a cache key for the given argument:
+#
+# integer: relative call stack levels to get the scope name of for
+# use as a key. [proj-scope [expr {1 + $arg + addLevel}]] is
+# then used to generate the key. i.e. the default of 0 uses the
+# calling scope's name as the key.
+#
+# Anything else: returned as-is
+#
+proc proj-cache-key {arg {addLevel 0}} {
+ if {[string is integer -strict $arg]} {
+ return [proj-scope [expr {$arg + $addLevel + 1}]]
+ }
+ return $arg
+}
+
+#
+# @proj-cache-set ?-key KEY? ?-level 0? value
+#
+# Sets a feature-check cache entry with the given key.
+#
+# See proj-cache-key for -key's and -level's semantics, noting that
+# this function adds one to -level for purposes of that call.
+proc proj-cache-set {args} {
+ proj-parse-simple-flags args flags {
+ -key => 0
+ -level => 0
+ }
+ lassign $args val
+ set key [proj-cache-key $flags(-key) [expr {1 + $flags(-level)}]]
+ #puts "** fcheck set $key = $val"
+ set ::proj__Cache($key) $val
+}
+
+#
+# @proj-cache-remove ?key? ?addLevel?
+#
+# Removes an entry from the proj-cache.
+proc proj-cache-remove {{key 0} {addLevel 0}} {
+ set key [proj-cache-key $key [expr {1 + $addLevel}]]
+ set rv ""
+ if {[info exists ::proj__Cache($key)]} {
+ set rv $::proj__Cache($key)
+ unset ::proj__Cache($key)
+ }
+ return $rv;
+}
+
+#
+# @proj-cache-check ?-key KEY? ?-level LEVEL? tgtVarName
+#
+# Checks for a feature-check cache entry with the given key.
+#
+# If the feature-check cache has a matching entry then this function
+# assigns its value to tgtVar and returns 1, else it assigns tgtVar to
+# "" and returns 0.
+#
+# See proj-cache-key for $key's and $addLevel's semantics, noting that
+# this function adds one to $addLevel for purposes of that call.
+proc proj-cache-check {args} {
+ proj-parse-simple-flags args flags {
+ -key => 0
+ -level => 0
+ }
+ lassign $args tgtVar
+ upvar $tgtVar tgt
+ set rc 0
+ set key [proj-cache-key $flags(-key) [expr {1 + $flags(-level)}]]
+ #puts "** fcheck get key=$key"
+ if {[info exists ::proj__Cache($key)]} {
+ set tgt $::proj__Cache($key)
+ incr rc
+ } else {
+ set tgt ""
+ }
+ return $rc
+}
+
+#
+# @proj-coalesce ...args
+#
+# Returns the first argument which is not empty (eq ""), or an empty
+# string on no match.
+proc proj-coalesce {args} {
+ foreach arg $args {
+ if {"" ne $arg} {
+ return $arg
+ }
+ }
+ return ""
+}
+
+#
+# @proj-parse-simple-flags ...
+#
+# A helper to parse flags from proc argument lists.
+#
+# Expects a list of arguments to parse, an array name to store any
+# -flag values to, and a prototype object which declares the flags.
+#
+# The prototype must be a list in one of the following forms:
+#
+# -flag defaultValue {script}
+#
+# -flag => defaultValue
+# -----^--^ (with spaces there!)
+#
+# Repeated for each flag.
+#
+# The first form represents a basic flag with no associated
+# following argument. The second form extracts its value
+# from the following argument in $argvName.
+#
+# The first argument to this function is the name of a var holding the
+# args to parse. It will be overwritten, possibly with a smaller list.
+#
+# The second argument the name of an array variable to create in the
+# caller's scope. (Pneumonic: => points to the next argument.)
+#
+# For the first form of flag, $script is run in the caller's scope if
+# $argv contains -flag, and the result of that script is the new value
+# for $tgtArrayName(-flag). This function intercepts [return $val]
+# from $script. Any empty script will result in the flag having ""
+# assigned to it.
+#
+# The args list is only inspected until the first argument which is
+# not described by $prototype. i.e. the first "non-flag" (not counting
+# values consumed for flags defined like --flag=>default).
+#
+# If a "--" flag is encountered, no more arguments are inspected as
+# flags. If "--" is the first non-flag argument, the "--" flag is
+# removed from the results but all remaining arguments are passed
+# through. If "--" appears after the first non-flag, it is retained.
+#
+# This function assumes that each flag is unique, and using a flag
+# more than once behaves in a last-one-wins fashion.
+#
+# Any argvName entries not described in $prototype are not treated as
+# flags.
+#
+# Returns the number of flags it processed in $argvName.
+#
+# Example:
+#
+# set args [list -foo -bar {blah} 8 9 10 -theEnd]
+# proj-parse-simple-flags args flags {
+# -foo 0 {expr 1}
+# -bar => 0
+# -no-baz 2 {return 0}
+# }
+#
+# After that $flags would contain {-foo 1 -bar {blah} -no-baz 2}
+# and $args would be {8 9 10 -theEnd}.
+#
+# Potential TODOs: consider using lappend instead of set so that any
+# given flag can be used more than once. Or add a syntax to indicate
+# that multiples are allowed. Also consider searching the whole
+# argv list, rather than stopping at the first non-flag
+#
+proc proj-parse-simple-flags {argvName tgtArrayName prototype} {
+ upvar $argvName argv
+ upvar $tgtArrayName tgt
+ array set dflt {}
+ array set scripts {}
+ array set consuming {}
+ set n [llength $prototype]
+ # Figure out what our flags are...
+ for {set i 0} {$i < $n} {incr i} {
+ set k [lindex $prototype $i]
+ #puts "**** #$i of $n k=$k"
+ proj-assert {[string match -* $k]} \
+ "Invalid flag value: $k"
+ set v ""
+ set s ""
+ switch -exact -- [lindex $prototype [expr {$i + 1}]] {
+ => {
+ incr i 2
+ if {$i >= $n} {
+ proj-error "Missing argument for $k => flag"
+ }
+ set consuming($k) 1
+ set v [lindex $prototype $i]
+ }
+ default {
+ set v [lindex $prototype [incr i]]
+ set s [lindex $prototype [incr i]]
+ set scripts($k) $s
+ }
+ }
+ #puts "**** #$i of $n k=$k v=$v s=$s"
+ set dflt($k) $v
+ }
+ # Now look for those flags in the source list
+ array set tgt [array get dflt]
+ unset dflt
+ set rc 0
+ set rv {}
+ set skipMode 0
+ set n [llength $argv]
+ for {set i 0} {$i < $n} {incr i} {
+ set arg [lindex $argv $i]
+ if {$skipMode} {
+ lappend rv $arg
+ } elseif {"--" eq $arg} {
+ incr skipMode
+ } elseif {[info exists tgt($arg)]} {
+ if {[info exists consuming($arg)]} {
+ if {$i + 1 >= $n} {
+ proj-assert 0 {Cannot happen - bounds already checked}
+ }
+ set tgt($arg) [lindex $argv [incr i]]
+ } elseif {"" eq $scripts($arg)} {
+ set tgt($arg) ""
+ } else {
+ #puts "**** running scripts($arg) $scripts($arg)"
+ set code [catch {uplevel 1 $scripts($arg)} xrc xopt]
+ #puts "**** tgt($arg)=$scripts($arg) code=$code rc=$rc"
+ if {$code in {0 2}} {
+ set tgt($arg) $xrc
+ } else {
+ return {*}$xopt $xrc
+ }
+ }
+ incr rc
+ } else {
+ incr skipMode
+ lappend rv $arg
+ }
+ }
+ set argv $rv
+ return $rc
+}
+
+if {$::proj__Config(self-tests)} {
+ apply {{} {
+ #proj-warn "Test code for proj-cache"
+ proj-assert {![proj-cache-check -key here check]}
+ proj-assert {"here" eq [proj-cache-key here]}
+ proj-assert {"" eq $check}
+ proj-cache-set -key here thevalue
+ proj-assert {[proj-cache-check -key here check]}
+ proj-assert {"thevalue" eq $check}
+
+ proj-assert {![proj-cache-check check]}
+ #puts "*** key = ([proj-cache-key 0])"
+ proj-assert {"" eq $check}
+ proj-cache-set abc
+ proj-assert {[proj-cache-check check]}
+ proj-assert {"abc" eq $check}
+
+ #parray ::proj__Cache;
+ proj-assert {"" ne [proj-cache-remove]}
+ proj-assert {![proj-cache-check check]}
+ proj-assert {"" eq [proj-cache-remove]}
+ proj-assert {"" eq $check}
+ }}
+}
diff --git a/contrib/sqlite3/autosetup/sqlite-config.tcl b/contrib/sqlite3/autosetup/sqlite-config.tcl
new file mode 100644
index 000000000000..85fe4143821c
--- /dev/null
+++ b/contrib/sqlite3/autosetup/sqlite-config.tcl
@@ -0,0 +1,2174 @@
+# This file holds functions for autosetup which are specific to the
+# sqlite build tree. They are in this file, instead of auto.def, so
+# that they can be reused in the autoconf sub-tree. This file requires
+# functions from proj.tcl.
+
+if {[string first " " $autosetup(srcdir)] != -1} {
+ user-error "The pathname of the source tree\
+ may not contain space characters"
+}
+if {[string first " " $autosetup(builddir)] != -1} {
+ user-error "The pathname of the build directory\
+ may not contain space characters"
+}
+#parray ::autosetup; exit 0
+use proj
+#
+# We want the package version info to be emitted early on, but doing
+# so requires a bit of juggling. We have to [use system] for
+# --prefix=... to work and to emit the Host/Build system info, but we
+# don't want those to interfere with --help output.
+define PACKAGE_VERSION [proj-file-content -trim $::autosetup(srcdir)/VERSION]
+if {"--help" ni $::argv} {
+ msg-result "Configuring SQLite version [get-define PACKAGE_VERSION]"
+}
+use system ; # Will output "Host System" and "Build System" lines
+if {"--help" ni $::argv} {
+ proj-tweak-default-env-dirs
+ msg-result "Source dir = $::autosetup(srcdir)"
+ msg-result "Build dir = $::autosetup(builddir)"
+ use cc cc-db cc-shared cc-lib pkg-config
+}
+
+#
+# Object for communicating certain config-time state across various
+# auto.def-related pieces.
+array set sqliteConfig [subst [proj-strip-hash-comments {
+ #
+ # Gets set by [sqlite-configure] (the main configure script driver).
+ build-mode unknown
+ #
+ # Gets set to 1 when using jimsh for code generation. May affect
+ # later decisions.
+ use-jim-for-codegen 0
+ #
+ # Set to 1 when cross-compiling This value may be changed by certain
+ # build options, so it's important that config code which checks for
+ # cross-compilation uses this var instead of
+ # [proj-is-cross-compiling].
+ is-cross-compiling [proj-is-cross-compiling]
+ #
+ # Pass msg-debug=1 to configure to enable obnoxiously loud output
+ # from [msg-debug].
+ msg-debug-enabled 0
+ #
+ # Output file for --dump-defines. Intended only for build debugging
+ # and not part of the public build interface.
+ dump-defines-txt ./config.defines.txt
+ #
+ # If not empty then --dump-defines will dump not only
+ # (dump-defines-txt) but also a JSON file named after this option's
+ # value.
+ dump-defines-json ""
+
+ #
+ # The list of feature --flags which the --all flag implies. This
+ # requires special handling in a few places.
+ #
+ all-flag-enables {fts4 fts5 rtree geopoly session}
+
+ #
+ # Default value for the --all flag. Can hypothetically be modified
+ # by non-canonical builds.
+ #
+ all-flag-default 0
+}]]
+
+########################################################################
+# Processes all configure --flags for this build, run build-specific
+# config checks, then finalize the configure process. $buildMode must
+# be one of (canonical, autoconf), and others may be added in the
+# future. After bootstrapping, $configScript is eval'd in the caller's
+# scope, then post-configuration finalization is run. $configScript is
+# intended to hold configure code which is specific to the given
+# $buildMode, with the caveat that _some_ build-specific code is
+# encapsulated in the configuration finalization step.
+#
+# The intent is that all (or almost all) build-mode-specific
+# configuration goes inside the $configScript argument to this
+# function, and that an auto.def file contains only two commands:
+#
+# use sqlite-config
+# sqlite-configure BUILD_NAME { build-specific configure script }
+#
+# There are snippets of build-mode-specific decision-making in
+# [sqlite-configure-finalize]
+proc sqlite-configure {buildMode configScript} {
+ proj-assert {$::sqliteConfig(build-mode) eq "unknown"} \
+ "sqlite-configure must not be called more than once"
+ set allBuildModes {canonical autoconf}
+ if {$buildMode ni $allBuildModes} {
+ user-error "Invalid build mode: $buildMode. Expecting one of: $allBuildModes"
+ }
+ if {$::sqliteConfig(all-flag-default)} {
+ set allFlagHelp "Disable these extensions: $::sqliteConfig(all-flag-enables)"
+ } else {
+ set allFlagHelp "Enable these extensions: $::sqliteConfig(all-flag-enables)"
+ }
+
+ set ::sqliteConfig(build-mode) $buildMode
+ ########################################################################
+ # A gentle introduction to flags handling in autosetup
+ #
+ # Reference: https://msteveb.github.io/autosetup/developer/
+ #
+ # All configure flags must be described in an 'options' call. The
+ # general syntax is:
+ #
+ # FLAG => {Help text}
+ #
+ # Where FLAG can have any of the following formats:
+ #
+ # boolopt => "a boolean option which defaults to disabled"
+ # boolopt2=1 => "a boolean option which defaults to enabled"
+ # stringopt: => "an option which takes an argument, e.g. --stringopt=value"
+ # stringopt:DESCR => As for stringopt: with a description for the value
+ # stringopt2:=value => "an option where the argument is optional and defaults to 'value'"
+ # optalias booltopt3 => "a boolean with a hidden alias. --optalias is not shown in --help"
+ #
+ # Autosetup does no small amount of specialized handling for flags,
+ # especially booleans. Each bool-type --FLAG implicitly gets
+ # --enable-FLAG and --disable-FLAG forms. That can lead lead to some
+ # confusion when writing help text. For example:
+ #
+ # options { json=1 {Disable JSON functions} }
+ #
+ # The reason the help text says "disable" is because a boolean option
+ # which defaults to true is, in the --help text, rendered as:
+ #
+ # --disable-json Disable JSON functions
+ #
+ # Whereas a bool flag which defaults to false will instead render as:
+ #
+ # --enable-FLAG
+ #
+ # Non-boolean flags, in contrast, use the names specifically given to
+ # them in the [options] invocation. e.g. "with-tcl" is the --with-tcl
+ # flag.
+ #
+ # Fetching values for flags:
+ #
+ # booleans: use one of:
+ # - [opt-bool FLAG] is autosetup's built-in command for this, but we
+ # have some convenience variants:
+ # - [proj-opt-truthy FLAG]
+ # - [proj-opt-if-truthy FLAG {THEN} {ELSE}]
+ #
+ # Non-boolean (i.e. string) flags:
+ # - [opt-val FLAG ?default?]
+ # - [opt-str ...] - see the docs in ./autosetup/autosetup
+ #
+ # [proj-opt-was-provided] can be used to determine whether a flag was
+ # explicitly provided, which is often useful for distinguishing from
+ # the case of a default value.
+ ########################################################################
+ set allFlags {
+ # Structure: a list of M {Z} pairs, where M is a descriptive
+ # option group name and Z is a list of X Y pairs. X is a list of
+ # $buildMode name(s) to which the Y flags apply, or {*} to apply
+ # to all builds. Y is a {block} in the form expected by
+ # autosetup's [options] command. Each block which is applicable
+ # to $buildMode is appended to a new list before that list is
+ # passed on to [options]. The order of each Y and sub-Y is
+ # retained, which is significant for rendering of --help.
+
+ # When writing {help text blocks}, be aware that:
+ #
+ # A) autosetup formats them differently if the {block} starts with
+ # a newline: it starts left-aligned, directly under the --flag, and
+ # the rest of the block is pasted verbatim rather than
+ # pretty-printed.
+ #
+ # B) Vars and commands are NOT expanded, but we use a [subst] call
+ # below which will replace (only) var refs.
+
+ # Options for how to build the library
+ build-modes {
+ {canonical autoconf} {
+ shared=1 => {Disable build of shared library}
+ static=1 => {Disable build of static library}
+ }
+ {canonical} {
+ amalgamation=1 => {Disable the amalgamation and instead build all files separately}
+ }
+ }
+
+ # Library-level features and defaults
+ lib-features {
+ {*} {
+ threadsafe=1 => {Disable mutexing}
+ with-tempstore:=no => {Use an in-RAM database for temporary tables: never,no,yes,always}
+ load-extension=1 => {Disable loading of external extensions}
+ # ^^^ one of the downstream custom builds overrides the load-extension default to 0, which
+ # confuses the --help text generator. https://github.com/msteveb/autosetup/issues/77
+ math=1 => {Disable math functions}
+ json=1 => {Disable JSON functions}
+ memsys5 => {Enable MEMSYS5}
+ memsys3 => {Enable MEMSYS3}
+ fts3 => {Enable the FTS3 extension}
+ fts4 => {Enable the FTS4 extension}
+ fts5 => {Enable the FTS5 extension}
+ update-limit => {Enable the UPDATE/DELETE LIMIT clause}
+ geopoly => {Enable the GEOPOLY extension}
+ rtree => {Enable the RTREE extension}
+ session => {Enable the SESSION extension}
+ all=$::sqliteConfig(all-flag-default) => {$allFlagHelp}
+ largefile=1
+ => {This legacy flag has no effect on the library but may influence
+ the generated sqlite_cfg.h by adding #define HAVE_LFS}
+ }
+ }
+
+ # Options for TCL support
+ tcl {
+ {canonical} {
+ tcl=1
+ => {Disable components which require TCL, including all tests.
+ This tree requires TCL for code generation but can use the in-tree
+ copy of autosetup/jimsh0.c for that. The SQLite TCL extension and the
+ test code require a canonical tclsh.}
+ }
+ {canonical} {
+ with-tcl:DIR
+ => {Directory containing tclConfig.sh or a directory one level up from
+ that, from which we can derive a directory containing tclConfig.sh.
+ A dir name of "prefix" is equivalent to the directory specified by
+ the --prefix flag.}
+ with-tclsh:PATH
+ => {Full pathname of tclsh to use. It is used for (A) trying to find
+ tclConfig.sh and (B) all TCL-based code generation. Warning: if
+ its containing dir has multiple tclsh versions, it may select the
+ wrong tclConfig.sh!}
+ }
+ {canonical} {
+ static-tclsqlite3=0
+ => {Statically-link tclsqlite3. This only works if TCL support is
+ enabled and all requisite libraries are available in
+ static form. Note that glibc is unable to fully statically
+ link certain libraries required by tclsqlite3, so this won't
+ work on most Linux environments.}
+ }
+ }
+
+ # Options for line-editing modes for the CLI shell
+ line-editing {
+ {canonical autoconf} {
+ readline=1
+ => {Disable readline support}
+ # --with-readline-lib is a backwards-compatible alias for
+ # --with-readline-ldflags
+ with-readline-lib:
+ with-readline-ldflags:=auto
+ => {Readline LDFLAGS, e.g. -lreadline -lncurses}
+ # --with-readline-inc is a backwards-compatible alias for
+ # --with-readline-cflags.
+ with-readline-inc:
+ with-readline-cflags:=auto
+ => {Readline CFLAGS, e.g. -I/path/to/includes}
+ with-readline-header:PATH
+ => {Full path to readline.h, from which --with-readline-cflags will be derived}
+ with-linenoise:DIR
+ => {Source directory for linenoise.c and linenoise.h}
+ editline=0
+ => {Enable BSD editline support}
+ }
+ }
+
+ # Options for ICU: International Components for Unicode
+ icu {
+ {*} {
+ with-icu-ldflags:LDFLAGS
+ => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the
+ ICU libraries. e.g. on Ubuntu systems, try '-licui18n -licuuc -licudata'.}
+ with-icu-cflags:CFLAGS
+ => {Apply extra CFLAGS/CPPFLAGS necessary for building with ICU.
+ e.g. -I/usr/local/include}
+ with-icu-config:=auto
+ => {Enable SQLITE_ENABLE_ICU. Value must be one of: auto, pkg-config,
+ /path/to/icu-config}
+ icu-collations=0
+ => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=...
+ or --with-icu-config}
+ }
+ }
+
+ # Options for exotic/alternative build modes
+ alternative-builds {
+ {canonical autoconf} {
+ with-wasi-sdk:=/opt/wasi-sdk
+ => {Top-most dir of the wasi-sdk for a WASI build}
+ }
+
+ {*} {
+ # Note that --static-cli-shell has a completely different
+ # meaning from --static-shell in the autoconf build!
+ # --[disable-]static-shell is a legacy flag which we can't
+ # remove without breaking downstream builds.
+ static-cli-shell=0
+ => {Statically-link the sqlite3 CLI shell.
+ This only works if the requisite libraries are all available in
+ static form.}
+ }
+
+ {canonical} {
+ static-shells=0
+ => {Shorthand for --static-cli-shell --static-tclsqlite3}
+
+ with-emsdk:=auto
+ => {Top-most dir of the Emscripten SDK installation.
+ Needed only by ext/wasm. Default=EMSDK env var.}
+
+ amalgamation-extra-src:FILES
+ => {Space-separated list of soure files to append as-is to the resulting
+ sqlite3.c amalgamation file. May be provided multiple times.}
+ }
+ }
+
+ # Options primarily for downstream packagers/package maintainers
+ packaging {
+ {autoconf} {
+ # --disable-static-shell: https://sqlite.org/forum/forumpost/cc219ee704
+ # Note that this has a different meaning from --static-cli-shell in the
+ # canonical build!
+ static-shell=1
+ => {Link the sqlite3 shell app against the DLL instead of embedding sqlite3.c}
+ }
+ {canonical autoconf} {
+ # A potential TODO without a current use case:
+ #rpath=1 => {Disable use of the rpath linker flag}
+ # soname: https://sqlite.org/src/forumpost/5a3b44f510df8ded
+ soname:=legacy
+ => {SONAME for libsqlite3.so. "none", or not using this flag, sets no
+ soname. "legacy" sets it to its historical value of
+ libsqlite3.so.0. A value matching the glob "libsqlite3.*" sets
+ it to that literal value. Any other value is assumed to be a
+ suffix which gets applied to "libsqlite3.so.",
+ e.g. --soname=9.10 equates to "libsqlite3.so.9.10".}
+ # dll-basename: https://sqlite.org/forum/forumpost/828fdfe904
+ dll-basename:=auto
+ => {Specifies the base name of the resulting DLL file.
+ If not provided, "libsqlite3" is usually assumed but on some platforms
+ a platform-dependent default is used. On some platforms this flag
+ gets automatically enabled if it is not provided. Use "default" to
+ explicitly disable platform-dependent activation on such systems.}
+ # out-implib: https://sqlite.org/forum/forumpost/0c7fc097b2
+ out-implib:=auto
+ => {Enable use of --out-implib linker flag to generate an
+ "import library" for the DLL. The output's base name is
+ specified by this flag's value, with "auto" meaning to figure
+ out a name automatically. On some platforms this flag gets
+ automatically enabled if it is not provided. Use "none" to
+ explicitly disable this feature on such platforms.}
+ }
+ }
+
+ # Options mostly for sqlite's own development
+ developer {
+ {*} {
+ # Note that using the --debug/--enable-debug flag here
+ # requires patching autosetup/autosetup to rename its builtin
+ # --debug to --autosetup-debug. See details in
+ # autosetup/README.md#patching.
+ with-debug=0
+ debug=0
+ => {Enable debug build flags. This option will impact performance by
+ as much as 4x, as it includes large numbers of assert()s in
+ performance-critical loops. Never use --debug for production
+ builds.}
+ scanstatus
+ => {Enable the SQLITE_ENABLE_STMT_SCANSTATUS feature flag}
+ }
+ {canonical} {
+ dev
+ => {Enable dev-mode build: automatically enables certain other flags}
+ test-status
+ => {Enable status of tests}
+ gcov=0
+ => {Enable coverage testing using gcov}
+ linemacros
+ => {Enable #line macros in the amalgamation}
+ dynlink-tools
+ => {Dynamically link libsqlite3 to certain tools which normally statically embed it}
+ asan-fsanitize:=auto
+ => {Comma- or space-separated list of -fsanitize flags for use with the
+ fuzzcheck-asan tool. Only those which the compiler claims to support
+ will actually be used. May be provided multiple times.}
+ }
+ {*} {
+ dump-defines=0
+ => {Dump autosetup defines to $::sqliteConfig(dump-defines-txt)
+ (for build debugging)}
+ }
+ }
+ }; # $allFlags
+
+ set allFlags [proj-strip-hash-comments $allFlags]
+ # ^^^ lappend of [sqlite-custom-flags] introduces weirdness if
+ # we delay [proj-strip-hash-comments] until after that.
+
+
+ ########################################################################
+ # sqlite-custom.tcl is intended only for vendor-branch-specific
+ # customization. See autosetup/README.md#branch-customization for
+ # details.
+ if {[file exists $::autosetup(libdir)/sqlite-custom.tcl]} {
+ uplevel 1 {source $::autosetup(libdir)/sqlite-custom.tcl}
+ }
+
+ if {[llength [info proc sqlite-custom-flags]] > 0} {
+ # sqlite-custom-flags is assumed to be imported via
+ # autosetup/sqlite-custom.tcl.
+ set scf [sqlite-custom-flags]
+ if {"" ne $scf} {
+ lappend allFlags sqlite-custom-flags $scf
+ }
+ }
+
+ # Filter allFlags to create the set of [options] legal for this build
+ foreach {group XY} [subst -nobackslashes -nocommands $allFlags] {
+ foreach {X Y} $XY {
+ if { $buildMode in $X || "*" in $X } {
+ options-add $Y
+ }
+ }
+ }
+ #lappend opts "soname:=duplicateEntry => {x}"; #just testing
+ if {[catch {options {}} msg xopts]} {
+ # Workaround for <https://github.com/msteveb/autosetup/issues/73>
+ # where [options] behaves oddly on _some_ TCL builds when it's
+ # called from deeper than the global scope.
+ dict incr xopts -level
+ return {*}$xopts $msg
+ }
+ sqlite-configure-phase1 $buildMode
+ uplevel 1 $configScript
+ sqlite-configure-finalize
+}; # sqlite-configure
+
+########################################################################
+# Runs "phase 1" of the configure process: after initial --flags
+# handling but before the build-specific parts are run. $buildMode
+# must be the mode which was passed to [sqlite-configure].
+proc sqlite-configure-phase1 {buildMode} {
+ define PACKAGE_NAME sqlite
+ define PACKAGE_URL {https://sqlite.org}
+ define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/forum
+ define PACKAGE_STRING "[get-define PACKAGE_NAME] [get-define PACKAGE_VERSION]"
+ proj-xfer-options-aliases {
+ # Carry values from hidden --flag aliases over to their canonical
+ # flag forms. This list must include only options which are common
+ # to all build modes supported by [sqlite-configure].
+ with-readline-inc => with-readline-cflags
+ with-readline-lib => with-readline-ldflags
+ with-debug => debug
+ }
+ set ::sqliteConfig(msg-debug-enabled) [proj-val-truthy [get-env msg-debug 0]]
+ proc-debug "msg-debug is enabled"
+ proj-setup-autoreconfig SQLITE_AUTORECONFIG
+ proj-file-extensions
+ if {".exe" eq [get-define TARGET_EXEEXT]} {
+ define SQLITE_OS_UNIX 0
+ define SQLITE_OS_WIN 1
+ } else {
+ define SQLITE_OS_UNIX 1
+ define SQLITE_OS_WIN 0
+ }
+ sqlite-setup-default-cflags
+ define HAVE_LFS 0
+ if {[opt-bool largefile]} {
+ #
+ # Insofar as we can determine HAVE_LFS has no effect on the
+ # library. Perhaps it did back in the early 2000's. The
+ # --enable/disable-largefile flag is retained because it's
+ # harmless, but it doesn't do anything useful. It does have
+ # visible side-effects, though: the generated sqlite_cfg.h may (or
+ # may not) define HAVE_LFS.
+ cc-check-lfs
+ }
+ set srcdir $::autosetup(srcdir)
+ proj-dot-ins-append $srcdir/Makefile.in
+ if {[file exists $srcdir/sqlite3.pc.in]} {
+ proj-dot-ins-append $srcdir/sqlite3.pc.in
+ }
+}; # sqlite-configure-phase1
+
+########################################################################
+# Performs late-stage config steps common to all supported
+# $::sqliteConfig(build-mode) values.
+proc sqlite-configure-finalize {} {
+ sqlite-handle-rpath
+ sqlite-handle-soname
+ sqlite-handle-threadsafe
+ sqlite-handle-tempstore
+ sqlite-handle-load-extension
+ sqlite-handle-math
+ sqlite-handle-icu
+ if {[proj-opt-exists readline]} {
+ sqlite-handle-line-editing
+ }
+ if {[proj-opt-exists shared]} {
+ proj-define-for-opt shared ENABLE_LIB_SHARED "Build shared library?"
+ }
+ if {[proj-opt-exists static]} {
+ if {![proj-define-for-opt static ENABLE_LIB_STATIC "Build static library?"]} {
+ # This notice really only applies to the canonical build...
+ proj-indented-notice {
+ NOTICE: static lib build may be implicitly re-activated by
+ other components, e.g. some test apps.
+ }
+ }
+ }
+ sqlite-handle-env-quirks
+ sqlite-handle-common-feature-flags
+ sqlite-finalize-feature-flags
+ sqlite-process-dot-in-files; # do not [define] anything after this
+ sqlite-dump-defines
+}
+
+########################################################################
+# Internal config-time debugging output routine. It generates no
+# output unless msg-debug=1 is passed to the configure script.
+proc msg-debug {msg} {
+ if {$::sqliteConfig(msg-debug-enabled)} {
+ puts stderr [proj-bold "** DEBUG: $msg"]
+ }
+}
+########################################################################
+# A [msg-debug] proxy which prepends the name of the current proc to
+# the debug message. It is not legal to call this from the global
+# scope.
+proc proc-debug {msg} {
+ msg-debug "\[[proj-scope 1]\]: $msg"
+}
+
+define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
+define OPT_SHELL {} ; # Feature-related CFLAGS for the sqlite3 CLI app
+########################################################################
+# Adds $args, if not empty, to OPT_FEATURE_FLAGS. If the first arg is
+# -shell then it strips that arg and passes the remaining args the
+# sqlite-add-shell-opt in addition to adding them to
+# OPT_FEATURE_FLAGS. This is intended only for holding
+# -DSQLITE_ENABLE/OMIT/... flags, but that is not enforced here.
+proc sqlite-add-feature-flag {args} {
+ set shell ""
+ if {"-shell" eq [lindex $args 0]} {
+ set args [lassign $args shell]
+ }
+ if {"" ne $args} {
+ if {"" ne $shell} {
+ sqlite-add-shell-opt {*}$args
+ }
+ define-append OPT_FEATURE_FLAGS {*}$args
+ }
+}
+
+########################################################################
+# Appends $args, if not empty, to OPT_SHELL.
+proc sqlite-add-shell-opt {args} {
+ if {"" ne $args} {
+ define-append OPT_SHELL {*}$args
+ }
+}
+
+########################################################################
+# Check for log(3) in libm and die with an error if it is not
+# found. $featureName should be the feature name which requires that
+# function (it's used only in error messages). defines LDFLAGS_MATH to
+# the required linker flags (which may be empty even if the math APIs
+# are found, depending on the OS).
+proc sqlite-affirm-have-math {featureName} {
+ if {"" eq [get-define LDFLAGS_MATH ""]} {
+ if {![msg-quiet proj-check-function-in-lib log m]} {
+ user-error "Missing math APIs for $featureName"
+ }
+ set lfl [get-define lib_log ""]
+ undefine lib_log
+ if {"" ne $lfl} {
+ user-notice "Forcing requirement of $lfl for $featureName"
+ }
+ define LDFLAGS_MATH $lfl
+ }
+}
+
+########################################################################
+# Run checks for required binaries, like ld and ar. In the canonical
+# build this must come before [sqlite-handle-wasi-sdk].
+proc sqlite-check-common-bins {} {
+ cc-check-tools ld ar ; # must come before [sqlite-handle-wasi-sdk]
+ if {"" eq [proj-bin-define install]} {
+ proj-warn "Cannot find install binary, so 'make install' will not work."
+ define BIN_INSTALL false
+ }
+}
+
+########################################################################
+# Run checks for system-level includes and libs which are common to
+# both the canonical build and the "autoconf" bundle.
+#
+# For the canonical build this must come after
+# [sqlite-handle-wasi-sdk], as that function may change the
+# environment in ways which affect this.
+proc sqlite-check-common-system-deps {} {
+ # Check for needed/wanted data types
+ cc-with {-includes stdint.h} \
+ {cc-check-types int8_t int16_t int32_t int64_t intptr_t \
+ uint8_t uint16_t uint32_t uint64_t uintptr_t}
+
+ # Check for needed/wanted functions
+ cc-check-functions gmtime_r isnan localtime_r localtime_s \
+ strchrnul usleep utime pread pread64 pwrite pwrite64
+
+ apply {{} {
+ set ldrt ""
+ # Collapse funcs from librt into LDFLAGS_RT.
+ # Some systems (ex: SunOS) require -lrt in order to use nanosleep
+ foreach func {fdatasync nanosleep} {
+ if {[proj-check-function-in-lib $func rt]} {
+ set ldrt [get-define lib_${func} ""]
+ undefine lib_${func}
+ if {"" ne $ldrt} {
+ break
+ }
+ }
+ }
+ define LDFLAGS_RT $ldrt
+ }}
+
+ # Check for needed/wanted headers
+ cc-check-includes \
+ sys/types.h sys/stat.h dlfcn.h unistd.h \
+ stdlib.h malloc.h memory.h \
+ string.h strings.h \
+ inttypes.h
+
+ if {[cc-check-includes zlib.h] && [proj-check-function-in-lib deflate z]} {
+ # TODO? port over the more sophisticated zlib search from the fossil auto.def
+ define HAVE_ZLIB 1
+ define LDFLAGS_ZLIB -lz
+ sqlite-add-shell-opt -DSQLITE_HAVE_ZLIB=1
+ } else {
+ define HAVE_ZLIB 0
+ define LDFLAGS_ZLIB ""
+ }
+}
+
+########################################################################
+# Move -DSQLITE_OMIT... and -DSQLITE_ENABLE... flags from CFLAGS and
+# CPPFLAGS to OPT_FEATURE_FLAGS and remove them from BUILD_CFLAGS.
+proc sqlite-munge-cflags {} {
+ # Move CFLAGS and CPPFLAGS entries matching -DSQLITE_OMIT* and
+ # -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived
+ # from the legacy build and was missing the 3.48.0 release (the
+ # initial Autosetup port).
+ # https://sqlite.org/forum/forumpost/9801e54665afd728
+ #
+ # Handling of CPPFLAGS, as well as removing ENABLE/OMIT from
+ # CFLAGS/CPPFLAGS, was missing in the 3.49.0 release as well.
+ #
+ # If any configure flags for features are in conflict with
+ # CFLAGS/CPPFLAGS-specified feature flags, all bets are off. There
+ # are no guarantees about which one will take precedence.
+ foreach flagDef {CFLAGS CPPFLAGS} {
+ set tmp ""
+ foreach cf [get-define $flagDef ""] {
+ switch -glob -- $cf {
+ -DSQLITE_OMIT* -
+ -DSQLITE_ENABLE* {
+ sqlite-add-feature-flag $cf
+ }
+ default {
+ lappend tmp $cf
+ }
+ }
+ }
+ define $flagDef $tmp
+ }
+
+ # Strip all SQLITE_ENABLE/OMIT flags from BUILD_CFLAGS,
+ # for compatibility with the legacy build.
+ set tmp ""
+ foreach cf [get-define BUILD_CFLAGS ""] {
+ switch -glob -- $cf {
+ -DSQLITE_OMIT* -
+ -DSQLITE_ENABLE* {}
+ default {
+ lappend tmp $cf
+ }
+ }
+ }
+ define BUILD_CFLAGS $tmp
+}
+
+#########################################################################
+# Set up the default CFLAGS and BUILD_CFLAGS values.
+proc sqlite-setup-default-cflags {} {
+ ########################################################################
+ # We differentiate between two C compilers: the one used for binaries
+ # which are to run on the build system (in autosetup it's called
+ # CC_FOR_BUILD and in Makefile.in it's $(B.cc)) and the one used for
+ # compiling binaries for the target system (CC a.k.a. $(T.cc)).
+ # Normally they're the same, but they will differ when
+ # cross-compiling.
+ #
+ # When cross-compiling we default to not using the -g flag, based on a
+ # /chat discussion prompted by
+ # https://sqlite.org/forum/forumpost/9a67df63eda9925c
+ set defaultCFlags {-O2}
+ if {!$::sqliteConfig(is-cross-compiling)} {
+ lappend defaultCFlags -g
+ }
+ define CFLAGS [proj-get-env CFLAGS $defaultCFlags]
+ # BUILD_CFLAGS is the CFLAGS for CC_FOR_BUILD.
+ define BUILD_CFLAGS [proj-get-env BUILD_CFLAGS {-g}]
+ sqlite-munge-cflags
+}
+
+########################################################################
+# Handle various SQLITE_ENABLE/OMIT_... feature flags.
+proc sqlite-handle-common-feature-flags {} {
+ msg-result "Feature flags..."
+ if {![opt-bool all]} {
+ # Special handling for --disable-all
+ foreach flag $::sqliteConfig(all-flag-enables) {
+ if {![proj-opt-was-provided $flag]} {
+ proj-opt-set $flag 0
+ }
+ }
+ }
+ foreach {boolFlag featureFlag ifSetEvalThis} [proj-strip-hash-comments {
+ all {} {
+ # The 'all' option must be first in this list. This impl makes
+ # an effort to only apply flags which the user did not already
+ # apply, so that combinations like (--all --disable-geopoly)
+ # will indeed disable geopoly. There are corner cases where
+ # flags which depend on each other will behave in non-intuitive
+ # ways:
+ #
+ # --all --disable-rtree
+ #
+ # Will NOT disable geopoly, though geopoly depends on rtree.
+ # The --geopoly flag, though, will automatically re-enable
+ # --rtree, so --disable-rtree won't actually disable anything in
+ # that case.
+ foreach k $::sqliteConfig(all-flag-enables) {
+ if {![proj-opt-was-provided $k]} {
+ proj-opt-set $k 1
+ }
+ }
+ }
+ fts3 -DSQLITE_ENABLE_FTS3 {sqlite-affirm-have-math fts3}
+ fts4 -DSQLITE_ENABLE_FTS4 {sqlite-affirm-have-math fts4}
+ fts5 -DSQLITE_ENABLE_FTS5 {sqlite-affirm-have-math fts5}
+ geopoly -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree}
+ rtree -DSQLITE_ENABLE_RTREE {}
+ session {-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK} {}
+ update-limit -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT {}
+ memsys5 -DSQLITE_ENABLE_MEMSYS5 {}
+ memsys3 {} {
+ if {[opt-bool memsys5]} {
+ proj-warn "not enabling memsys3 because memsys5 is enabled."
+ expr 0
+ } else {
+ sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
+ }
+ }
+ scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
+ }] {
+ if {$boolFlag ni $::autosetup(options)} {
+ # Skip flags which are in the canonical build but not
+ # the autoconf bundle.
+ continue
+ }
+ proj-if-opt-truthy $boolFlag {
+ sqlite-add-feature-flag $featureFlag
+ if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} {
+ msg-result " + $boolFlag"
+ }
+ } {
+ if {"all" ne $boolFlag} {
+ msg-result " - $boolFlag"
+ }
+ }
+ }
+ ########################################################################
+ # Invert the above loop's logic for some SQLITE_OMIT_... cases. If
+ # config option $boolFlag is false, [sqlite-add-feature-flag
+ # $featureFlag], where $featureFlag is intended to be
+ # -DSQLITE_OMIT_...
+ foreach {boolFlag featureFlag} {
+ json -DSQLITE_OMIT_JSON
+ } {
+ if {[proj-opt-truthy $boolFlag]} {
+ msg-result " + $boolFlag"
+ } else {
+ sqlite-add-feature-flag $featureFlag
+ msg-result " - $boolFlag"
+ }
+ }
+}
+
+#########################################################################
+# Remove duplicates from the final feature flag sets and show them to
+# the user.
+proc sqlite-finalize-feature-flags {} {
+ set oFF [get-define OPT_FEATURE_FLAGS]
+ if {"" ne $oFF} {
+ define OPT_FEATURE_FLAGS [lsort -unique $oFF]
+ msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
+ }
+ set oFF [get-define OPT_SHELL]
+ if {"" ne $oFF} {
+ define OPT_SHELL [lsort -unique $oFF]
+ msg-result "Shell options: [get-define OPT_SHELL]"
+ }
+ if {"" ne [set extraSrc [get-define AMALGAMATION_EXTRA_SRC ""]]} {
+ proj-assert {"canonical" eq $::sqliteConfig(build-mode)}
+ msg-result "Appending source files to amalgamation: $extraSrc"
+ }
+ if {[lsearch [get-define TARGET_DEBUG ""] -DSQLITE_DEBUG=1] > -1} {
+ msg-result "Note: this is a debug build, so performance will suffer."
+ }
+}
+
+########################################################################
+# Checks for the --debug flag and [define]s TARGET_DEBUG based on
+# that. TARGET_DEBUG is unused in the autoconf build but that is
+# arguably a bug.
+proc sqlite-handle-debug {} {
+ msg-checking "SQLITE_DEBUG build? "
+ proj-if-opt-truthy debug {
+ define TARGET_DEBUG {-g -DSQLITE_DEBUG=1 -O0 -Wall}
+ sqlite-add-feature-flag -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE
+ proj-opt-set memsys5
+ msg-result yes
+ } {
+ define TARGET_DEBUG {-DNDEBUG}
+ msg-result no
+ }
+}
+
+########################################################################
+# "soname" for libsqlite3.so. See discussion at:
+# https://sqlite.org/src/forumpost/5a3b44f510df8ded
+proc sqlite-handle-soname {} {
+ define LDFLAGS_LIBSQLITE3_SONAME ""
+ if {[proj-opt-was-provided soname]} {
+ set soname [join [opt-val soname] ""]
+ } else {
+ # Enabling soname breaks linking for the --dynlink-tools feature,
+ # and this project has no direct use for soname, so default to
+ # none. Package maintainers, on the other hand, like to have an
+ # soname.
+ set soname none
+ }
+ switch -exact -- $soname {
+ none - "" { return 0 }
+ legacy { set soname libsqlite3.so.0 }
+ default {
+ if {[string match libsqlite3.* $soname]} {
+ # use it as-is
+ } else {
+ # Assume it's a suffix
+ set soname "libsqlite3.so.${soname}"
+ }
+ }
+ }
+ proc-debug "soname=$soname"
+ if {[proj-check-soname $soname]} {
+ define LDFLAGS_LIBSQLITE3_SONAME [get-define LDFLAGS_SONAME_PREFIX]$soname
+ msg-result "Setting SONAME using: [get-define LDFLAGS_LIBSQLITE3_SONAME]"
+ } elseif {[proj-opt-was-provided soname]} {
+ # --soname was explicitly requested but not available, so fail fatally
+ proj-fatal "This environment does not support SONAME."
+ } else {
+ # --soname was not explicitly requested but not available, so just warn
+ msg-result "This environment does not support SONAME."
+ }
+}
+
+########################################################################
+# If --enable-threadsafe is set, this adds -DSQLITE_THREADSAFE=1 to
+# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to the linker flags
+# needed for linking pthread (possibly an empty string). If
+# --enable-threadsafe is not set, adds -DSQLITE_THREADSAFE=0 to
+# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to an empty string.
+proc sqlite-handle-threadsafe {} {
+ msg-checking "Support threadsafe operation? "
+ define LDFLAGS_PTHREAD ""
+ set enable 0
+ proj-if-opt-truthy threadsafe {
+ msg-result "Checking for libs..."
+ if {[proj-check-function-in-lib pthread_create pthread]
+ && [proj-check-function-in-lib pthread_mutexattr_init pthread]} {
+ set enable 1
+ define LDFLAGS_PTHREAD [get-define lib_pthread_create]
+ undefine lib_pthread_create
+ undefine lib_pthread_mutexattr_init
+ } elseif {[proj-opt-was-provided threadsafe]} {
+ user-error "Missing required pthread libraries. Use --disable-threadsafe to disable this check."
+ } else {
+ msg-result "pthread support not detected"
+ }
+ # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if
+ # found because it's in -lc on some platforms.
+ } {
+ msg-result "Disabled using --disable-threadsafe"
+ }
+ sqlite-add-feature-flag -DSQLITE_THREADSAFE=${enable}
+ return $enable
+}
+
+########################################################################
+# Handles the --with-tempstore flag.
+#
+# The test fixture likes to set SQLITE_TEMP_STORE on its own, so do
+# not set that feature flag unless it was explicitly provided to the
+# configure script.
+proc sqlite-handle-tempstore {} {
+ if {[proj-opt-was-provided with-tempstore]} {
+ set ts [opt-val with-tempstore no]
+ set tsn 1
+ msg-checking "Use an in-RAM database for temporary tables? "
+ switch -exact -- $ts {
+ never { set tsn 0 }
+ no { set tsn 1 }
+ yes { set tsn 2 }
+ always { set tsn 3 }
+ default {
+ user-error "Invalid --with-tempstore value '$ts'. Use one of: never, no, yes, always"
+ }
+ }
+ msg-result $ts
+ sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn
+ }
+}
+
+########################################################################
+# Check for the Emscripten SDK for building the web-based wasm
+# components. The core lib and tools do not require this but ext/wasm
+# does. Most of the work is done via [proj-check-emsdk], then this
+# function adds the following defines:
+#
+# - EMCC_WRAPPER = "" or top-srcdir/tool/emcc.sh
+# - BIN_WASM_OPT = "" or path to wasm-opt
+# - BIN_WASM_STRIP = "" or path to wasm-strip
+#
+# Noting that:
+#
+# 1) Not finding the SDK is not fatal at this level, nor is failure to
+# find one of the related binaries.
+#
+# 2) wasm-strip is part of the wabt package:
+#
+# https://github.com/WebAssembly/wabt
+#
+# and this project requires it for production-mode builds but not dev
+# builds.
+#
+proc sqlite-handle-emsdk {} {
+ define EMCC_WRAPPER ""
+ define BIN_WASM_STRIP ""
+ define BIN_WASM_OPT ""
+ set srcdir $::autosetup(srcdir)
+ if {$srcdir ne $::autosetup(builddir)} {
+ # The EMSDK pieces require writing to the original source tree
+ # even when doing an out-of-tree build. The ext/wasm pieces do not
+ # support an out-of-tree build so we treat that case as if EMSDK
+ # were not found.
+ msg-result "Out-of tree build: not checking for EMSDK."
+ return
+ }
+ set emccSh $srcdir/tool/emcc.sh
+ set extWasmConfig $srcdir/ext/wasm/config.make
+ if {![get-define HAVE_WASI_SDK] && [proj-check-emsdk]} {
+ define EMCC_WRAPPER $emccSh
+ set emsdkHome [get-define EMSDK_HOME ""]
+ proj-assert {"" ne $emsdkHome}
+ #define EMCC_WRAPPER ""; # just for testing
+ proj-bin-define wasm-strip
+ proj-bin-define bash; # ext/wasm/GNUmakefile requires bash
+ if {[file-isexec $emsdkHome/upstream/bin/wasm-opt]} {
+ define BIN_WASM_OPT $emsdkHome/upstream/bin/wasm-opt
+ } else {
+ # Maybe there's a copy in the path?
+ proj-bin-define wasm-opt BIN_WASM_OPT
+ }
+ proj-dot-ins-append $emccSh.in $emccSh {
+ catch {exec chmod u+x $dotInsOut}
+ }
+ proj-dot-ins-append $extWasmConfig.in $extWasmConfig
+ } else {
+ define EMCC_WRAPPER ""
+ file delete -force -- $emccSh $extWasmConfig
+ }
+}
+
+########################################################################
+# Internal helper for [sqlite-check-line-editing]. Returns a list of
+# potential locations under which readline.h might be found.
+#
+# On some environments this function may perform extra work to help
+# sqlite-check-line-editing figure out how to find libreadline and
+# friends. It will communicate those results via means other than the
+# result value, e.g. by modifying configure --flags.
+proc sqlite-get-readline-dir-list {} {
+ # Historical note: the dirs list, except for the inclusion of
+ # $prefix and some platform-specific dirs, originates from the
+ # legacy configure script
+ set dirs [list [get-define prefix]]
+ switch -glob -- [get-define host] {
+ *-linux-android {
+ # Possibly termux
+ lappend dirs /data/data/com.termux/files/usr
+ }
+ *-mingw32 {
+ lappend dirs /mingw32 /mingw
+ }
+ *-mingw64 {
+ lappend dirs /mingw64 /mingw
+ }
+ *-haiku {
+ lappend dirs /boot/system/develop/headers
+ if {[opt-val with-readline-ldflags] in {auto ""}} {
+ # If the user did not supply their own --with-readline-ldflags
+ # value, hijack that flag to inject options which are known to
+ # work on a default Haiku installation.
+ if {"" ne [glob -nocomplain /boot/system/lib/libreadline*]} {
+ proj-opt-set with-readline-ldflags {-L/boot/system/lib -lreadline}
+ }
+ }
+ }
+ }
+ lappend dirs /usr /usr/local /usr/local/readline /usr/contrib
+ set rv {}
+ foreach d $dirs {
+ if {[file isdir $d]} {lappend rv $d}
+ }
+ #proc-debug "dirs=$rv"
+ return $rv
+}
+
+########################################################################
+# sqlite-check-line-editing jumps through proverbial hoops to try to
+# find a working line-editing library, setting:
+#
+# - HAVE_READLINE to 0 or 1
+# - HAVE_LINENOISE to 0, 1, or 2
+# - HAVE_EDITLINE to 0 or 1
+#
+# Only one of ^^^ those will be set to non-0.
+#
+# - LDFLAGS_READLINE = linker flags or empty string
+#
+# - CFLAGS_READLINE = compilation flags for clients or empty string.
+#
+# Note that LDFLAGS_READLINE and CFLAGS_READLINE may refer to
+# linenoise or editline, not necessarily libreadline. In some cases
+# it will set HAVE_READLINE=1 when it's really using editline, for
+# reasons described in this function's comments.
+#
+# Returns a string describing which line-editing approach to use, or
+# "none" if no option is available.
+#
+# Order of checks:
+#
+# 1) --with-linenoise trumps all others and skips all of the
+# complexities involved with the remaining options.
+#
+# 2) --editline trumps --readline
+#
+# 3) --disable-readline trumps --readline
+#
+# 4) Default to automatic search for optional readline
+#
+# 5) Try to find readline or editline. If it's not found AND the
+# corresponding --FEATURE flag was explicitly given, fail fatally,
+# else fail silently.
+proc sqlite-check-line-editing {} {
+ msg-result "Checking for line-editing capability..."
+ define HAVE_READLINE 0
+ define HAVE_LINENOISE 0
+ define HAVE_EDITLINE 0
+ define LDFLAGS_READLINE ""
+ define CFLAGS_READLINE ""
+ set failIfNotFound 0 ; # Gets set to 1 for explicit --FEATURE requests
+ # so that we know whether to fail fatally or not
+ # if the library is not found.
+ set libsForReadline {readline edit} ; # -l<LIB> names to check for readline().
+ # The libedit check changes this.
+ set editLibName "readline" ; # "readline" or "editline"
+ set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE"
+ set dirLn [opt-val with-linenoise]
+ if {"" ne $dirLn} {
+ # Use linenoise from a copy of its sources (not a library)...
+ if {![file isdir $dirLn]} {
+ proj-fatal "--with-linenoise value is not a directory"
+ }
+ set lnH $dirLn/linenoise.h
+ if {![file exists $lnH] } {
+ proj-fatal "Cannot find linenoise.h in $dirLn"
+ }
+ set lnC ""
+ set lnCOpts {linenoise-ship.c linenoise.c}
+ foreach f $lnCOpts {
+ if {[file exists $dirLn/$f]} {
+ set lnC $dirLn/$f
+ break;
+ }
+ }
+ if {"" eq $lnC} {
+ proj-fatal "Cannot find any of $lnCOpts in $dirLn"
+ }
+ set flavor ""
+ set lnVal [proj-which-linenoise $lnH]
+ switch -- $lnVal {
+ 1 { set flavor "antirez" }
+ 2 { set flavor "msteveb" }
+ default {
+ proj-fatal "Cannot determine the flavor of linenoise from $lnH"
+ }
+ }
+ define CFLAGS_READLINE "-I$dirLn $lnC"
+ define HAVE_LINENOISE $lnVal
+ sqlite-add-shell-opt -DHAVE_LINENOISE=$lnVal
+ if {$::sqliteConfig(use-jim-for-codegen) && 2 == $lnVal} {
+ define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE]
+ user-notice "Adding linenoise support to jimsh."
+ }
+ return "linenoise ($flavor)"
+ } elseif {[opt-bool editline]} {
+ # libedit mimics libreadline and on some systems does not have its
+ # own header installed (instead, that of libreadline is used).
+ #
+ # shell.c historically expects HAVE_EDITLINE to be set for
+ # libedit, but it then expects to see <editline/readline.h>, which
+ # some system's don't actually have despite having libedit. If we
+ # end up finding <editline/readline.h> below, we will use
+ # -DHAVE_EDITLINE=1, else we will use -DHAVE_READLINE=1. In either
+ # case, we will link against libedit.
+ set failIfNotFound 1
+ set libsForReadline {edit}
+ set editLibName editline
+ } elseif {![opt-bool readline]} {
+ msg-result "Readline support explicitly disabled with --disable-readline"
+ return "none"
+ } elseif {[proj-opt-was-provided readline]} {
+ # If an explicit --[enable-]readline was used, fail if it's not
+ # found, else treat the feature as optional.
+ set failIfNotFound 1
+ }
+
+ # Transform with-readline-header=X to with-readline-cflags=-I...
+ set v [opt-val with-readline-header]
+ proj-opt-set with-readline-header ""
+ if {"" ne $v} {
+ if {"auto" eq $v} {
+ proj-opt-set with-readline-cflags auto
+ } else {
+ set v [file dirname $v]
+ if {[string match */readline $v]} {
+ # Special case: if the path includes .../readline/readline.h,
+ # set the -I to one dir up from that because our sources
+ # #include <readline/readline.h> or <editline/readline.h>.
+ set v [file dirname $v]
+ }
+ proj-opt-set with-readline-cflags "-I$v"
+ }
+ }
+
+ # Look for readline.h
+ set rlInc [opt-val with-readline-cflags auto]
+ if {"auto" eq $rlInc} {
+ set rlInc ""
+ if {$::sqliteConfig(is-cross-compiling)} {
+ # ^^^ this check is derived from the legacy configure script.
+ proj-warn "Skipping check for readline.h because we're cross-compiling."
+ } else {
+ set dirs [sqlite-get-readline-dir-list]
+ set subdirs [list \
+ include/$editLibName \
+ readline]
+ if {"editline" eq $editLibName} {
+ lappend subdirs include/readline
+ # ^^^ editline, on some systems, does not have its own header,
+ # and uses libreadline's header.
+ }
+ lappend subdirs include
+ set rlInc [proj-search-for-header-dir readline.h \
+ -dirs $dirs -subdirs $subdirs]
+ #proc-debug "rlInc=$rlInc"
+ if {"" ne $rlInc} {
+ if {[string match */readline $rlInc]} {
+ set rlInc [file dirname $rlInc]; # CLI shell: #include <readline/readline.h>
+ } elseif {[string match */editline $rlInc]} {
+ set editLibDef HAVE_EDITLINE
+ set rlInc [file dirname $rlInc]; # CLI shell: #include <editline/readline.h>
+ }
+ set rlInc "-I${rlInc}"
+ }
+ }
+ } elseif {"" ne $rlInc && ![string match *-I* $rlInc]} {
+ proj-fatal "Argument to --with-readline-cflags is intended to be CFLAGS and contain -I..."
+ }
+
+ # If readline.h was found/specified, look for lib(readline|edit)...
+ #
+ # This is not quite straightforward because both libreadline and
+ # libedit typically require some other library which (according to
+ # legacy autotools-generated tests) provides tgetent(3). On some
+ # systems that's built into libreadline/edit, on some (most?) its in
+ # lib[n]curses, and on some it's in libtermcap.
+ set rlLib ""
+ if {"" ne $rlInc} {
+ set rlLib [opt-val with-readline-ldflags]
+ #proc-debug "rlLib=$rlLib"
+ if {$rlLib in {auto ""}} {
+ set rlLib ""
+ set libTerm ""
+ if {[proj-check-function-in-lib tgetent "$editLibName ncurses curses termcap"]} {
+ # ^^^ that libs list comes from the legacy configure script ^^^
+ set libTerm [get-define lib_tgetent]
+ undefine lib_tgetent
+ }
+ if {$editLibName eq $libTerm} {
+ set rlLib $libTerm
+ } elseif {[proj-check-function-in-lib readline $libsForReadline $libTerm]} {
+ set rlLib [get-define lib_readline]
+ lappend rlLib $libTerm
+ undefine lib_readline
+ }
+ }
+ }
+
+ # If we found a library, configure the build to use it...
+ if {"" ne $rlLib} {
+ if {"editline" eq $editLibName && "HAVE_READLINE" eq $editLibDef} {
+ # Alert the user that, despite outward appearances, we won't be
+ # linking to the GPL'd libreadline. Presumably that distinction is
+ # significant for those using --editline.
+ proj-indented-notice {
+ NOTE: the local libedit uses <readline/readline.h> so we
+ will compile with -DHAVE_READLINE=1 but will link with
+ libedit.
+ }
+ }
+ set rlLib [join $rlLib]
+ set rlInc [join $rlInc]
+ define LDFLAGS_READLINE $rlLib
+ define CFLAGS_READLINE $rlInc
+ proj-assert {$editLibDef in {HAVE_READLINE HAVE_EDITLINE}}
+ proj-assert {$editLibName in {readline editline}}
+ sqlite-add-shell-opt -D${editLibDef}=1
+ msg-result "Using $editLibName flags: $rlInc $rlLib"
+ # Check whether rl_completion_matches() has a signature we can use
+ # and disable that sub-feature if it doesn't.
+ if {![cctest \
+ -cflags "$rlInc -D${editLibDef}" -libs $rlLib -nooutput 1 -source {
+ #include <stdio.h>
+ #ifdef HAVE_EDITLINE
+ #include <editline/readline.h>
+ #else
+ #include <readline/readline.h>
+ #endif
+ static char * rcg(const char *z, int i){(void)z; (void)i; return 0;}
+ int main(void) {
+ char ** x = rl_completion_matches("one", rcg);
+ (void)x;
+ return 0;
+ }
+ }]} {
+ proj-warn "readline-style completion disabled due to rl_completion_matches() signature mismatch"
+ sqlite-add-shell-opt -DSQLITE_OMIT_READLINE_COMPLETION
+ }
+ return $editLibName
+ }
+
+ if {$failIfNotFound} {
+ proj-fatal "Explicit --$editLibName failed to find a matching library."
+ }
+ return "none"
+}; # sqlite-check-line-editing
+
+########################################################################
+# Runs sqlite-check-line-editing and adds a message around it. In the
+# canonical build this must not be called before
+# sqlite-determine-codegen-tcl for reasons now lost to history (and
+# might not still be applicable).
+proc sqlite-handle-line-editing {} {
+ msg-result "Line-editing support for the sqlite3 shell: [sqlite-check-line-editing]"
+}
+
+
+########################################################################
+# ICU - International Components for Unicode
+#
+# Handles these flags:
+#
+# --with-icu-ldflags=LDFLAGS
+# --with-icu-cflags=CFLAGS
+# --with-icu-config[=auto | pkg-config | /path/to/icu-config]
+# --enable-icu-collations
+#
+# --with-icu-config values:
+#
+# - auto: use the first one of (pkg-config, icu-config) found on the
+# system.
+# - pkg-config: use only pkg-config to determine flags
+# - /path/to/icu-config: use that to determine flags
+#
+# If --with-icu-config is used as neither pkg-config nor icu-config
+# are found, fail fatally.
+#
+# If both --with-icu-ldflags and --with-icu-config are provided, they
+# are cumulative. If neither are provided, icu-collations is not
+# honored and a warning is emitted if it is provided.
+#
+# Design note: though we could automatically enable ICU if the
+# icu-config binary or (pkg-config icu-io) are found, we specifically
+# do not. ICU is always an opt-in feature.
+proc sqlite-handle-icu {} {
+ define LDFLAGS_ICU [join [opt-val with-icu-ldflags ""]]
+ define CFLAGS_ICU [join [opt-val with-icu-cflags ""]]
+ if {[proj-opt-was-provided with-icu-config]} {
+ msg-result "Checking for ICU support..."
+ set icuConfigBin [opt-val with-icu-config]
+ set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config
+ if {$icuConfigBin in {auto pkg-config}} {
+ if {[pkg-config-init 0] && [pkg-config icu-io]} {
+ # Maintenance reminder: historical docs say to use both of
+ # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has
+ # all of them on tested OSes.
+ set tryIcuConfigBin 0
+ define LDFLAGS_ICU [get-define PKG_ICU_IO_LDFLAGS]
+ define-append LDFLAGS_ICU [get-define PKG_ICU_IO_LIBS]
+ define CFLAGS_ICU [get-define PKG_ICU_IO_CFLAGS]
+ } elseif {"pkg-config" eq $icuConfigBin} {
+ proj-fatal "pkg-config cannot find package icu-io"
+ } else {
+ proj-assert {"auto" eq $icuConfigBin}
+ }
+ }
+ if {$tryIcuConfigBin} {
+ if {"auto" eq $icuConfigBin} {
+ set icuConfigBin [proj-first-bin-of \
+ /usr/local/bin/icu-config \
+ /usr/bin/icu-config]
+ if {"" eq $icuConfigBin} {
+ proj-indented-notice -error {
+ --with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary.
+ On Ubuntu-like systems try:
+ --with-icu-ldflags='-licui18n -licuuc -licudata'
+ }
+ }
+ }
+ if {[file-isexec $icuConfigBin]} {
+ set x [exec $icuConfigBin --ldflags]
+ if {"" eq $x} {
+ proj-indented-notice -error \
+ [subst {
+ $icuConfigBin --ldflags returned no data.
+ On Ubuntu-like systems try:
+ --with-icu-ldflags='-licui18n -licuuc -licudata'
+ }]
+ }
+ define-append LDFLAGS_ICU $x
+ set x [exec $icuConfigBin --cppflags]
+ define-append CFLAGS_ICU $x
+ } else {
+ proj-fatal "--with-icu-config=$icuConfigBin does not refer to an executable"
+ }
+ }
+ }
+ set ldflags [define LDFLAGS_ICU [string trim [get-define LDFLAGS_ICU]]]
+ set cflags [define CFLAGS_ICU [string trim [get-define CFLAGS_ICU]]]
+ if {"" ne $ldflags} {
+ sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU
+ msg-result "Enabling ICU support with flags: $ldflags $cflags"
+ if {[opt-bool icu-collations]} {
+ msg-result "Enabling ICU collations."
+ sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU_COLLATIONS
+ # Recall that shell.c builds with sqlite3.c except in the case
+ # of --disable-static-shell, a combination we do not
+ # specifically attempt to account for.
+ }
+ } elseif {[opt-bool icu-collations]} {
+ proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
+ } else {
+ msg-result "ICU support is disabled."
+ }
+}; # sqlite-handle-icu
+
+
+########################################################################
+# Handles the --enable-load-extension flag. Returns 1 if the support
+# is enabled, else 0. If support for that feature is not found, a
+# fatal error is triggered if --enable-load-extension is explicitly
+# provided, else a loud warning is instead emitted. If
+# --disable-load-extension is used, no check is performed.
+#
+# Makes the following environment changes:
+#
+# - defines LDFLAGS_DLOPEN to any linker flags needed for this
+# feature. It may legally be empty on some systems where dlopen()
+# is in libc.
+#
+# - If the feature is not available, adds
+# -DSQLITE_OMIT_LOAD_EXTENSION=1 to the feature flags list.
+proc sqlite-handle-load-extension {} {
+ define LDFLAGS_DLOPEN ""
+ set found 0
+ proj-if-opt-truthy load-extension {
+ set found [proj-check-function-in-lib dlopen dl]
+ if {$found} {
+ define LDFLAGS_DLOPEN [get-define lib_dlopen]
+ undefine lib_dlopen
+ } else {
+ if {[proj-opt-was-provided load-extension]} {
+ # Explicit --enable-load-extension: fail if not found
+ proj-indented-notice -error {
+ --enable-load-extension was provided but dlopen()
+ not found. Use --disable-load-extension to bypass this
+ check.
+ }
+ } else {
+ # It was implicitly enabled: warn if not found
+ proj-indented-notice {
+ WARNING: dlopen() not found, so loadable module support will
+ be disabled. Use --disable-load-extension to bypass this
+ check.
+ }
+ }
+ }
+ }
+ if {$found} {
+ msg-result "Loadable extension support enabled."
+ } else {
+ msg-result "Disabling loadable extension support. Use --enable-load-extension to enable them."
+ sqlite-add-feature-flag -DSQLITE_OMIT_LOAD_EXTENSION=1
+ }
+ return $found
+}
+
+########################################################################
+# Handles the --enable-math flag.
+proc sqlite-handle-math {} {
+ proj-if-opt-truthy math {
+ if {![proj-check-function-in-lib ceil m]} {
+ user-error "Cannot find libm functions. Use --disable-math to bypass this."
+ }
+ define LDFLAGS_MATH [get-define lib_ceil]
+ undefine lib_ceil
+ sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS
+ msg-result "Enabling math SQL functions"
+ } {
+ define LDFLAGS_MATH ""
+ msg-result "Disabling math SQL functions"
+ }
+}
+
+########################################################################
+# If this OS looks like a Mac, checks for the Mac-specific
+# -current_version and -compatibility_version linker flags. Defines
+# LDFLAGS_MAC_CVERSION to an empty string and returns 0 if they're not
+# supported, else defines that to the linker flags and returns 1.
+#
+# We don't check this on non-Macs because this whole thing is a
+# libtool compatibility kludge to account for a version stamp which
+# libtool applied only on Mac platforms.
+#
+# Based on https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7.
+proc sqlite-handle-mac-cversion {} {
+ define LDFLAGS_MAC_CVERSION ""
+ set rc 0
+ if {[proj-looks-like-mac]} {
+ cc-with {-link 1} {
+ # These version numbers are historical libtool-defined values, not
+ # library-defined ones
+ if {[cc-check-flags "-Wl,-current_version,9.6.0"]
+ && [cc-check-flags "-Wl,-compatibility_version,9.0.0"]} {
+ define LDFLAGS_MAC_CVERSION "-Wl,-compatibility_version,9.0.0 -Wl,-current_version,9.6.0"
+ set rc 1
+ } elseif {[cc-check-flags "-compatibility_version 9.0.0"]
+ && [cc-check-flags "-current_version 9.6.0"]} {
+ define LDFLAGS_MAC_CVERSION "-compatibility_version 9.0.0 -current_version 9.6.0"
+ set rc 1
+ }
+ }
+ }
+ return $rc
+}
+
+########################################################################
+# If this is a Mac platform, check for support for
+# -Wl,-install_name,... and, if it's available, define
+# LDFLAGS_MAC_INSTALL_NAME to a variant of that string which is
+# intended to expand at make-time, else set LDFLAGS_MAC_INSTALL_NAME
+# to an empty string.
+#
+# https://sqlite.org/forum/forumpost/5651662b8875ec0a
+proc sqlite-handle-mac-install-name {} {
+ define LDFLAGS_MAC_INSTALL_NAME ""; # {-Wl,-install_name,"$(install-dir.lib)/$(libsqlite3.DLL)"}
+ set rc 0
+ if {[proj-looks-like-mac]} {
+ cc-with {-link 1} {
+ if {[cc-check-flags "-Wl,-install_name,/usr/local/lib/libsqlite3.dylib"]} {
+ define LDFLAGS_MAC_INSTALL_NAME {-Wl,-install_name,"$(install-dir.lib)/$(libsqlite3.DLL)"}
+ set rc 1
+ }
+ }
+ }
+ return $rc
+}
+
+########################################################################
+# Handles the --dll-basename configure flag. [define]'s
+# SQLITE_DLL_BASENAME to the DLL's preferred base name (minus
+# extension). If --dll-basename is not provided (or programmatically
+# set - see [sqlite-handle-env-quirks]) then this is always
+# "libsqlite3", otherwise it may use a different value based on the
+# value of [get-define host].
+proc sqlite-handle-dll-basename {} {
+ if {[proj-opt-was-provided dll-basename]} {
+ set dn [join [opt-val dll-basename] ""]
+ if {$dn in {none default}} { set dn libsqlite3 }
+ } else {
+ set dn libsqlite3
+ }
+ if {$dn in {auto ""}} {
+ switch -glob -- [get-define host] {
+ *-*-cygwin { set dn cygsqlite3-0 }
+ *-*-ming* { set dn libsqlite3-0 }
+ *-*-msys { set dn msys-sqlite3-0 }
+ default { set dn libsqlite3 }
+ }
+ }
+ define SQLITE_DLL_BASENAME $dn
+}
+
+########################################################################
+# [define]s LDFLAGS_OUT_IMPLIB to either an empty string or to a
+# -Wl,... flag for the platform-specific --out-implib flag, which is
+# used for building an "import library .dll.a" file on some platforms
+# (e.g. msys2, mingw). SQLITE_OUT_IMPLIB is defined to the name of the
+# import lib or an empty string. Returns 1 if supported, else 0.
+#
+# The name of the import library is [define]d in SQLITE_OUT_IMPLIB.
+#
+# If the configure flag --out-implib is not used (or programmatically
+# set) then this simply sets the above-listed defines to empty strings
+# (but see [sqlite-handle-env-quirks]). If that flag is used but the
+# capability is not available, a fatal error is triggered.
+#
+# This feature is specifically opt-in because it's supported on far
+# more platforms than actually need it and enabling it causes creation
+# of libsqlite3.so.a files which are unnecessary in most environments.
+#
+# Added in response to: https://sqlite.org/forum/forumpost/0c7fc097b2
+#
+# Platform notes:
+#
+# - cygwin sqlite packages historically install no .dll.a file.
+#
+# - msys2 and mingw sqlite packages historically install
+# /usr/lib/libsqlite3.dll.a despite the DLL being in
+# /usr/bin.
+proc sqlite-handle-out-implib {} {
+ define LDFLAGS_OUT_IMPLIB ""
+ define SQLITE_OUT_IMPLIB ""
+ set rc 0
+ if {[proj-opt-was-provided out-implib]} {
+ set olBaseName [join [opt-val out-implib] ""]
+ if {$olBaseName in {auto ""}} {
+ set olBaseName "libsqlite3" ;# [get-define SQLITE_DLL_BASENAME]
+ # Based on discussions with mingw/msys users, the import lib
+ # should always be called libsqlite3.dll.a even on platforms
+ # which rename libsqlite3.dll to something else.
+ }
+ if {$olBaseName ne "none"} {
+ cc-with {-link 1} {
+ set dll "${olBaseName}[get-define TARGET_DLLEXT]"
+ set flags [proj-cc-check-Wl-flag --out-implib ${dll}.a]
+ if {"" ne $flags} {
+ define LDFLAGS_OUT_IMPLIB $flags
+ define SQLITE_OUT_IMPLIB ${dll}.a
+ set rc 1
+ }
+ }
+ if {!$rc} {
+ user-error "--out-implib is not supported on this platform"
+ }
+ }
+ }
+ return $rc
+}
+
+########################################################################
+# If the given platform identifier (defaulting to [get-define host])
+# appears to be one of the Unix-on-Windows environments, returns a
+# brief symbolic name for that environment, else returns an empty
+# string.
+#
+# It does not distinguish between msys and msys2, returning msys for
+# both. The build does not, as of this writing, specifically support
+# msys v1. Similarly, this function returns "mingw" for both "mingw32"
+# and "mingw64".
+proc sqlite-env-is-unix-on-windows {{envTuple ""}} {
+ if {"" eq $envTuple} {
+ set envTuple [get-define host]
+ }
+ set name ""
+ switch -glob -- $envTuple {
+ *-*-cygwin { set name cygwin }
+ *-*-ming* { set name mingw }
+ *-*-msys { set name msys }
+ }
+ return $name
+}
+
+########################################################################
+# Performs various tweaks to the build which are only relevant on
+# certain platforms, e.g. Mac and "Unix on Windows" platforms (msys2,
+# cygwin, ...).
+#
+# 1) DLL installation:
+#
+# [define]s SQLITE_DLL_INSTALL_RULES to a symbolic name suffix for a
+# set of "make install" rules to use for installation of the DLL
+# deliverable. The makefile is tasked with providing rules named
+# install-dll-NAME which runs the installation for that set, as well
+# as providing a rule named install-dll which resolves to
+# install-dll-NAME (perhaps indirectly, depending on whether the DLL
+# is (de)activated).
+#
+# The default value is "unix-generic".
+#
+# 2) --out-implib:
+#
+# On platforms where an "import library" is conventionally used but
+# --out-implib was not explicitly used, automatically add that flag.
+# This conventionally applies only to the "Unix on Windows"
+# environments like msys and cygwin.
+#
+# 3) --dll-basename:
+#
+# On the same platforms addressed by --out-implib, if --dll-basename
+# is not explicitly specified, --dll-basename=auto is implied.
+proc sqlite-handle-env-quirks {} {
+ set instName unix-generic; # name of installation rules set
+ set autoDll 0; # true if --out-implib/--dll-basename should be implied
+ set host [get-define host]
+ switch -glob -- $host {
+ *apple* -
+ *darwin* { set instName darwin }
+ default {
+ set x [sqlite-env-is-unix-on-windows $host]
+ if {"" ne $x} {
+ set instName $x
+ set autoDll 1
+ }
+ }
+ }
+ define SQLITE_DLL_INSTALL_RULES $instName
+ if {$autoDll} {
+ if {![proj-opt-was-provided out-implib]} {
+ # Imply --out-implib=auto
+ proj-indented-notice [subst -nocommands -nobackslashes {
+ NOTICE: auto-enabling --out-implib for environment [$host].
+ Use --out-implib=none to disable this special case
+ or --out-implib=auto to squelch this notice.
+ }]
+ proj-opt-set out-implib auto
+ }
+ if {![proj-opt-was-provided dll-basename]} {
+ # Imply --dll-basename=auto
+ proj-indented-notice [subst -nocommands -nobackslashes {
+ NOTICE: auto-enabling --dll-basename for environment [$host].
+ Use --dll-basename=default to disable this special case
+ or --dll-basename=auto to squelch this notice.
+ }]
+ proj-opt-set dll-basename auto
+ }
+ }
+ sqlite-handle-dll-basename
+ sqlite-handle-out-implib
+ sqlite-handle-mac-cversion
+ sqlite-handle-mac-install-name
+ if {[llength [info proc sqlite-custom-handle-flags]] > 0} {
+ # sqlite-custom-handle-flags is assumed to be imported via a
+ # client-specific import: autosetup/sqlite-custom.tcl.
+ sqlite-custom-handle-flags
+ }
+}
+
+########################################################################
+# Perform some late-stage work and generate the configure-process
+# output file(s).
+proc sqlite-process-dot-in-files {} {
+ ########################################################################
+ # "Re-export" the autoconf-conventional --XYZdir flags into something
+ # which is more easily overridable from a make invocation. See the docs
+ # for [proj-remap-autoconf-dir-vars] for the explanation of why.
+ #
+ # We do this late in the config process, immediately before we export
+ # the Makefile and other generated files, so that configure tests
+ # which make make use of the autotools-conventional flags
+ # (e.g. [proj-check-rpath]) may do so before we "mangle" them here.
+ proj-remap-autoconf-dir-vars
+
+ proj-dot-ins-process -validate
+ make-config-header sqlite_cfg.h \
+ -bare {SIZEOF_* HAVE_DECL_*} \
+ -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG
+ TARGET_* USE_GCOV TCL_*} \
+ -auto {HAVE_* PACKAGE_*} \
+ -none *
+ proj-touch sqlite_cfg.h ; # help avoid frequent unnecessary @SQLITE_AUTORECONFIG@
+}
+
+########################################################################
+# Handle --with-wasi-sdk[=DIR]
+#
+# This must be run relatively early on because it may change the
+# toolchain and disable a number of config options. However, in the
+# canonical build this must come after [sqlite-check-common-bins].
+proc sqlite-handle-wasi-sdk {} {
+ set wasiSdkDir [opt-val with-wasi-sdk] ; # ??? [lindex [opt-val with-wasi-sdk] end]
+ define HAVE_WASI_SDK 0
+ if {$wasiSdkDir eq ""} {
+ return 0
+ } elseif {$::sqliteConfig(is-cross-compiling)} {
+ proj-fatal "Cannot combine --with-wasi-sdk with cross-compilation"
+ }
+ msg-result "Checking WASI SDK directory \[$wasiSdkDir]... "
+ proj-affirm-files-exist -v {*}[prefix "$wasiSdkDir/bin/" {clang wasm-ld ar}]
+ define HAVE_WASI_SDK 1
+ define WASI_SDK_DIR $wasiSdkDir
+ # Disable numerous options which we know either can't work or are
+ # not useful in this build...
+ msg-result "Using wasi-sdk clang. Disabling CLI shell and modifying config flags:"
+ # Boolean (--enable-/--disable-) flags which must be switched off:
+ foreach opt {
+ dynlink-tools
+ editline
+ gcov
+ icu-collations
+ load-extension
+ readline
+ shared
+ tcl
+ threadsafe
+ } {
+ if {[proj-opt-exists $opt] && [opt-bool $opt]} {
+ # -^^^^ not all builds define all of these flags
+ msg-result " --disable-$opt"
+ proj-opt-set $opt 0
+ }
+ }
+ # Non-boolean flags which need to be cleared:
+ foreach opt {
+ with-emsdk
+ with-icu-config
+ with-icu-ldflags
+ with-icu-cflags
+ with-linenoise
+ with-tcl
+ } {
+ if {[proj-opt-was-provided $opt]} {
+ msg-result " removing --$opt"
+ proj-opt-set $opt ""
+ }
+ }
+ # Remember that we now have a discrepancy between
+ # $::sqliteConfig(is-cross-compiling) and [proj-is-cross-compiling].
+ set ::sqliteConfig(is-cross-compiling) 1
+
+ #
+ # Changing --host and --target have no effect here except to
+ # possibly cause confusion. Autosetup has finished processing them
+ # by this point.
+ #
+ # host_alias=wasm32-wasi
+ # target=wasm32-wasi
+ #
+ # Merely changing CC, LD, and AR to the wasi-sdk's is enough to get
+ # sqlite3.o building in WASM format.
+ #
+ define CC "${wasiSdkDir}/bin/clang"
+ define LD "${wasiSdkDir}/bin/wasm-ld"
+ define AR "${wasiSdkDir}/bin/ar"
+ #define STRIP "${wasiSdkDir}/bin/strip"
+ return 1
+}; # sqlite-handle-wasi-sdk
+
+########################################################################
+# TCL...
+#
+# sqlite-check-tcl performs most of the --with-tcl and --with-tclsh
+# handling. Some related bits and pieces are performed before and
+# after that function is called.
+#
+# Important [define]'d vars:
+#
+# - HAVE_TCL indicates whether we have a tclsh suitable for building
+# the TCL SQLite extension and, by extension, the testing
+# infrastructure. This must only be 1 for environments where
+# tclConfig.sh can be found.
+#
+# - TCLSH_CMD is the path to the canonical tclsh or "". It never
+# refers to jimtcl.
+#
+# - TCL_CONFIG_SH is the path to tclConfig.sh or "".
+#
+# - TCLLIBDIR is the dir to which libtclsqlite3 gets installed.
+#
+# - BTCLSH = the path to the tcl interpreter used for in-tree code
+# generation. It may be jimtcl or the canonical tclsh but may not
+# be empty - this tree requires TCL to generated numerous
+# components.
+#
+# If --tcl or --with-tcl are provided but no TCL is found, this
+# function fails fatally. If they are not explicitly provided then
+# failure to find TCL is not fatal but a loud warning will be emitted.
+#
+proc sqlite-check-tcl {} {
+ define TCLSH_CMD false ; # Significant is that it exits with non-0
+ define HAVE_TCL 0 ; # Will be enabled via --tcl or a successful search
+ define TCLLIBDIR "" ; # Installation dir for TCL extension lib
+ define TCL_CONFIG_SH ""; # full path to tclConfig.sh
+
+ # Clear out all vars which would harvest from tclConfig.sh so that
+ # the late-config validation of @VARS@ works even if --disable-tcl
+ # is used.
+ proj-tclConfig-sh-to-autosetup ""
+
+ file delete -force ".tclenv.sh"; # ensure no stale state from previous configures.
+ if {![opt-bool tcl]} {
+ proj-indented-notice {
+ NOTE: TCL is disabled via --disable-tcl. This means that none
+ of the TCL-based components will be built, including tests
+ and sqlite3_analyzer.
+ }
+ return
+ }
+ # TODO: document the steps this is taking.
+ set srcdir $::autosetup(srcdir)
+ msg-result "Checking for a suitable tcl... "
+ proj-assert [proj-opt-truthy tcl]
+ set use_tcl 1
+ set with_tclsh [opt-val with-tclsh]
+ set with_tcl [opt-val with-tcl]
+ if {"prefix" eq $with_tcl} {
+ set with_tcl [get-define prefix]
+ }
+ proc-debug "use_tcl ${use_tcl}"
+ proc-debug "with_tclsh=${with_tclsh}"
+ proc-debug "with_tcl=$with_tcl"
+ if {"" eq $with_tclsh && "" eq $with_tcl} {
+ # If neither --with-tclsh nor --with-tcl are provided, try to find
+ # a workable tclsh.
+ set with_tclsh [proj-first-bin-of tclsh9.1 tclsh9.0 tclsh8.6 tclsh]
+ proc-debug "with_tclsh=${with_tclsh}"
+ }
+
+ set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases
+ if {"" ne $with_tclsh} {
+ # --with-tclsh was provided or found above. Validate it and use it
+ # to trump any value passed via --with-tcl=DIR.
+ if {![file-isexec $with_tclsh]} {
+ proj-fatal "TCL shell $with_tclsh is not executable"
+ } else {
+ define TCLSH_CMD $with_tclsh
+ #msg-result "Using tclsh: $with_tclsh"
+ }
+ if {$doConfigLookup &&
+ [catch {exec $with_tclsh $::autosetup(libdir)/find_tclconfig.tcl} result] == 0} {
+ set with_tcl $result
+ }
+ if {"" ne $with_tcl && [file isdir $with_tcl]} {
+ msg-result "$with_tclsh recommends the tclConfig.sh from $with_tcl"
+ } else {
+ proj-warn "$with_tclsh is unable to recommend a tclConfig.sh"
+ set use_tcl 0
+ }
+ }
+ set cfg ""
+ set tclSubdirs {tcl9.1 tcl9.0 tcl8.6 lib}
+ while {$use_tcl} {
+ if {"" ne $with_tcl} {
+ # Ensure that we can find tclConfig.sh under ${with_tcl}/...
+ if {$doConfigLookup} {
+ if {[file readable "${with_tcl}/tclConfig.sh"]} {
+ set cfg "${with_tcl}/tclConfig.sh"
+ } else {
+ foreach i $tclSubdirs {
+ if {[file readable "${with_tcl}/$i/tclConfig.sh"]} {
+ set cfg "${with_tcl}/$i/tclConfig.sh"
+ break
+ }
+ }
+ }
+ }
+ if {"" eq $cfg} {
+ proj-fatal "No tclConfig.sh found under ${with_tcl}"
+ }
+ } else {
+ # If we have not yet found a tclConfig.sh file, look in $libdir
+ # which is set automatically by autosetup or via the --prefix
+ # command-line option. See
+ # https://sqlite.org/forum/forumpost/e04e693439a22457
+ set libdir [get-define libdir]
+ if {[file readable "${libdir}/tclConfig.sh"]} {
+ set cfg "${libdir}/tclConfig.sh"
+ } else {
+ foreach i $tclSubdirs {
+ if {[file readable "${libdir}/$i/tclConfig.sh"]} {
+ set cfg "${libdir}/$i/tclConfig.sh"
+ break
+ }
+ }
+ }
+ if {![file readable $cfg]} {
+ break
+ }
+ }
+ msg-result "Using tclConfig.sh: $cfg"
+ break
+ }
+ define TCL_CONFIG_SH $cfg
+ # Export a subset of tclConfig.sh to the current TCL-space. If $cfg
+ # is an empty string, this emits empty-string entries for the
+ # various options we're interested in.
+ proj-tclConfig-sh-to-autosetup $cfg
+
+ if {"" eq $with_tclsh && $cfg ne ""} {
+ # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh
+ # based on info from tclConfig.sh.
+ set tclExecPrefix [get-define TCL_EXEC_PREFIX]
+ proj-assert {"" ne $tclExecPrefix}
+ set tryThese [list \
+ $tclExecPrefix/bin/tclsh[get-define TCL_VERSION] \
+ $tclExecPrefix/bin/tclsh ]
+ foreach trySh $tryThese {
+ if {[file-isexec $trySh]} {
+ set with_tclsh $trySh
+ break
+ }
+ }
+ if {![file-isexec $with_tclsh]} {
+ proj-warn "Cannot find a usable tclsh (tried: $tryThese)
+ }
+ }
+ define TCLSH_CMD $with_tclsh
+ if {$use_tcl} {
+ # Set up the TCLLIBDIR
+ #
+ # 2024-10-28: calculation of TCLLIBDIR is now done via the shell
+ # in main.mk (search it for T.tcl.env.sh) so that
+ # static/hand-written makefiles which import main.mk do not have
+ # to define that before importing main.mk. Even so, we export
+ # TCLLIBDIR from here, which will cause the canonical makefile to
+ # use this one rather than to re-calculate it at make-time.
+ set tcllibdir [get-env TCLLIBDIR ""]
+ if {"" eq $tcllibdir} {
+ # Attempt to extract TCLLIBDIR from TCL's $auto_path
+ if {"" ne $with_tclsh &&
+ [catch {exec echo "puts stdout \$auto_path" | "$with_tclsh"} result] == 0} {
+ foreach i $result {
+ if {[file isdir $i]} {
+ set tcllibdir $i/sqlite3
+ break
+ }
+ }
+ } else {
+ proj-warn "Cannot determine TCLLIBDIR."
+ # The makefile will fail fatally in this case if a target is
+ # invoked which requires TCLLIBDIR.
+ }
+ }
+ #if {"" ne $tcllibdir} { msg-result "TCLLIBDIR = ${tcllibdir}"; }
+ define TCLLIBDIR $tcllibdir
+ }; # find TCLLIBDIR
+
+ if {[file-isexec $with_tclsh]} {
+ msg-result "Using tclsh: $with_tclsh"
+ if {$cfg ne ""} {
+ define HAVE_TCL 1
+ } else {
+ proj-warn "Found tclsh but no tclConfig.sh."
+ }
+ }
+ show-notices
+ # If TCL is not found: if it was explicitly requested then fail
+ # fatally, else just emit a warning. If we can find the APIs needed
+ # to generate a working JimTCL then that will suffice for build-time
+ # TCL purposes (see: proc sqlite-determine-codegen-tcl).
+ if {![get-define HAVE_TCL] &&
+ ([proj-opt-was-provided tcl] || [proj-opt-was-provided with-tcl])} {
+ proj-fatal "TCL support was requested but no tclConfig.sh could be found."
+ }
+ if {"" eq $cfg} {
+ proj-assert {0 == [get-define HAVE_TCL]}
+ proj-indented-notice {
+ WARNING: Cannot find a usable tclConfig.sh file. Use
+ --with-tcl=DIR to specify a directory where tclConfig.sh can be
+ found. SQLite does not use TCL internally, but some optional
+ components require TCL, including tests and sqlite3_analyzer.
+ }
+ }
+}; # sqlite-check-tcl
+
+########################################################################
+# sqlite-determine-codegen-tcl checks which TCL to use as a code
+# generator. By default, prefer jimsh simply because we have it
+# in-tree (it's part of autosetup) unless --with-tclsh=X is used, in
+# which case prefer X.
+#
+# Returns the human-readable name of the TCL it selects. Fails fatally
+# if it cannot detect a TCL appropriate for code generation.
+#
+# Defines:
+#
+# - BTCLSH = the TCL shell used for code generation. It may set this
+# to an unexpanded makefile var name.
+#
+# - CFLAGS_JIMSH = any flags needed for buildng a BTCLSH-compatible
+# jimsh. The defaults may be passed on to configure as
+# CFLAGS_JIMSH=...
+proc sqlite-determine-codegen-tcl {} {
+ msg-result "Checking for TCL to use for code generation... "
+ define CFLAGS_JIMSH [proj-get-env CFLAGS_JIMSH {-O1}]
+ set cgtcl [opt-val with-tclsh jimsh]
+ if {"jimsh" ne $cgtcl} {
+ # When --with-tclsh=X is used, use that for all TCL purposes,
+ # including in-tree code generation, per developer request.
+ define BTCLSH "\$(TCLSH_CMD)"
+ return $cgtcl
+ }
+ set flagsToRestore {CC CFLAGS AS_CFLAGS CPPFLAGS AS_CPPFLAGS LDFLAGS LINKFLAGS LIBS CROSS}
+ define-push $flagsToRestore {
+ # We have to swap CC to CC_FOR_BUILD for purposes of the various
+ # [cc-...] tests below. Recall that --with-wasi-sdk may have
+ # swapped out CC with one which is not appropriate for this block.
+ # Per consulation with autosetup's creator, doing this properly
+ # requires us to [define-push] the whole $flagsToRestore list
+ # (plus a few others which are not relevant in this tree).
+ #
+ # These will get set to their previous values at the end of this
+ # block.
+ foreach flag $flagsToRestore {define $flag ""}
+ define CC [get-define CC_FOR_BUILD]
+ # These headers are technically optional for JimTCL but necessary if
+ # we want to use it for code generation:
+ set sysh [cc-check-includes dirent.h sys/time.h]
+ # jimsh0.c hard-codes #define's for HAVE_DIRENT_H and
+ # HAVE_SYS_TIME_H on the platforms it supports, so we do not
+ # need to add -D... flags for those. We check for them here only
+ # so that we can avoid the situation that we later, at
+ # make-time, try to compile jimsh but it then fails due to
+ # missing headers (i.e. fail earlier rather than later).
+ if {$sysh && [cc-check-functions realpath]} {
+ define-append CFLAGS_JIMSH -DHAVE_REALPATH
+ define BTCLSH "\$(JIMSH)"
+ set ::sqliteConfig(use-jim-for-codegen) 1
+ } elseif {$sysh && [cc-check-functions _fullpath]} {
+ # _fullpath() is a Windows API. It's not entirely clear
+ # whether we need to add {-DHAVE_SYS_TIME_H -DHAVE_DIRENT_H}
+ # to CFLAGS_JIMSH in this case. On MinGW32 we definitely do
+ # not want to because it already hard-codes them. On _MSC_VER
+ # builds it does not.
+ define-append CFLAGS_JIMSH -DHAVE__FULLPATH
+ define BTCLSH "\$(JIMSH)"
+ set ::sqliteConfig(use-jim-for-codegen) 1
+ } elseif {[file-isexec [get-define TCLSH_CMD]]} {
+ set cgtcl [get-define TCLSH_CMD]
+ define BTCLSH "\$(TCLSH_CMD)"
+ } else {
+ # One last-ditch effort to find TCLSH_CMD: use info from
+ # tclConfig.sh to try to find a tclsh
+ if {"" eq [get-define TCLSH_CMD]} {
+ set tpre [get-define TCL_EXEC_PREFIX]
+ if {"" ne $tpre} {
+ set tv [get-define TCL_VERSION]
+ if {[file-isexec "${tpre}/bin/tclsh${tv}"]} {
+ define TCLSH_CMD "${tpre}/bin/tclsh${tv}"
+ } elseif {[file-isexec "${tpre}/bin/tclsh"]} {
+ define TCLSH_CMD "${tpre}/bin/tclsh"
+ }
+ }
+ }
+ set cgtcl [get-define TCLSH_CMD]
+ if {![file-isexec $cgtcl]} {
+ proj-fatal "Cannot find a tclsh to use for code generation."
+ }
+ define BTCLSH "\$(TCLSH_CMD)"
+ }
+ }; # /define-push $flagsToRestore
+ return $cgtcl
+}; # sqlite-determine-codegen-tcl
+
+########################################################################
+# Runs sqlite-check-tcl and, if this is the canonical build,
+# sqlite-determine-codegen-tcl.
+proc sqlite-handle-tcl {} {
+ sqlite-check-tcl
+ if {"canonical" eq $::sqliteConfig(build-mode)} {
+ msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]"
+ }
+}
+
+########################################################################
+# Handle the --enable/disable-rpath flag.
+proc sqlite-handle-rpath {} {
+ proj-check-rpath
+ # autosetup/cc-shared.tcl sets the rpath flag definition in
+ # [get-define SH_LINKRPATH], but it does so on a per-platform basis
+ # rather than as a compiler check. Though we should do a proper
+ # compiler check (as proj-check-rpath does), we may want to consider
+ # adopting its approach of clearing the rpath flags for environments
+ # for which sqlite-env-is-unix-on-windows returns a non-empty
+ # string.
+
+# if {[proj-opt-truthy rpath]} {
+# proj-check-rpath
+# } else {
+# msg-result "Disabling use of rpath."
+# define LDFLAGS_RPATH ""
+# }
+}
+
+########################################################################
+# If the --dump-defines configure flag is provided then emit a list of
+# all [define] values to config.defines.txt, else do nothing.
+proc sqlite-dump-defines {} {
+ proj-if-opt-truthy dump-defines {
+ make-config-header $::sqliteConfig(dump-defines-txt) \
+ -bare {SQLITE_OS* SQLITE_DEBUG USE_*} \
+ -str {BIN_* CC LD AR LDFLAG* OPT_*} \
+ -auto {*}
+ # achtung: ^^^^ whichever SQLITE_OS_foo flag which is set to 0 will
+ # get _undefined_ here unless it's part of the -bare set.
+ if {"" ne $::sqliteConfig(dump-defines-json)} {
+ msg-result "--dump-defines is creating $::sqliteConfig(dump-defines-json)"
+ ########################################################################
+ # Dump config-defines.json...
+ # Demonstrate (mis?)handling of spaces in JSON-export array values:
+ # define-append OPT_FOO.list {"-DFOO=bar baz" -DBAR="baz barre"}
+ define OPT_FEATURE_FLAGS.list [get-define OPT_FEATURE_FLAGS]
+ define OPT_SHELL.list [get-define OPT_SHELL]
+ set dumpDefsOpt {
+ -bare {SIZEOF_* HAVE_DECL_*}
+ -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG TARGET_* USE_GCOV TCL_*}
+ -array {*.list}
+ -auto {OPT_* PACKAGE_* HAVE_*}
+ }
+# if {$::sqliteConfig(dump-defines-json-include-lowercase)} {
+# lappend dumpDefsOpt -none {lib_*} ; # remnants from proj-check-function-in-lib and friends
+# lappend dumpDefsOpt -auto {[a-z]*}
+# }
+ lappend dumpDefsOpt -none *
+ proj-dump-defs-json $::sqliteConfig(dump-defines-json) {*}$dumpDefsOpt
+ undefine OPT_FEATURE_FLAGS.list
+ undefine OPT_SHELL.list
+ }
+ }
+}
diff --git a/contrib/sqlite3/autosetup/system.tcl b/contrib/sqlite3/autosetup/system.tcl
new file mode 100644
index 000000000000..05d378afdd26
--- /dev/null
+++ b/contrib/sqlite3/autosetup/system.tcl
@@ -0,0 +1,420 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# This module supports common system interrogation and options
+# such as '--host', '--build', '--prefix', and setting 'srcdir', 'builddir', and 'EXEEXT'.
+#
+# It also support the "feature" naming convention, where searching
+# for a feature such as 'sys/type.h' defines 'HAVE_SYS_TYPES_H'.
+#
+# It defines the following variables, based on '--prefix' unless overridden by the user:
+#
+## datadir
+## sysconfdir
+## sharedstatedir
+## localstatedir
+## infodir
+## mandir
+## includedir
+#
+# If '--prefix' is not supplied, it defaults to '/usr/local' unless 'options-defaults { prefix ... }' is used *before*
+# including the 'system' module.
+
+if {[is-defined defaultprefix]} {
+ user-notice "Note: defaultprefix is deprecated. Use options-defaults to set default options"
+ options-defaults [list prefix [get-define defaultprefix]]
+}
+
+options {
+ host:host-alias => {a complete or partial cpu-vendor-opsys for the system where
+ the application will run (defaults to the same value as --build)}
+ build:build-alias => {a complete or partial cpu-vendor-opsys for the system
+ where the application will be built (defaults to the
+ result of running config.guess)}
+ prefix:dir=/usr/local => {the target directory for the build (default: '@default@')}
+
+ # These (hidden) options are supported for autoconf/automake compatibility
+ exec-prefix:
+ bindir:
+ sbindir:
+ includedir:
+ mandir:
+ infodir:
+ libexecdir:
+ datadir:
+ libdir:
+ sysconfdir:
+ sharedstatedir:
+ localstatedir:
+ runstatedir:
+ maintainer-mode=0
+ dependency-tracking=0
+ silent-rules=0
+ program-prefix:
+ program-suffix:
+ program-transform-name:
+ x-includes:
+ x-libraries:
+}
+
+# @check-feature name { script }
+#
+# defines feature '$name' to the return value of '$script',
+# which should be 1 if found or 0 if not found.
+#
+# e.g. the following will define 'HAVE_CONST' to 0 or 1.
+#
+## check-feature const {
+## cctest -code {const int _x = 0;}
+## }
+proc check-feature {name code} {
+ msg-checking "Checking for $name..."
+ set r [uplevel 1 $code]
+ define-feature $name $r
+ if {$r} {
+ msg-result "ok"
+ } else {
+ msg-result "not found"
+ }
+ return $r
+}
+
+# @have-feature name ?default=0?
+#
+# Returns the value of feature '$name' if defined, or '$default' if not.
+#
+# See 'feature-define-name' for how the "feature" name
+# is translated into the "define" name.
+#
+proc have-feature {name {default 0}} {
+ get-define [feature-define-name $name] $default
+}
+
+# @define-feature name ?value=1?
+#
+# Sets the feature 'define' to '$value'.
+#
+# See 'feature-define-name' for how the "feature" name
+# is translated into the "define" name.
+#
+proc define-feature {name {value 1}} {
+ define [feature-define-name $name] $value
+}
+
+# @feature-checked name
+#
+# Returns 1 if feature '$name' has been checked, whether true or not.
+#
+proc feature-checked {name} {
+ is-defined [feature-define-name $name]
+}
+
+# @feature-define-name name ?prefix=HAVE_?
+#
+# Converts a "feature" name to the corresponding "define",
+# e.g. 'sys/stat.h' becomes 'HAVE_SYS_STAT_H'.
+#
+# Converts '*' to 'P' and all non-alphanumeric to underscore.
+#
+proc feature-define-name {name {prefix HAVE_}} {
+ string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
+}
+
+# @write-if-changed filename contents ?script?
+#
+# If '$filename' doesn't exist, or it's contents are different to '$contents',
+# the file is written and '$script' is evaluated.
+#
+# Otherwise a "file is unchanged" message is displayed.
+proc write-if-changed {file buf {script {}}} {
+ set old [readfile $file ""]
+ if {$old eq $buf && [file exists $file]} {
+ msg-result "$file is unchanged"
+ } else {
+ writefile $file $buf\n
+ uplevel 1 $script
+ }
+}
+
+
+# @include-file infile mapping
+#
+# The core of make-template, called recursively for each @include
+# directive found within that template so that this proc's result
+# is the fully-expanded template.
+#
+# The mapping parameter is how we expand @varname@ within the template.
+# We do that inline within this step only for @include directives which
+# can have variables in the filename arg. A separate substitution pass
+# happens when this recursive function returns, expanding the rest of
+# the variables.
+#
+proc include-file {infile mapping} {
+ # A stack of true/false conditions, one for each nested conditional
+ # starting with "true"
+ set condstack {1}
+ set result {}
+ set linenum 0
+ foreach line [split [readfile $infile] \n] {
+ incr linenum
+ if {[regexp {^@(if|else|endif)(\s*)(.*)} $line -> condtype condspace condargs]} {
+ if {$condtype eq "if"} {
+ if {[string length $condspace] == 0} {
+ autosetup-error "$infile:$linenum: Invalid expression: $line"
+ }
+ if {[llength $condargs] == 1} {
+ # ABC => [get-define ABC] ni {0 ""}
+ # !ABC => [get-define ABC] in {0 ""}
+ lassign $condargs condvar
+ if {[regexp {^!(.*)} $condvar -> condvar]} {
+ set op in
+ } else {
+ set op ni
+ }
+ set condexpr "\[[list get-define $condvar]\] $op {0 {}}"
+ } else {
+ # Translate alphanumeric ABC into [get-define ABC] and leave the
+ # rest of the expression untouched
+ regsub -all {([A-Z][[:alnum:]_]*)} $condargs {[get-define \1]} condexpr
+ }
+ if {[catch [list expr $condexpr] condval]} {
+ dputs $condval
+ autosetup-error "$infile:$linenum: Invalid expression: $line"
+ }
+ dputs "@$condtype: $condexpr => $condval"
+ }
+ if {$condtype ne "if"} {
+ if {[llength $condstack] <= 1} {
+ autosetup-error "$infile:$linenum: Error: @$condtype missing @if"
+ } elseif {[string length $condargs] && [string index $condargs 0] ne "#"} {
+ autosetup-error "$infile:$linenum: Error: Extra arguments after @$condtype"
+ }
+ }
+ switch -exact $condtype {
+ if {
+ # push condval
+ lappend condstack $condval
+ }
+ else {
+ # Toggle the last entry
+ set condval [lpop condstack]
+ set condval [expr {!$condval}]
+ lappend condstack $condval
+ }
+ endif {
+ if {[llength $condstack] == 0} {
+ user-notice "$infile:$linenum: Error: @endif missing @if"
+ }
+ lpop condstack
+ }
+ }
+ continue
+ }
+ # Only continue if the stack contains all "true"
+ if {"0" in $condstack} {
+ continue
+ }
+ if {[regexp {^@include\s+(.*)} $line -> filearg]} {
+ set incfile [string map $mapping $filearg]
+ if {[file exists $incfile]} {
+ lappend ::autosetup(deps) [file-normalize $incfile]
+ lappend result {*}[include-file $incfile $mapping]
+ } else {
+ user-error "$infile:$linenum: Include file $incfile is missing"
+ }
+ continue
+ }
+ if {[regexp {^@define\s+(\w+)\s+(.*)} $line -> var val]} {
+ define $var $val
+ continue
+ }
+ lappend result $line
+ }
+ return $result
+}
+
+
+# @make-template template ?outfile?
+#
+# Reads the input file '<srcdir>/$template' and writes the output file '$outfile'
+# (unless unchanged).
+# If '$outfile' is blank/omitted, '$template' should end with '.in' which
+# is removed to create the output file name.
+#
+# Each pattern of the form '@define@' is replaced with the corresponding
+# "define", if it exists, or left unchanged if not.
+#
+# The special value '@srcdir@' is substituted with the relative
+# path to the source directory from the directory where the output
+# file is created, while the special value '@top_srcdir@' is substituted
+# with the relative path to the top level source directory.
+#
+# Conditional sections may be specified as follows:
+## @if NAME eq "value"
+## lines
+## @else
+## lines
+## @endif
+#
+# Where 'NAME' is a defined variable name and '@else' is optional.
+# Note that variables names *must* start with an uppercase letter.
+# If the expression does not match, all lines through '@endif' are ignored.
+#
+# The alternative forms may also be used:
+## @if NAME (true if the variable is defined, but not empty and not "0")
+## @if !NAME (opposite of the form above)
+## @if <general-tcl-expression>
+#
+# In the general Tcl expression, any words beginning with an uppercase letter
+# are translated into [get-define NAME]
+#
+# Expressions may be nested
+#
+proc make-template {template {out {}}} {
+ set infile [file join $::autosetup(srcdir) $template]
+
+ if {![file exists $infile]} {
+ user-error "Template $template is missing"
+ }
+
+ # Define this as late as possible
+ define AUTODEPS $::autosetup(deps)
+
+ if {$out eq ""} {
+ if {[file ext $template] ne ".in"} {
+ autosetup-error "make_template $template has no target file and can't guess"
+ }
+ set out [file rootname $template]
+ }
+
+ set outdir [file dirname $out]
+
+ # Make sure the directory exists
+ file mkdir $outdir
+
+ # Set up srcdir and top_srcdir to be relative to the target dir
+ define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
+ define top_srcdir [relative-path $::autosetup(srcdir) $outdir]
+
+ # Build map from global defines to their values so they can be
+ # substituted into @include file names.
+ proc build-define-mapping {} {
+ set mapping {}
+ foreach {n v} [array get ::define] {
+ lappend mapping @$n@ $v
+ }
+ return $mapping
+ }
+ set mapping [build-define-mapping]
+
+ set result [include-file $infile $mapping]
+
+ # Rebuild the define mapping in case we ran across @define
+ # directives in the template or a file it @included, then
+ # apply that mapping to the expanded template.
+ set mapping [build-define-mapping]
+ write-if-changed $out [string map $mapping [join $result \n]] {
+ msg-result "Created [relative-path $out] from [relative-path $template]"
+ }
+}
+
+proc system-init {} {
+ global autosetup
+
+ # build/host tuples and cross-compilation prefix
+ opt-str build build ""
+ define build_alias $build
+ if {$build eq ""} {
+ define build [config_guess]
+ } else {
+ define build [config_sub $build]
+ }
+
+ opt-str host host ""
+ define host_alias $host
+ if {$host eq ""} {
+ define host [get-define build]
+ set cross ""
+ } else {
+ define host [config_sub $host]
+ set cross $host-
+ }
+ define cross [get-env CROSS $cross]
+
+ # build/host _cpu, _vendor and _os
+ foreach type {build host} {
+ set v [get-define $type]
+ if {![regexp {^([^-]+)-([^-]+)-(.*)$} $v -> cpu vendor os]} {
+ user-error "Invalid canonical $type: $v"
+ }
+ define ${type}_cpu $cpu
+ define ${type}_vendor $vendor
+ define ${type}_os $os
+ }
+
+ opt-str prefix prefix /usr/local
+
+ # These are for compatibility with autoconf
+ define target [get-define host]
+ define prefix $prefix
+ define builddir $autosetup(builddir)
+ define srcdir $autosetup(srcdir)
+ define top_srcdir $autosetup(srcdir)
+ define abs_top_srcdir [file-normalize $autosetup(srcdir)]
+ define abs_top_builddir [file-normalize $autosetup(builddir)]
+
+ # autoconf supports all of these
+ define exec_prefix [opt-str exec-prefix exec_prefix $prefix]
+ foreach {name defpath} {
+ bindir /bin
+ sbindir /sbin
+ libexecdir /libexec
+ libdir /lib
+ } {
+ define $name [opt-str $name o $exec_prefix$defpath]
+ }
+ foreach {name defpath} {
+ datadir /share
+ sharedstatedir /com
+ infodir /share/info
+ mandir /share/man
+ includedir /include
+ } {
+ define $name [opt-str $name o $prefix$defpath]
+ }
+ if {$prefix ne {/usr}} {
+ opt-str sysconfdir sysconfdir $prefix/etc
+ } else {
+ opt-str sysconfdir sysconfdir /etc
+ }
+ define sysconfdir $sysconfdir
+
+ define localstatedir [opt-str localstatedir o /var]
+ define runstatedir [opt-str runstatedir o /run]
+
+ define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
+
+ # These could be used to generate Makefiles following some automake conventions
+ define AM_SILENT_RULES [opt-bool silent-rules]
+ define AM_MAINTAINER_MODE [opt-bool maintainer-mode]
+ define AM_DEPENDENCY_TRACKING [opt-bool dependency-tracking]
+
+ # Windows vs. non-Windows
+ switch -glob -- [get-define host] {
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ define-feature windows
+ define EXEEXT .exe
+ }
+ default {
+ define EXEEXT ""
+ }
+ }
+
+ # Display
+ msg-result "Host System...[get-define host]"
+ msg-result "Build System...[get-define build]"
+}
+
+system-init
diff --git a/contrib/sqlite3/autosetup/teaish/README.txt b/contrib/sqlite3/autosetup/teaish/README.txt
new file mode 100644
index 000000000000..e11519b042bd
--- /dev/null
+++ b/contrib/sqlite3/autosetup/teaish/README.txt
@@ -0,0 +1,4 @@
+The *.tcl files in this directory are part of the SQLite's "autoconf"
+bundle which are specific to the TEA(-ish) build. During the tarball
+generation process, they are copied into <TOP>/autoconf/autosetup/teaish
+(which itself is created as part of that process).
diff --git a/contrib/sqlite3/autosetup/teaish/core.tcl b/contrib/sqlite3/autosetup/teaish/core.tcl
new file mode 100644
index 000000000000..09017029d77f
--- /dev/null
+++ b/contrib/sqlite3/autosetup/teaish/core.tcl
@@ -0,0 +1,2539 @@
+########################################################################
+# 2025 April 5
+#
+# 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.
+#
+########################################################################
+# ----- @module teaish.tcl -----
+# @section TEA-ish ((TCL Extension Architecture)-ish)
+#
+# Functions in this file with a prefix of teaish__ are
+# private/internal APIs. Those with a prefix of teaish- are
+# public APIs.
+#
+# Teaish has a hard dependency on proj.tcl, and any public API members
+# of that module are considered legal for use by teaish extensions.
+#
+# Project home page: https://fossil.wanderinghorse.net/r/teaish
+
+use proj
+
+#
+# API-internal settings and shared state.
+array set teaish__Config [proj-strip-hash-comments {
+ #
+ # Teaish's version number, not to be confused with
+ # teaish__PkgInfo(-version).
+ #
+ version 0.1-beta
+
+ # set to 1 to enable some internal debugging output
+ debug-enabled 0
+
+ #
+ # 0 = don't yet have extension's pkgindex
+ # 0x01 = found TEAISH_EXT_DIR/pkgIndex.tcl.in
+ # 0x02 = found srcdir/pkgIndex.tcl.in
+ # 0x10 = found TEAISH_EXT_DIR/pkgIndex.tcl (static file)
+ # 0x20 = static-pkgIndex.tcl pragma: behave as if 0x10
+ # 0x100 = disabled by -tm.tcl.in
+ # 0x200 = disabled by -tm.tcl
+ #
+ # Reminder: it's significant that the bottom 4 bits be
+ # cases where teaish manages ./pkgIndex.tcl.
+ #
+ pkgindex-policy 0
+
+ #
+ # The pkginit counterpart of pkgindex-policy:
+ #
+ # 0 = no pkginit
+ # 0x01 = found default X.in: generate X from X.in
+ # 0x10 = found static pkginit file X
+ # 0x02 = user-provided X.in generates ./X.
+ # 0x20 = user-provided static pkginit file X
+ #
+ # The 0x0f bits indicate that teaish is responsible for cleaning up
+ # the (generated) pkginit file.
+ #
+ pkginit-policy 0
+ #
+ # 0 = no tm.tcl
+ # 0x01 = tm.tcl.in
+ # 0x10 = static tm.tcl
+ tm-policy 0
+
+ #
+ # If 1+ then teaish__verbose will emit messages.
+ #
+ verbose 0
+
+ #
+ # Mapping of pkginfo -flags to their TEAISH_xxx define (if any).
+ # This must not be modified after initialization.
+ #
+ pkginfo-f2d {
+ -name TEAISH_NAME
+ -name.dist TEAISH_DIST_NAME
+ -name.pkg TEAISH_PKGNAME
+ -version TEAISH_VERSION
+ -libDir TEAISH_LIBDIR_NAME
+ -loadPrefix TEAISH_LOAD_PREFIX
+ -vsatisfies TEAISH_VSATISFIES
+ -pkgInit.tcl TEAISH_PKGINIT_TCL
+ -pkgInit.tcl.in TEAISH_PKGINIT_TCL_IN
+ -url TEAISH_URL
+ -tm.tcl TEAISH_TM_TCL
+ -tm.tcl.in TEAISH_TM_TCL_IN
+ -options {}
+ -pragmas {}
+ }
+
+ #
+ # Queues for use with teaish-checks-queue and teaish-checks-run.
+ #
+ queued-checks-pre {}
+ queued-checks-post {}
+
+ # Whether or not "make dist" parts are enabled. They get enabled
+ # when building from an extension's dir, disabled when building
+ # elsewhere.
+ dist-enabled 1
+ # Whether or not "make install" parts are enabled. By default
+ # they are, but we have a single use case where they're
+ # both unnecessary and unhelpful, so...
+ install-enabled 1
+
+ # By default we enable compilation of a native extension but if the
+ # extension has no native code or the user wants to take that over
+ # via teaish.make.in or provide a script-only extension, we will
+ # elide the default compilation rules if this is 0.
+ dll-enabled 1
+
+ # Files to include in the "make dist" bundle.
+ dist-files {}
+
+ # List of source files for the extension.
+ extension-src {}
+
+ # Path to the teaish.tcl file.
+ teaish.tcl {}
+
+ # Dir where teaish.tcl is found.
+ extension-dir {}
+
+ # Whether the generates TEASH_VSATISFIES_CODE should error out on a
+ # satisfies error. If 0, it uses return instead of error.
+ vsatisfies-error 1
+
+ # Whether or not to allow a "full dist" - a "make dist" build which
+ # includes both the extension and teaish. By default this is only on
+ # if the extension dir is teaish's dir.
+ dist-full-enabled 0
+}]
+set teaish__Config(core-dir) $::autosetup(libdir)/teaish
+
+#
+# Array of info managed by teaish-pkginfo-get and friends. Has the
+# same set of keys as $teaish__Config(pkginfo-f2d).
+#
+array set teaish__PkgInfo {}
+
+#
+# Runs {*}$args if $lvl is <= the current verbosity level, else it has
+# no side effects.
+#
+proc teaish__verbose {lvl args} {
+ if {$lvl <= $::teaish__Config(verbose)} {
+ {*}$args
+ }
+}
+
+#
+# @teaish-argv-has flags...
+#
+# Returns true if any arg in $::argv matches any of the given globs,
+# else returns false.
+#
+proc teaish-argv-has {args} {
+ foreach glob $args {
+ foreach arg $::argv {
+ if {[string match $glob $arg]} {
+ return 1
+ }
+ }
+ }
+ return 0
+}
+
+if {[teaish-argv-has --teaish-verbose --t-v]} {
+ # Check this early so that we can use verbose-only messages in the
+ # pre-options-parsing steps.
+ set ::teaish__Config(verbose) 1
+ #teaish__verbose 1 msg-result "--teaish-verbose activated"
+}
+
+msg-quiet use system ; # Outputs "Host System" and "Build System" lines
+if {"--help" ni $::argv} {
+ teaish__verbose 1 msg-result "TEA(ish) Version = $::teaish__Config(version)"
+ teaish__verbose 1 msg-result "Source dir = $::autosetup(srcdir)"
+ teaish__verbose 1 msg-result "Build dir = $::autosetup(builddir)"
+}
+
+#
+# @teaish-configure-core
+#
+# Main entry point for the TEA-ish configure process. auto.def's primary
+# (ideally only) job should be to call this.
+#
+proc teaish-configure-core {} {
+ proj-tweak-default-env-dirs
+
+ set ::teaish__Config(install-mode) [teaish-argv-has --teaish-install*]
+ set ::teaish__Config(create-ext-mode) \
+ [teaish-argv-has --teaish-create-extension=* --t-c-e=*]
+ set gotExt 0; # True if an extension config is found
+ if {!$::teaish__Config(create-ext-mode)
+ && !$::teaish__Config(install-mode)} {
+ # Don't look for an extension if we're in --t-c-e or --t-i mode
+ set gotExt [teaish__find_extension]
+ }
+
+ #
+ # Set up the core --flags. This needs to come before teaish.tcl is
+ # sourced so that that file can use teaish-pkginfo-set to append
+ # options.
+ #
+ options-add [proj-strip-hash-comments {
+ with-tcl:DIR
+ => {Directory containing tclConfig.sh or a directory one level up from
+ that, from which we can derive a directory containing tclConfig.sh.
+ Defaults to the $TCL_HOME environment variable.}
+
+ with-tclsh:PATH
+ => {Full pathname of tclsh to use. It is used for trying to find
+ tclConfig.sh. Warning: if its containing dir has multiple tclsh
+ versions, it may select the wrong tclConfig.sh!
+ Defaults to the $TCLSH environment variable.}
+
+ # TEA has --with-tclinclude but it appears to only be useful for
+ # building an extension against an uninstalled copy of TCL's own
+ # source tree. The policy here is that either we get that info
+ # from tclConfig.sh or we give up.
+ #
+ # with-tclinclude:DIR
+ # => {Specify the directory which contains the tcl.h. This should not
+ # normally be required, as that information comes from tclConfig.sh.}
+
+ # We _generally_ want to reduce the possibility of flag collisions with
+ # extensions, and thus use a teaish-... prefix on most flags. However,
+ # --teaish-extension-dir is frequently needed, so...
+ #
+ # As of this spontaneous moment, we'll settle on using --t-A-X to
+ # abbreviate --teaish-A...-X... flags when doing so is
+ # unambiguous...
+ ted: t-e-d:
+ teaish-extension-dir:DIR
+ => {Looks for an extension in the given directory instead of the current
+ dir.}
+
+ t-c-e:
+ teaish-create-extension:TARGET_DIRECTORY
+ => {Writes stub files for creating an extension. Will refuse to overwrite
+ existing files without --teaish-force.}
+
+ t-f
+ teaish-force
+ => {Has a context-dependent meaning (autosetup defines --force for its
+ own use).}
+
+ t-d-d
+ teaish-dump-defines
+ => {Dump all configure-defined vars to config.defines.txt}
+
+ t-v:=0
+ teaish-verbose:=0
+ => {Enable more (often extraneous) messages from the teaish core.}
+
+ t-d
+ teaish-debug=0 => {Enable teaish-specific debug output}
+
+ t-i
+ teaish-install:=auto
+ => {Installs a copy of teaish, including autosetup, to the target dir.
+ When used with --teaish-create-extension=DIR, a value of "auto"
+ (no no value) will inherit that directory.}
+
+ #TODO: --teaish-install-extension:=dir as short for
+ # --t-c-e=dir --t-i
+
+ t-e-p:
+ teaish-extension-pkginfo:pkginfo
+ => {For use with --teaish-create-extension. If used, it must be a
+ list of arguments for use with teaish-pkginfo-set, e.g.
+ --teaish-extension-pkginfo="-name Foo -version 2.3"}
+
+ t-v-c
+ teaish-vsatisfies-check=1
+ => {Disable the configure-time "vsatisfies" check on the target tclsh.}
+
+ }]; # main options.
+
+ if {$gotExt} {
+ # We found an extension. Source it...
+ set ttcl $::teaish__Config(teaish.tcl)
+ proj-assert {"" ne [teaish-pkginfo-get -name]}
+ proj-assert {[file exists $ttcl]} \
+ "Expecting to have found teaish.(tcl|config) by now"
+ if {[string match *.tcl $ttcl]} {
+ uplevel 1 {source $::teaish__Config(teaish.tcl)}
+ } else {
+ teaish-pkginfo-set {*}[proj-file-content -trim $ttcl]
+ }
+ unset ttcl
+ # Set up some default values if the extension did not set them.
+ # This must happen _after_ it's sourced but before
+ # teaish-configure is called.
+ array set f2d $::teaish__Config(pkginfo-f2d)
+ foreach {pflag key type val} {
+ - TEAISH_CFLAGS -v ""
+ - TEAISH_LDFLAGS -v ""
+ - TEAISH_MAKEFILE -v ""
+ - TEAISH_MAKEFILE_CODE -v ""
+ - TEAISH_MAKEFILE_IN -v ""
+ - TEAISH_PKGINDEX_TCL -v ""
+ - TEAISH_PKGINDEX_TCL_IN -v ""
+ - TEAISH_PKGINIT_TCL -v ""
+ - TEAISH_PKGINIT_TCL_IN -v ""
+ - TEAISH_PKGINIT_TCL_TAIL -v ""
+ - TEAISH_TEST_TCL -v ""
+ - TEAISH_TEST_TCL_IN -v ""
+
+ -version - -v 0.0.0
+ -name.pkg - -e {set ::teaish__PkgInfo(-name)}
+ -name.dist - -e {set ::teaish__PkgInfo(-name)}
+ -libDir - -e {
+ join [list \
+ $::teaish__PkgInfo(-name.pkg) \
+ $::teaish__PkgInfo(-version)] ""
+ }
+ -loadPrefix - -e {
+ string totitle $::teaish__PkgInfo(-name.pkg)
+ }
+ -vsatisfies - -v {{Tcl 8.5-}}
+ -pkgInit.tcl - -v ""
+ -pkgInit.tcl.in - -v ""
+ -url - -v ""
+ -tm.tcl - -v ""
+ -tm.tcl.in - -v ""
+ } {
+ set isPIFlag [expr {"-" ne $pflag}]
+ if {$isPIFlag} {
+ if {[info exists ::teaish__PkgInfo($pflag)]} {
+ # Was already set - skip it.
+ continue;
+ }
+ proj-assert {{-} eq $key}
+ set key $f2d($pflag)
+ }
+ proj-assert {"" ne $key}
+ set got [get-define $key "<nope>"]
+ if {"<nope>" ne $got} {
+ # Was already set - skip it.
+ continue
+ }
+ switch -exact -- $type {
+ -v {}
+ -e { set val [eval $val] }
+ default { proj-error "Invalid type flag: $type" }
+ }
+ #puts "***** defining default $pflag $key {$val} isPIFlag=$isPIFlag got=$got"
+ define $key $val
+ if {$isPIFlag} {
+ set ::teaish__PkgInfo($pflag) $val
+ }
+ }
+ unset isPIFlag pflag key type val
+ array unset f2d
+ }; # sourcing extension's teaish.tcl
+
+ if {[llength [info proc teaish-options]] > 0} {
+ # Add options defined by teaish-options, which is assumed to be
+ # imported via [teaish-get -teaish-tcl].
+ set o [teaish-options]
+ if {"" ne $o} {
+ options-add $o
+ }
+ }
+ #set opts [proj-options-combine]
+ #lappend opts teaish-debug => {x}; #testing dupe entry handling
+ if {[catch {options {}} msg xopts]} {
+ # Workaround for <https://github.com/msteveb/autosetup/issues/73>
+ # where [options] behaves oddly on _some_ TCL builds when it's
+ # called from deeper than the global scope.
+ dict incr xopts -level
+ return {*}$xopts $msg
+ }
+
+ proj-xfer-options-aliases {
+ t-c-e => teaish-create-extension
+ t-d => teaish-debug
+ t-d-d => teaish-dump-defines
+ ted => teaish-extension-dir
+ t-e-d => teaish-extension-dir
+ t-e-p => teaish-extension-pkginfo
+ t-f => teaish-force
+ t-i => teaish-install
+ t-v => teaish-verbose
+ t-v-c => teaish-vsatisfies-check
+ }
+
+ scan [opt-val teaish-verbose 0] %d ::teaish__Config(verbose)
+ set ::teaish__Config(debug-enabled) [opt-bool teaish-debug]
+
+ set exitEarly 0
+ if {[proj-opt-was-provided teaish-create-extension]} {
+ teaish__create_extension [opt-val teaish-create-extension]
+ incr exitEarly
+ }
+ if {$::teaish__Config(install-mode)} {
+ teaish__install
+ incr exitEarly
+ }
+
+ if {$exitEarly} {
+ file delete -force config.log
+ return
+ }
+ proj-assert {1==$gotExt} "Else we cannot have gotten this far"
+
+ teaish__configure_phase1
+}
+
+
+#
+# Internal config-time debugging output routine. It is not legal to
+# call this from the global scope.
+#
+proc teaish-debug {msg} {
+ if {$::teaish__Config(debug-enabled)} {
+ puts stderr [proj-bold "** DEBUG: \[[proj-scope 1]\]: $msg"]
+ }
+}
+
+#
+# Runs "phase 1" of the configuration, immediately after processing
+# --flags. This is what will import the client-defined teaish.tcl.
+#
+proc teaish__configure_phase1 {} {
+ msg-result \
+ [join [list "Configuring build of Tcl extension" \
+ [proj-bold [teaish-pkginfo-get -name] \
+ [teaish-pkginfo-get -version]] "..."]]
+
+ uplevel 1 {
+ use cc cc-db cc-shared cc-lib; # pkg-config
+ }
+ teaish__check_tcl
+ apply {{} {
+ #
+ # If --prefix or --exec-prefix are _not_ provided, use their
+ # TCL_... counterpart from tclConfig.sh. Caveat: by the time we can
+ # reach this point, autosetup's system.tcl will have already done
+ # some non-trivial amount of work with these to create various
+ # derived values from them, so we temporarily end up with a mishmash
+ # of autotools-compatibility var values. That will be straightened
+ # out in the final stage of the configure script via
+ # [proj-remap-autoconf-dir-vars].
+ #
+ foreach {flag uflag tclVar} {
+ prefix prefix TCL_PREFIX
+ exec-prefix exec_prefix TCL_EXEC_PREFIX
+ } {
+ if {![proj-opt-was-provided $flag]} {
+ if {"exec-prefix" eq $flag} {
+ # If --exec-prefix was not used, ensure that --exec-prefix
+ # derives from the --prefix we may have just redefined.
+ set v {${prefix}}
+ } else {
+ set v [get-define $tclVar "???"]
+ teaish__verbose 1 msg-result "Using \$$tclVar for --$flag=$v"
+ }
+ proj-assert {"???" ne $v} "Expecting teaish__check_tcl to have defined $tclVar"
+ #puts "*** $flag $uflag $tclVar = $v"
+ proj-opt-set $flag $v
+ define $uflag $v
+
+ # ^^^ As of here, all autotools-compatibility vars which derive
+ # from --$flag, e.g. --libdir, still derive from the default
+ # --$flag value which was active when system.tcl was
+ # included. So long as those flags are not explicitly passed to
+ # the configure script, those will be straightened out via
+ # [proj-remap-autoconf-dir-vars].
+ }
+ }
+ }}; # --[exec-]prefix defaults
+ teaish__check_common_bins
+ #
+ # Set up library file names
+ #
+ proj-file-extensions
+ teaish__define_pkginfo_derived *
+
+ teaish-checks-run -pre
+ if {[llength [info proc teaish-configure]] > 0} {
+ # teaish-configure is assumed to be imported via
+ # teaish.tcl
+ teaish-configure
+ }
+ teaish-checks-run -post
+
+ apply {{} {
+ # Set up "vsatisfies" code for pkgIndex.tcl.in,
+ # _teaish.tester.tcl.in, and for a configure-time check. We would
+ # like to put this before [teaish-checks-run -pre] but it's
+ # marginally conceivable that a client may need to dynamically
+ # calculate the vsatisfies and set it via [teaish-configure].
+ set vs [get-define TEAISH_VSATISFIES ""]
+ if {"" eq $vs} return
+ set code {}
+ set n 0
+ # Treat $vs as a list-of-lists {{Tcl 8.5-} {Foo 1.0- -3.0} ...}
+ # and generate Tcl which will run package vsatisfies tests with
+ # that info.
+ foreach pv $vs {
+ set n [llength $pv]
+ if {$n < 2} {
+ proj-error "-vsatisfies: {$pv} appears malformed. Whole list is: $vs"
+ }
+ set pkg [lindex $pv 0]
+ set vcheck {}
+ for {set i 1} {$i < $n} {incr i} {
+ lappend vcheck [lindex $pv $i]
+ }
+ if {[opt-bool teaish-vsatisfies-check]} {
+ set tclsh [get-define TCLSH_CMD]
+ set vsat "package vsatisfies \[ package provide $pkg \] $vcheck"
+ set vputs "puts \[ $vsat \]"
+ #puts "*** vputs = $vputs"
+ scan [exec echo $vputs | $tclsh] %d vvcheck
+ if {![info exists vvcheck] || 0 == $vvcheck} {
+ proj-fatal -up $tclsh "check failed:" $vsat
+ }
+ }
+ if {$::teaish__Config(vsatisfies-error)} {
+ set vunsat \
+ [list error [list Package \
+ $::teaish__PkgInfo(-name) $::teaish__PkgInfo(-version) \
+ requires $pv]]
+ } else {
+ set vunsat return
+ }
+ lappend code \
+ [string trim [subst -nocommands \
+ {if { ![package vsatisfies [package provide $pkg] $vcheck] } {\n $vunsat\n}}]]
+ }; # foreach pv
+ define TEAISH_VSATISFIES_CODE [join $code "\n"]
+ }}; # vsatisfies
+
+ if {[proj-looks-like-windows] || [proj-looks-like-mac]} {
+ # Without this, linking of an extension will not work on Cygwin or
+ # Msys2.
+ msg-result "Using USE_TCL_STUBS for this environment"
+ teaish-cflags-add -DUSE_TCL_STUBS=1
+ }
+
+ #define AS_LIBDIR $::autosetup(libdir)
+ define TEAISH_TESTUTIL_TCL $::teaish__Config(core-dir)/tester.tcl
+
+ apply {{} {
+ #
+ # Ensure we have a pkgIndex.tcl and don't have a stale generated one
+ # when rebuilding for different --with-tcl=... values.
+ #
+ if {!$::teaish__Config(pkgindex-policy)} {
+ proj-error "Cannot determine which pkgIndex.tcl to use"
+ }
+ if {0x300 & $::teaish__Config(pkgindex-policy)} {
+ teaish__verbose 1 msg-result "pkgIndex disabled by -tm.tcl(.in)"
+ } else {
+ set tpi [proj-coalesce \
+ [get-define TEAISH_PKGINDEX_TCL_IN] \
+ [get-define TEAISH_PKGINDEX_TCL]]
+ proj-assert {$tpi ne ""} \
+ "TEAISH_PKGINDEX_TCL should have been set up by now"
+ teaish__verbose 1 msg-result "Using pkgIndex from $tpi"
+ if {0x0f & $::teaish__Config(pkgindex-policy)} {
+ # Don't leave stale pkgIndex.tcl laying around yet don't delete
+ # or overwrite a user-managed static pkgIndex.tcl.
+ file delete -force -- [get-define TEAISH_PKGINDEX_TCL]
+ proj-dot-ins-append [get-define TEAISH_PKGINDEX_TCL_IN]
+ } else {
+ teaish-dist-add [file tail $tpi]
+ }
+ }
+ }}; # $::teaish__Config(pkgindex-policy)
+
+ #
+ # Ensure we clean up TEAISH_PKGINIT_TCL if needed and @-process
+ # TEAISH_PKGINIT_TCL_IN if needed.
+ #
+ if {0x0f & $::teaish__Config(pkginit-policy)} {
+ file delete -force -- [get-define TEAISH_PKGINIT_TCL]
+ proj-dot-ins-append [get-define TEAISH_PKGINIT_TCL_IN]
+ }
+ if {0x0f & $::teaish__Config(tm-policy)} {
+ file delete -force -- [get-define TEAISH_TM_TCL]
+ proj-dot-ins-append [get-define TEAISH_TM_TCL_IN]
+ }
+
+ apply {{} {
+ # Queue up any remaining dot-in files
+ set dotIns [list]
+ foreach d {
+ TEAISH_TESTER_TCL_IN
+ TEAISH_TEST_TCL_IN
+ TEAISH_MAKEFILE_IN
+ } {
+ lappend dotIns [get-define $d ""]
+ }
+ lappend dotIns $::autosetup(srcdir)/Makefile.in; # must be after TEAISH_MAKEFILE_IN
+ foreach f $dotIns {
+ if {"" ne $f} {
+ proj-dot-ins-append $f
+ }
+ }
+ }}
+
+ define TEAISH_DIST_FULL \
+ [expr {
+ $::teaish__Config(dist-enabled)
+ && $::teaish__Config(dist-full-enabled)
+ }]
+
+ define TEAISH_AUTOSETUP_DIR $::teaish__Config(core-dir)
+ define TEAISH_ENABLE_DIST $::teaish__Config(dist-enabled)
+ define TEAISH_ENABLE_INSTALL $::teaish__Config(install-enabled)
+ define TEAISH_ENABLE_DLL $::teaish__Config(dll-enabled)
+ define TEAISH_TCL $::teaish__Config(teaish.tcl)
+
+ define TEAISH_DIST_FILES [join $::teaish__Config(dist-files)]
+ define TEAISH_EXT_DIR [join $::teaish__Config(extension-dir)]
+ define TEAISH_EXT_SRC [join $::teaish__Config(extension-src)]
+ proj-setup-autoreconfig TEAISH_AUTORECONFIG
+ foreach f {
+ TEAISH_CFLAGS
+ TEAISH_LDFLAGS
+ } {
+ # Ensure that any of these lists are flattened
+ define $f [join [get-define $f]]
+ }
+ proj-remap-autoconf-dir-vars
+ set tdefs [teaish__defines_to_list]
+ define TEAISH__DEFINES_MAP $tdefs; # injected into _teaish.tester.tcl
+
+ #
+ # NO [define]s after this point!
+ #
+ proj-dot-ins-process -validate
+ proj-if-opt-truthy teaish-dump-defines {
+ proj-file-write config.defines.txt $tdefs
+ }
+
+}; # teaish__configure_phase1
+
+#
+# Run checks for required binaries.
+#
+proc teaish__check_common_bins {} {
+ if {"" eq [proj-bin-define install]} {
+ proj-warn "Cannot find install binary, so 'make install' will not work."
+ define BIN_INSTALL false
+ }
+ if {"" eq [proj-bin-define zip]} {
+ proj-warn "Cannot find zip, so 'make dist.zip' will not work."
+ }
+ if {"" eq [proj-bin-define tar]} {
+ proj-warn "Cannot find tar, so 'make dist.tgz' will not work."
+ }
+}
+
+#
+# TCL...
+#
+# teaish__check_tcl performs most of the --with-tcl and --with-tclsh
+# handling. Some related bits and pieces are performed before and
+# after that function is called.
+#
+# Important [define]'d vars:
+#
+# - TCLSH_CMD is the path to the canonical tclsh or "".
+#
+# - TCL_CONFIG_SH is the path to tclConfig.sh or "".
+#
+# - TCLLIBDIR is the dir to which the extension library gets
+# - installed.
+#
+proc teaish__check_tcl {} {
+ define TCLSH_CMD false ; # Significant is that it exits with non-0
+ define TCLLIBDIR "" ; # Installation dir for TCL extension lib
+ define TCL_CONFIG_SH ""; # full path to tclConfig.sh
+
+ # Clear out all vars which would harvest from tclConfig.sh so that
+ # the late-config validation of @VARS@ works even if --disable-tcl
+ # is used.
+ proj-tclConfig-sh-to-autosetup ""
+
+ # TODO: better document the steps this is taking.
+ set srcdir $::autosetup(srcdir)
+ msg-result "Checking for a suitable tcl... "
+ set use_tcl 1
+ set withSh [opt-val with-tclsh [proj-get-env TCLSH]]
+ set tclHome [opt-val with-tcl [proj-get-env TCL_HOME]]
+ if {[string match */lib $tclHome]} {
+ # TEA compatibility kludge: its --with-tcl wants the lib
+ # dir containing tclConfig.sh.
+ #proj-warn "Replacing --with-tcl=$tclHome for TEA compatibility"
+ regsub {/lib^} $tclHome "" tclHome
+ msg-result "NOTE: stripped /lib suffix from --with-tcl=$tclHome (a TEA-ism)"
+ }
+ if {0} {
+ # This misinteracts with the $TCL_PREFIX default: it will use the
+ # autosetup-defined --prefix default
+ if {"prefix" eq $tclHome} {
+ set tclHome [get-define prefix]
+ }
+ }
+ teaish-debug "use_tcl ${use_tcl}"
+ teaish-debug "withSh=${withSh}"
+ teaish-debug "tclHome=$tclHome"
+ if {"" eq $withSh && "" eq $tclHome} {
+ # If neither --with-tclsh nor --with-tcl are provided, try to find
+ # a workable tclsh.
+ set withSh [proj-first-bin-of tclsh9.1 tclsh9.0 tclsh8.6 tclsh]
+ teaish-debug "withSh=${withSh}"
+ }
+
+ set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases
+ if {"" ne $withSh} {
+ # --with-tclsh was provided or found above. Validate it and use it
+ # to trump any value passed via --with-tcl=DIR.
+ if {![file-isexec $withSh]} {
+ proj-error "TCL shell $withSh is not executable"
+ } else {
+ define TCLSH_CMD $withSh
+ #msg-result "Using tclsh: $withSh"
+ }
+ if {$doConfigLookup &&
+ [catch {exec $withSh $::autosetup(libdir)/find_tclconfig.tcl} result] == 0} {
+ set tclHome $result
+ }
+ if {"" ne $tclHome && [file isdirectory $tclHome]} {
+ teaish__verbose 1 msg-result "$withSh recommends the tclConfig.sh from $tclHome"
+ } else {
+ proj-warn "$withSh is unable to recommend a tclConfig.sh"
+ set use_tcl 0
+ }
+ }
+ set cfg ""
+ set tclSubdirs {tcl9.1 tcl9.0 tcl8.6 tcl8.5 lib}
+ while {$use_tcl} {
+ if {"" ne $tclHome} {
+ # Ensure that we can find tclConfig.sh under ${tclHome}/...
+ if {$doConfigLookup} {
+ if {[file readable "${tclHome}/tclConfig.sh"]} {
+ set cfg "${tclHome}/tclConfig.sh"
+ } else {
+ foreach i $tclSubdirs {
+ if {[file readable "${tclHome}/$i/tclConfig.sh"]} {
+ set cfg "${tclHome}/$i/tclConfig.sh"
+ break
+ }
+ }
+ }
+ }
+ if {"" eq $cfg} {
+ proj-error "No tclConfig.sh found under ${tclHome}"
+ }
+ } else {
+ # If we have not yet found a tclConfig.sh file, look in $libdir
+ # which is set automatically by autosetup or via the --prefix
+ # command-line option. See
+ # https://sqlite.org/forum/forumpost/e04e693439a22457
+ set libdir [get-define libdir]
+ if {[file readable "${libdir}/tclConfig.sh"]} {
+ set cfg "${libdir}/tclConfig.sh"
+ } else {
+ foreach i $tclSubdirs {
+ if {[file readable "${libdir}/$i/tclConfig.sh"]} {
+ set cfg "${libdir}/$i/tclConfig.sh"
+ break
+ }
+ }
+ }
+ if {![file readable $cfg]} {
+ break
+ }
+ }
+ teaish__verbose 1 msg-result "Using tclConfig.sh = $cfg"
+ break
+ }; # while {$use_tcl}
+ define TCL_CONFIG_SH $cfg
+ # Export a subset of tclConfig.sh to the current TCL-space. If $cfg
+ # is an empty string, this emits empty-string entries for the
+ # various options we're interested in.
+ proj-tclConfig-sh-to-autosetup $cfg
+
+ if {"" eq $withSh && $cfg ne ""} {
+ # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh
+ # based on info from tclConfig.sh.
+ set tclExecPrefix [get-define TCL_EXEC_PREFIX]
+ proj-assert {"" ne $tclExecPrefix}
+ set tryThese [list \
+ $tclExecPrefix/bin/tclsh[get-define TCL_VERSION] \
+ $tclExecPrefix/bin/tclsh ]
+ foreach trySh $tryThese {
+ if {[file-isexec $trySh]} {
+ set withSh $trySh
+ break
+ }
+ }
+ if {![file-isexec $withSh]} {
+ proj-warn "Cannot find a usable tclsh (tried: $tryThese)"
+ }
+ }
+ define TCLSH_CMD $withSh
+ if {$use_tcl} {
+ # Set up the TCLLIBDIR
+ set tcllibdir [get-env TCLLIBDIR ""]
+ set extDirName [teaish-pkginfo-get -libDir]
+ if {"" eq $tcllibdir} {
+ # Attempt to extract TCLLIBDIR from TCL's $auto_path
+ if {"" ne $withSh &&
+ [catch {exec echo "puts stdout \$auto_path" | "$withSh"} result] == 0} {
+ foreach i $result {
+ if {![string match //zip* $i] && [file isdirectory $i]} {
+ # isdirectory actually passes on //zipfs:/..., but those are
+ # useless for our purposes
+ set tcllibdir $i/$extDirName
+ break
+ }
+ }
+ } else {
+ proj-error "Cannot determine TCLLIBDIR."
+ }
+ }
+ define TCLLIBDIR $tcllibdir
+ }; # find TCLLIBDIR
+
+ set gotSh [file-isexec $withSh]
+ set tmdir ""; # first tcl::tm::list entry
+ if {$gotSh} {
+ catch {
+ set tmli [exec echo {puts [tcl::tm::list]} | $withSh]
+ # Reminder: this list contains many names of dirs which do not
+ # exist but are legitimate. If we rely only on an is-dir check,
+ # we can end up not finding any of the many candidates.
+ set firstDir ""
+ foreach d $tmli {
+ if {"" eq $firstDir && ![string match //*:* $d]} {
+ # First non-VFS entry, e.g. not //zipfs:
+ set firstDir $d
+ }
+ if {[file isdirectory $d]} {
+ set tmdir $d
+ break
+ }
+ }
+ if {"" eq $tmdir} {
+ set tmdir $firstDir
+ }
+ }; # find tcl::tm path
+ }
+ define TEAISH_TCL_TM_DIR $tmdir
+
+ # Finally, let's wrap up...
+ if {$gotSh} {
+ teaish__verbose 1 msg-result "Using tclsh = $withSh"
+ if {$cfg ne ""} {
+ define HAVE_TCL 1
+ } else {
+ proj-warn "Found tclsh but no tclConfig.sh."
+ }
+ if {"" eq $tmdir} {
+ proj-warn "Did not find tcl::tm directory."
+ }
+ }
+ show-notices
+ # If TCL is not found: if it was explicitly requested then fail
+ # fatally, else just emit a warning. If we can find the APIs needed
+ # to generate a working JimTCL then that will suffice for build-time
+ # TCL purposes (see: proc sqlite-determine-codegen-tcl).
+ if {!$gotSh} {
+ proj-error "Did not find tclsh"
+ } elseif {"" eq $cfg} {
+ proj-indented-notice -error {
+ Cannot find a usable tclConfig.sh file. Use --with-tcl=DIR to
+ specify a directory near which tclConfig.sh can be found, or
+ --with-tclsh=/path/to/tclsh to allow the tclsh binary to locate
+ its tclConfig.sh, with the caveat that a symlink to tclsh, or
+ wrapper script around it, e.g. ~/bin/tclsh ->
+ $HOME/tcl/9.0/bin/tclsh9.1, may not work because tclsh emits
+ different library paths for the former than the latter.
+ }
+ }
+ msg-result "Using Tcl [get-define TCL_VERSION] from [get-define TCL_PREFIX]."
+ teaish__tcl_platform_quirks
+}; # teaish__check_tcl
+
+#
+# Perform last-minute platform-specific tweaks to account for quirks.
+#
+proc teaish__tcl_platform_quirks {} {
+ define TEAISH_POSTINST_PREREQUIRE ""
+ switch -glob -- [get-define host] {
+ *-haiku {
+ # Haiku's default TCLLIBDIR is "all wrong": it points to a
+ # read-only virtual filesystem mount-point. We bend it back to
+ # fit under $TCL_PACKAGE_PATH here.
+ foreach {k d} {
+ vj TCL_MAJOR_VERSION
+ vn TCL_MINOR_VERSION
+ pp TCL_PACKAGE_PATH
+ ld TCLLIBDIR
+ } {
+ set $k [get-define $d]
+ }
+ if {[string match /packages/* $ld]} {
+ set old $ld
+ set tail [file tail $ld]
+ if {8 == $vj} {
+ set ld "${pp}/tcl${vj}.${vn}/${tail}"
+ } else {
+ proj-assert {9 == $vj}
+ set ld "${pp}/${tail}"
+ }
+ define TCLLIBDIR $ld
+ # [load foo.so], without a directory part, does not work via
+ # automated tests on Haiku (but works when run
+ # manually). Similarly, the post-install [package require ...]
+ # test fails, presumably for a similar reason. We work around
+ # the former in _teaish.tester.tcl.in. We work around the
+ # latter by amending the post-install check's ::auto_path (in
+ # Makefile.in). This code MUST NOT contain any single-quotes.
+ define TEAISH_POSTINST_PREREQUIRE \
+ [join [list set ::auto_path \
+ \[ linsert \$::auto_path 0 $ld \] \; \
+ ]]
+ proj-indented-notice [subst -nocommands -nobackslashes {
+ Haiku users take note: patching target installation dir to match
+ Tcl's home because Haiku's is not writable.
+
+ Original : $old
+ Substitute: $ld
+ }]
+ }
+ }
+ }
+}; # teaish__tcl_platform_quirks
+
+#
+# Searches $::argv and/or the build dir and/or the source dir for
+# teaish.tcl and friends. Fails if it cannot find teaish.tcl or if
+# there are other irreconcilable problems. If it returns 0 then it did
+# not find an extension but the --help flag was seen, in which case
+# that's not an error.
+#
+# This does not _load_ the extension, it primarily locates the files
+# which make up an extension and fills out no small amount of teaish
+# state related to that.
+#
+proc teaish__find_extension {} {
+ proj-assert {!$::teaish__Config(install-mode)}
+ teaish__verbose 1 msg-result "Looking for teaish extension..."
+
+ # Helper for the foreach loop below.
+ set checkTeaishTcl {{mustHave fid dir} {
+ set f [file join $dir $fid]
+ if {[file readable $f]} {
+ file-normalize $f
+ } elseif {$mustHave} {
+ proj-error "Missing required $dir/$fid"
+ }
+ }}
+
+ #
+ # We have to handle some flags manually because the extension must
+ # be loaded before [options] is run (so that the extension can
+ # inject its own options).
+ #
+ set dirBld $::autosetup(builddir); # dir we're configuring under
+ set dirSrc $::autosetup(srcdir); # where teaish's configure script lives
+ set extT ""; # teaish.tcl
+ set largv {}; # rewritten $::argv
+ set gotHelpArg 0; # got the --help
+ foreach arg $::argv {
+ #puts "*** arg=$arg"
+ switch -glob -- $arg {
+ --ted=* -
+ --t-e-d=* -
+ --teaish-extension-dir=* {
+ # Ensure that $extD refers to a directory and contains a
+ # teaish.tcl.
+ regexp -- {--[^=]+=(.+)} $arg - extD
+ set extD [file-normalize $extD]
+ if {![file isdirectory $extD]} {
+ proj-error "--teaish-extension-dir value is not a directory: $extD"
+ }
+ set extT [apply $checkTeaishTcl 0 teaish.config $extD]
+ if {"" eq $extT} {
+ set extT [apply $checkTeaishTcl 1 teaish.tcl $extD]
+ }
+ set ::teaish__Config(extension-dir) $extD
+ }
+ --help {
+ incr gotHelpArg
+ lappend largv $arg
+ }
+ default {
+ lappend largv $arg
+ }
+ }
+ }
+ set ::argv $largv
+
+ set dirExt $::teaish__Config(extension-dir); # dir with the extension
+ #
+ # teaish.tcl is a TCL script which implements various
+ # interfaces described by this framework.
+ #
+ # We use the first one we find in the builddir or srcdir.
+ #
+ if {"" eq $extT} {
+ set flist [list]
+ proj-assert {$dirExt eq ""}
+ lappend flist $dirBld/teaish.tcl $dirBld/teaish.config $dirSrc/teaish.tcl
+ if {![proj-first-file-found extT $flist]} {
+ if {$gotHelpArg} {
+ # Tell teaish-configure-core that the lack of extension is not
+ # an error when --help or --teaish-install is used.
+ return 0;
+ }
+ proj-indented-notice -error "
+Did not find any of: $flist
+
+If you are attempting an out-of-tree build, use
+ --teaish-extension-dir=/path/to/extension"
+ }
+ }
+ if {![file readable $extT]} {
+ proj-error "extension tcl file is not readable: $extT"
+ }
+ set ::teaish__Config(teaish.tcl) $extT
+ set dirExt [file dirname $extT]
+
+ set ::teaish__Config(extension-dir) $dirExt
+ set ::teaish__Config(blddir-is-extdir) [expr {$dirBld eq $dirExt}]
+ set ::teaish__Config(dist-enabled) $::teaish__Config(blddir-is-extdir); # may change later
+ set ::teaish__Config(dist-full-enabled) \
+ [expr {[file-normalize $::autosetup(srcdir)]
+ eq [file-normalize $::teaish__Config(extension-dir)]}]
+
+ set addDist {{file} {
+ teaish-dist-add [file tail $file]
+ }}
+ apply $addDist $extT
+
+ teaish__verbose 1 msg-result "Extension dir = [teaish-get -dir]"
+ teaish__verbose 1 msg-result "Extension config = $extT"
+
+ teaish-pkginfo-set -name [file tail [file dirname $extT]]
+
+ #
+ # teaish.make[.in] provides some of the info for the main makefile,
+ # like which source(s) to build and their build flags.
+ #
+ # We use the first one of teaish.make.in or teaish.make we find in
+ # $dirExt.
+ #
+ if {[proj-first-file-found extM \
+ [list \
+ $dirExt/teaish.make.in \
+ $dirExt/teaish.make \
+ ]]} {
+ if {[string match *.in $extM]} {
+ define TEAISH_MAKEFILE_IN $extM
+ define TEAISH_MAKEFILE [file rootname [file tail $extM]]
+ } else {
+ define TEAISH_MAKEFILE_IN ""
+ define TEAISH_MAKEFILE $extM
+ }
+ apply $addDist $extM
+ teaish__verbose 1 msg-result "Extension makefile = $extM"
+ } else {
+ define TEAISH_MAKEFILE_IN ""
+ define TEAISH_MAKEFILE ""
+ }
+
+ # Look for teaish.pkginit.tcl[.in]
+ set piPolicy 0
+ if {[proj-first-file-found extI \
+ [list \
+ $dirExt/teaish.pkginit.tcl.in \
+ $dirExt/teaish.pkginit.tcl \
+ ]]} {
+ if {[string match *.in $extI]} {
+ # Generate teaish.pkginit.tcl from $extI.
+ define TEAISH_PKGINIT_TCL_IN $extI
+ define TEAISH_PKGINIT_TCL [file rootname [file tail $extI]]
+ set piPolicy 0x01
+ } else {
+ # Assume static $extI.
+ define TEAISH_PKGINIT_TCL_IN ""
+ define TEAISH_PKGINIT_TCL $extI
+ set piPolicy 0x10
+ }
+ apply $addDist $extI
+ teaish__verbose 1 msg-result "Extension post-load init = $extI"
+ define TEAISH_PKGINIT_TCL_TAIL \
+ [file tail [get-define TEAISH_PKGINIT_TCL]]; # for use in pkgIndex.tcl.in
+ }
+ set ::teaish__Config(pkginit-policy) $piPolicy
+
+ # Look for pkgIndex.tcl[.in]...
+ set piPolicy 0
+ if {[proj-first-file-found extPI $dirExt/pkgIndex.tcl.in]} {
+ # Generate ./pkgIndex.tcl from $extPI.
+ define TEAISH_PKGINDEX_TCL_IN $extPI
+ define TEAISH_PKGINDEX_TCL [file rootname [file tail $extPI]]
+ apply $addDist $extPI
+ set piPolicy 0x01
+ } elseif {$dirExt ne $dirSrc
+ && [proj-first-file-found extPI $dirSrc/pkgIndex.tcl.in]} {
+ # Generate ./pkgIndex.tcl from $extPI.
+ define TEAISH_PKGINDEX_TCL_IN $extPI
+ define TEAISH_PKGINDEX_TCL [file rootname [file tail $extPI]]
+ set piPolicy 0x02
+ } elseif {[proj-first-file-found extPI $dirExt/pkgIndex.tcl]} {
+ # Assume $extPI's a static file and use it.
+ define TEAISH_PKGINDEX_TCL_IN ""
+ define TEAISH_PKGINDEX_TCL $extPI
+ apply $addDist $extPI
+ set piPolicy 0x10
+ }
+ # Reminder: we have to delay removal of stale TEAISH_PKGINDEX_TCL
+ # and the proj-dot-ins-append of TEAISH_PKGINDEX_TCL_IN until much
+ # later in the process.
+ set ::teaish__Config(pkgindex-policy) $piPolicy
+
+ # Look for teaish.test.tcl[.in]
+ proj-assert {"" ne $dirExt}
+ set flist [list $dirExt/teaish.test.tcl.in $dirExt/teaish.test.tcl]
+ if {[proj-first-file-found ttt $flist]} {
+ if {[string match *.in $ttt]} {
+ # Generate teaish.test.tcl from $ttt
+ set xt [file rootname [file tail $ttt]]
+ file delete -force -- $xt; # ensure no stale copy is used
+ define TEAISH_TEST_TCL $xt
+ define TEAISH_TEST_TCL_IN $ttt
+ } else {
+ define TEAISH_TEST_TCL $ttt
+ define TEAISH_TEST_TCL_IN ""
+ }
+ apply $addDist $ttt
+ } else {
+ define TEAISH_TEST_TCL ""
+ define TEAISH_TEST_TCL_IN ""
+ }
+
+ # Look for _teaish.tester.tcl[.in]
+ set flist [list $dirExt/_teaish.tester.tcl.in $dirSrc/_teaish.tester.tcl.in]
+ if {[proj-first-file-found ttt $flist]} {
+ # Generate teaish.test.tcl from $ttt
+ set xt [file rootname [file tail $ttt]]
+ file delete -force -- $xt; # ensure no stale copy is used
+ define TEAISH_TESTER_TCL $xt
+ define TEAISH_TESTER_TCL_IN $ttt
+ if {[lindex $flist 0] eq $ttt} {
+ apply $addDist $ttt
+ }
+ unset ttt xt
+ } else {
+ if {[file exists [set ttt [file join $dirSrc _teaish.tester.tcl.in]]]} {
+ set xt [file rootname [file tail $ttt]]
+ define TEAISH_TESTER_TCL $xt
+ define TEAISH_TESTER_TCL_IN $ttt
+ } else {
+ define TEAISH_TESTER_TCL ""
+ define TEAISH_TESTER_TCL_IN ""
+ }
+ }
+ unset flist
+
+ # TEAISH_OUT_OF_EXT_TREE = 1 if we're building from a dir other
+ # than the extension's home dir.
+ define TEAISH_OUT_OF_EXT_TREE \
+ [expr {[file-normalize $::autosetup(builddir)] ne \
+ [file-normalize $::teaish__Config(extension-dir)]}]
+ return 1
+}; # teaish__find_extension
+
+#
+# @teaish-cflags-add ?-p|prepend? ?-define? cflags...
+#
+# Equivalent to [proj-define-amend TEAISH_CFLAGS {*}$args].
+#
+proc teaish-cflags-add {args} {
+ proj-define-amend TEAISH_CFLAGS {*}$args
+}
+
+#
+# @teaish-define-to-cflag ?flags? defineName...|{defineName...}
+#
+# Uses [proj-define-to-cflag] to expand a list of [define] keys, each
+# one a separate argument, to CFLAGS-style -D... form then appends
+# that to the current TEAISH_CFLAGS.
+#
+# It accepts these flags from proj-define-to-cflag: -quote,
+# -zero-undef. It does _not_ support its -list flag.
+#
+# It accepts its non-flag argument(s) in 2 forms: (1) each arg is a
+# single [define] key or (2) its one arg is a list of such keys.
+#
+# TODO: document teaish's well-defined (as it were) defines for this
+# purpose. At a bare minimum:
+#
+# - TEAISH_NAME
+# - TEAISH_PKGNAME
+# - TEAISH_VERSION
+# - TEAISH_LIBDIR_NAME
+# - TEAISH_LOAD_PREFIX
+# - TEAISH_URL
+#
+proc teaish-define-to-cflag {args} {
+ set flags {}
+ while {[string match -* [lindex $args 0]]} {
+ set arg [lindex $args 0]
+ switch -exact -- $arg {
+ -quote -
+ -zero-undef {
+ lappend flags $arg
+ set args [lassign $args -]
+ }
+ default break
+ }
+ }
+ if {1 == [llength $args]} {
+ set args [list {*}[lindex $args 0]]
+ }
+ #puts "***** flags=$flags args=$args"
+ teaish-cflags-add [proj-define-to-cflag {*}$flags {*}$args]
+}
+
+#
+# @teaish-cflags-for-tea ?...CFLAGS?
+#
+# Adds several -DPACKAGE_... CFLAGS using the extension's metadata,
+# all as quoted strings. Those symbolic names are commonly used in
+# TEA-based builds, and this function is intended to simplify porting
+# of such builds. The -D... flags added are:
+#
+# -DPACKAGE_VERSION=...
+# -DPACKAGE_NAME=...
+# -DPACKAGE_URL=...
+# -DPACKAGE_STRING=...
+#
+# Any arguments are passed-on as-is to teaish-cflags-add.
+#
+proc teaish-cflags-for-tea {args} {
+ set name $::teaish__PkgInfo(-name)
+ set version $::teaish__PkgInfo(-version)
+ set pstr [join [list $name $version]]
+ teaish-cflags-add \
+ {*}$args \
+ '-DPACKAGE_VERSION="$version"' \
+ '-DPACKAGE_NAME="$name"' \
+ '-DPACKAGE_STRING="$pstr"' \
+ '-DPACKAGE_URL="[teaish-get -url]"'
+}
+
+#
+# @teaish-ldflags-add ?-p|-prepend? ?-define? ldflags...
+#
+# Equivalent to [proj-define-amend TEAISH_LDFLAGS {*}$args].
+#
+# Typically, -lXYZ flags need to be in "reverse" order, with each -lY
+# resolving symbols for -lX's to its left. This order is largely
+# historical, and not relevant on all environments, but it is
+# technically correct and still relevant on some environments.
+#
+# See: teaish-ldflags-prepend
+#
+proc teaish-ldflags-add {args} {
+ proj-define-amend TEAISH_LDFLAGS {*}$args
+}
+
+#
+# @teaish-ldflags-prepend args...
+#
+# Functionally equivalent to [teaish-ldflags-add -p {*}$args]
+#
+proc teaish-ldflags-prepend {args} {
+ teaish-ldflags-add -p {*}$args
+}
+
+#
+# @teaish-src-add ?-dist? ?-dir? src-files...
+#
+# Appends all non-empty $args to the project's list of C/C++ source or
+# (in some cases) object files.
+#
+# If passed -dist then it also passes each filename, as-is, to
+# [teaish-dist-add].
+#
+# If passed -dir then each src-file has [teaish-get -dir] prepended to
+# it before they're added to the list. As often as not, that will be
+# the desired behavior so that out-of-tree builds can find the
+# sources, but there are cases where it's not desired (e.g. when using
+# a source file from outside of the extension's dir, or when adding
+# object files (which are typically in the build tree)).
+#
+proc teaish-src-add {args} {
+ set i 0
+ proj-parse-simple-flags args flags {
+ -dist 0 {expr 1}
+ -dir 0 {expr 1}
+ }
+ if {$flags(-dist)} {
+ teaish-dist-add {*}$args
+ }
+ if {$flags(-dir)} {
+ set xargs {}
+ foreach arg $args {
+ if {"" ne $arg} {
+ lappend xargs [file join $::teaish__Config(extension-dir) $arg]
+ }
+ }
+ set args $xargs
+ }
+ lappend ::teaish__Config(extension-src) {*}$args
+}
+
+#
+# @teaish-dist-add files-or-dirs...
+#
+# Adds the given files to the list of files to include with the "make
+# dist" rules.
+#
+# This is a no-op when the current build is not in the extension's
+# directory, as dist support is disabled in out-of-tree builds.
+#
+# It is not legal to call this until [teaish-get -dir] has been
+# reliably set (via teaish__find_extension).
+#
+proc teaish-dist-add {args} {
+ if {$::teaish__Config(blddir-is-extdir)} {
+ # ^^^ reminder: we ignore $::teaish__Config(dist-enabled) here
+ # because the client might want to implement their own dist
+ # rules.
+ #proj-warn "**** args=$args"
+ lappend ::teaish__Config(dist-files) {*}$args
+ }
+}
+
+# teaish-install-add files...
+# Equivalent to [proj-define-apend TEAISH_INSTALL_FILES ...].
+#proc teaish-install-add {args} {
+# proj-define-amend TEAISH_INSTALL_FILES {*}$args
+#}
+
+#
+# @teash-make-add args...
+#
+# Appends makefile code to the TEAISH_MAKEFILE_CODE define. Each
+# arg may be any of:
+#
+# -tab: emit a literal tab
+# -nl: emit a literal newline
+# -nltab: short for -nl -tab
+# -bnl: emit a backslash-escaped end-of-line
+# -bnltab: short for -eol -tab
+#
+# Anything else is appended verbatim. This function adds no additional
+# spacing between each argument nor between subsequent invocations.
+# Generally speaking, a series of calls to this function need to
+# be sure to end the series with a newline.
+proc teaish-make-add {args} {
+ set out [get-define TEAISH_MAKEFILE_CODE ""]
+ foreach a $args {
+ switch -exact -- $a {
+ -bnl { set a " \\\n" }
+ -bnltab { set a " \\\n\t" }
+ -tab { set a "\t" }
+ -nl { set a "\n" }
+ -nltab { set a "\n\t" }
+ }
+ append out $a
+ }
+ define TEAISH_MAKEFILE_CODE $out
+}
+
+# Internal helper to generate a clean/distclean rule name
+proc teaish__cleanup_rule {{tgt clean}} {
+ set x [incr ::teaish__Config(teaish__cleanup_rule-counter-${tgt})]
+ return ${tgt}-_${x}_
+}
+
+# @teaish-make-obj objfile srcfile ?...args?
+#
+# Uses teaish-make-add to inject makefile rules for $objfile from
+# $srcfile, which is assumed to be C code which uses libtcl. Unless
+# -recipe is used (see below) it invokes the compiler using the
+# makefile-defined $(CC.tcl) which, in the default Makefile.in
+# template, includes any flags needed for building against the
+# configured Tcl.
+#
+# This always terminates the resulting code with a newline.
+#
+# Any arguments after the 2nd may be flags described below or, if no
+# -recipe is provided, flags for the compiler call.
+#
+# -recipe {...}
+# Uses the trimmed value of {...} as the recipe, prefixing it with
+# a single hard-tab character.
+#
+# -deps {...}
+# List of extra files to list as dependencies of $o. Good luck
+# escaping non-trivial cases properly.
+#
+# -clean
+# Generate cleanup rules as well.
+proc teaish-make-obj {o src args} {
+ set consume 0
+ set clean 0
+ set flag ""
+ array set flags {}
+ set xargs {}
+ foreach arg $args {
+ if {$consume} {
+ set consume 0
+ set flags($flag) $arg
+ continue
+ }
+ switch -exact -- $arg {
+ -clean {incr clean}
+ -recipe -
+ -deps {
+ set flag $arg
+ incr consume
+ }
+ default {
+ lappend xargs $arg
+ }
+ }
+ }
+ teaish-make-add \
+ "# [proj-scope 1] -> [proj-scope] $o $src" -nl \
+ "$o: $src $::teaish__Config(teaish.tcl)"
+ if {[info exists flags(-deps)]} {
+ teaish-make-add " " [join $flags(-deps)]
+ }
+ teaish-make-add -nltab
+ if {[info exists flags(-recipe)]} {
+ teaish-make-add [string trim $flags(-recipe)] -nl
+ } else {
+ teaish-make-add [join [list \$(CC.tcl) -c $src {*}$xargs]] -nl
+ }
+ if {$clean} {
+ set rule [teaish__cleanup_rule]
+ teaish-make-add \
+ "clean: $rule\n$rule:\n\trm -f \"$o\"\n"
+ }
+}
+
+#
+# @teaish-make-clean ?-r? ?-dist? ...files|{...files}
+#
+# Adds makefile rules for cleaning up the given files via the "make
+# clean" or (if -dist is used) "make distclean" makefile rules. The -r
+# flag uses "rm -fr" instead of "rm -f", so be careful with that.
+#
+# The file names are taken literally as arguments to "rm", so they may
+# be shell wildcards to be resolved at cleanup-time. To clean up whole
+# directories, pass the -r flag. Each name gets quoted in
+# double-quotes, so spaces in names should not be a problem (but
+# double-quotes in names will be).
+#
+proc teaish-make-clean {args} {
+ if {1 == [llength $args]} {
+ set args [list {*}[lindex $args 0]]
+ }
+
+ set tgt clean
+ set rmflags "-f"
+ proj-parse-simple-flags args flags {
+ -dist 0 {
+ set tgt distclean
+ }
+ -r 0 {
+ set rmflags "-fr"
+ }
+ }
+ set rule [teaish__cleanup_rule $tgt]
+ teaish-make-add "# [proj-scope 1] -> [proj-scope]: [join $args]\n"
+ teaish-make-add "${rule}:\n\trm ${rmflags}"
+ foreach a $args {
+ teaish-make-add " \"$a\""
+ }
+ teaish-make-add "\n${tgt}: ${rule}\n"
+}
+
+#
+# @teaish-make-config-header filename
+#
+# Invokes autosetup's [make-config-header] and passes it $filename and
+# a relatively generic list of options for controlling which defined
+# symbols get exported. Clients which need more control over the
+# exports can copy/paste/customize this.
+#
+# The exported file is then passed to [proj-touch] because, in
+# practice, that's sometimes necessary to avoid build dependency
+# issues.
+#
+proc teaish-make-config-header {filename} {
+ make-config-header $filename \
+ -none {HAVE_CFLAG_* LDFLAGS_* SH_* TEAISH__* TEAISH_*_CODE} \
+ -auto {SIZEOF_* HAVE_* TEAISH_* TCL_*} \
+ -none *
+ proj-touch $filename; # help avoid frequent unnecessary auto-reconfig
+}
+
+#
+# @teaish-feature-cache-set $key value
+#
+# Sets a feature-check cache entry with the given key.
+# See proj-cache-set for the key's semantics. $key should
+# normally be 0.
+#
+proc teaish-feature-cache-set {key val} {
+ proj-cache-set -key $key -level 1 $val
+}
+
+#
+# @teaish-feature-cache-check key tgtVarName
+#
+# Checks for a feature-check cache entry with the given key.
+# See proj-cache-set for the key's semantics.
+#
+# $key should also almost always be 0 but, due to a tclsh
+# incompatibility in 1 OS, it cannot have a default value unless it's
+# the second argument (but it should be the first one).
+#
+# If the feature-check cache has a matching entry then this function
+# assigns its value to tgtVar and returns 1, else it assigns tgtVar to
+# "" and returns 0.
+#
+# See proj-cache-check for $key's semantics.
+#
+proc teaish-feature-cache-check {key tgtVar} {
+ upvar $tgtVar tgt
+ proj-cache-check -key $key -level 1 tgt
+}
+
+#
+# @teaish-check-cached@ ?flags? msg script...
+#
+# A proxy for feature-test impls which handles caching of a feature
+# flag check on per-function basis, using the calling scope's name as
+# the cache key.
+#
+# It emits [msg-checking $msg]. If $msg is empty then it defaults to
+# the name of the caller's scope. The -nomsg flag suppresses the
+# message for non-cache-hit checks. At the end, it will [msg-result
+# "ok"] [msg-result "no"] unless -nostatus is used, in which case the
+# caller is responsible for emitting at least a newline when it's
+# done. The -msg-0 and -msg-1 flags can be used to change the ok/no
+# text.
+#
+# This function checks for a cache hit before running $script and
+# caching the result. If no hit is found then $script is run in the
+# calling scope and its result value is stored in the cache. This
+# routine will intercept a 'return' from $script.
+#
+# $script may be a command and its arguments, as opposed to a single
+# script block.
+#
+# Flags:
+#
+# -nostatus = do not emit "ok" or "no" at the end. This presumes
+# that either $script will emit at least one newline before
+# returning or the caller will account for it. Because of how this
+# function is typically used, -nostatus is not honored when the
+# response includes a cached result.
+#
+# -quiet = disable output from Autosetup's msg-checking and
+# msg-result for the duration of the $script check. Note that when
+# -quiet is in effect, Autosetup's user-notice can be used to queue
+# up output to appear after the check is done. Also note that
+# -quiet has no effect on _this_ function, only the $script part.
+#
+# -nomsg = do not emit $msg for initial check. Like -nostatus, this
+# flag is not honored when the response includes a cached result
+# because it would otherwise produce no output (which is confusing
+# in this context). This is useful when a check runs several other
+# verbose checks and they emit all the necessary info.
+#
+# -msg-0 and -msg-1 MSG = strings to show when the check has failed
+# resp. passed. Defaults are "no" and "ok". The 0 and 1 refer to the
+# result value from teaish-feature-cache-check.
+#
+# -key cachekey = set the cache context key. Only needs to be
+# explicit when using this function multiple times from a single
+# scope. See proj-cache-check and friends for details on the key
+# name. Its default is the name of the scope which calls this
+# function.
+#
+proc teaish-check-cached {args} {
+ proj-parse-simple-flags args flags {
+ -nostatus 0 {expr 1}
+ -quiet 0 {expr 1}
+ -key => 1
+ -nomsg 0 {expr 1}
+ -msg-0 => no
+ -msg-1 => ok
+ }
+ set args [lassign $args msg]
+ set script [join $args]
+ if {"" eq $msg} {
+ set msg [proj-scope 1]
+ }
+ if {[teaish-feature-cache-check $flags(-key) check]} {
+ #if {0 == $flags(-nomsg)} {
+ msg-checking "${msg} ... (cached) "
+ #}
+ #if {!$flags(-nostatus)} {
+ msg-result $flags(-msg-[expr {0 != ${check}}])
+ #}
+ return $check
+ } else {
+ if {0 == $flags(-nomsg)} {
+ msg-checking "${msg} ... "
+ }
+ if {$flags(-quiet)} {
+ incr ::autosetup(msg-quiet)
+ }
+ set code [catch {uplevel 1 $script} rc xopt]
+ if {$flags(-quiet)} {
+ incr ::autosetup(msg-quiet) -1
+ }
+ #puts "***** cached-check got code=$code rc=$rc"
+ if {$code in {0 2}} {
+ teaish-feature-cache-set 1 $rc
+ if {!$flags(-nostatus)} {
+ msg-result $flags(-msg-[expr {0 != ${rc}}])
+ } else {
+ #show-notices; # causes a phantom newline because we're in a
+ #msg-checking scope, so...
+ if {[info exists ::autosetup(notices)]} {
+ show-notices
+ }
+ }
+ } else {
+ #puts "**** code=$code rc=$rc xopt=$xopt"
+ teaish-feature-cache-set 1 0
+ }
+ #puts "**** code=$code rc=$rc"
+ return {*}$xopt $rc
+ }
+}
+
+#
+# Internal helper for teaish__defs_format_: returns a JSON-ish quoted
+# form of the given string-type values.
+#
+# If $asList is true then the return value is in {$value} form. If
+# $asList is false it only performs the most basic of escaping and
+# the input must not contain any control characters.
+#
+proc teaish__quote_str {asList value} {
+ if {$asList} {
+ return "{${value}}"
+ }
+ return \"[string map [list \\ \\\\ \" \\\"] $value]\"
+}
+
+#
+# Internal helper for teaish__defines_to_list. Expects to be passed
+# a name and the variadic $args which are passed to
+# teaish__defines_to_list.. If it finds a pattern match for the
+# given $name in the various $args, it returns the type flag for that
+# $name, e.g. "-str" or "-bare", else returns an empty string.
+#
+proc teaish__defs_type {name spec} {
+ foreach {type patterns} $spec {
+ foreach pattern $patterns {
+ if {[string match $pattern $name]} {
+ return $type
+ }
+ }
+ }
+ return ""
+}
+
+#
+# An internal impl detail. Requires a data type specifier, as used by
+# Autosetup's [make-config-header], and a value. Returns the formatted
+# value or the value $::teaish__Config(defs-skip) if the caller should
+# skip emitting that value.
+#
+# In addition to -str, -auto, etc., as defined by make-config-header,
+# it supports:
+#
+# -list {...} will cause non-integer values to be quoted in {...}
+# instead of quotes.
+#
+# -autolist {...} works like -auto {...} except that it falls back to
+# -list {...} type instead of -str {...} style for non-integers.
+#
+# -jsarray {...} emits the output in something which, for
+# conservative inputs, will be a valid JSON array. It can only
+# handle relatively simple values with no control characters in
+# them.
+#
+set teaish__Config(defs-skip) "-teaish__defs_format sentinel"
+proc teaish__defs_format {type value} {
+ switch -exact -- $type {
+ -bare {
+ # Just output the value unchanged
+ }
+ -none {
+ set value $::teaish__Config(defs-skip)
+ }
+ -str {
+ set value [teaish__quote_str 0 $value]
+ }
+ -auto {
+ # Automatically determine the type
+ if {![string is integer -strict $value]} {
+ set value [teaish__quote_str 0 $value]
+ }
+ }
+ -autolist {
+ if {![string is integer -strict $value]} {
+ set value [teaish__quote_str 1 $value]
+ }
+ }
+ -list {
+ set value [teaish__quote_str 1 $value]
+ }
+ -jsarray {
+ set ar {}
+ foreach v $value {
+ if {![string is integer -strict $v]} {
+ set v [teaish__quote_str 0 $v]
+ }
+ if {$::teaish__Config(defs-skip) ne $v} {
+ lappend ar $v
+ }
+ }
+ set value [concat \[ [join $ar {, }] \]]
+ }
+ "" {
+ # (Much later:) Why do we do this?
+ set value $::teaish__Config(defs-skip)
+ }
+ default {
+ proj-error \
+ "Unknown [proj-scope] -type ($type) called from" \
+ [proj-scope 1]
+ }
+ }
+ return $value
+}
+
+#
+# Returns Tcl code in the form of code which evaluates to a list of
+# configure-time DEFINEs in the form {key val key2 val...}. It may
+# misbehave for values which are not numeric or simple strings. Some
+# defines are specifically filtered out of the result, either because
+# their irrelevant to teaish or because they may be arbitrarily large
+# (e.g. makefile content).
+#
+# The $args are explained in the docs for internal-use-only
+# [teaish__defs_format]. The default mode is -autolist.
+#
+proc teaish__defines_to_list {args} {
+ set lines {}
+ lappend lines "\{"
+ set skipper $::teaish__Config(defs-skip)
+ set args [list \
+ -none {
+ TEAISH__*
+ TEAISH_*_CODE
+ AM_* AS_*
+ } \
+ {*}$args \
+ -autolist *]
+ foreach d [lsort [dict keys [all-defines]]] {
+ set type [teaish__defs_type $d $args]
+ set value [teaish__defs_format $type [get-define $d]]
+ if {$skipper ne $value} {
+ lappend lines "$d $value"
+ }
+ }
+ lappend lines "\}"
+ tailcall join $lines "\n"
+}
+
+#
+# teaish__pragma ...flags
+#
+# Offers a way to tweak how teaish's core behaves in some cases, in
+# particular those which require changing how the core looks for an
+# extension and its files.
+#
+# Accepts the following flags. Those marked with [L] are safe to use
+# during initial loading of tclish.tcl (recall that most teaish APIs
+# cannot be used until [teaish-configure] is called).
+#
+# static-pkgIndex.tcl [L]: Tells teaish that ./pkgIndex.tcl is not
+# a generated file, so it will not try to overwrite or delete
+# it. Errors out if it does not find pkgIndex.tcl in the
+# extension's dir.
+#
+# no-dist [L]: tells teaish to elide the 'make dist' recipe
+# from the generated Makefile.
+#
+# no-dll [L]: tells teaish to elide the DLL-building recipe
+# from the generated Makefile.
+#
+# no-vsatisfies-error [L]: tells teaish that failure to match the
+# -vsatisfies value should simply "return" instead of "error".
+#
+# no-tester [L]: disables automatic generation of teaish.test.tcl
+# even if a copy of _teaish.tester.tcl.in is found.
+#
+# no-full-dist [L]: changes the "make dist" rules to never include
+# a copy of teaish itself. By default it will include itself only
+# if the extension lives in the same directory as teaish.
+#
+# full-dist [L]: changes the "make dist" rules to always include
+# a copy of teaish itself.
+#
+# Emits a warning message for unknown arguments.
+#
+proc teaish__pragma {args} {
+ foreach arg $args {
+ switch -exact -- $arg {
+
+ static-pkgIndex.tcl {
+ if {$::teaish__Config(tm-policy)} {
+ proj-fatal -up "Cannot use pragma $arg together with -tm.tcl or -tm.tcl.in."
+ }
+ set tpi [file join $::teaish__Config(extension-dir) pkgIndex.tcl]
+ if {[file exists $tpi]} {
+ define TEAISH_PKGINDEX_TCL_IN ""
+ define TEAISH_PKGINDEX_TCL $tpi
+ set ::teaish__Config(pkgindex-policy) 0x20
+ } else {
+ proj-error "pragma $arg: found no package-local pkgIndex.tcl\[.in]"
+ }
+ }
+
+ no-dist {
+ set ::teaish__Config(dist-enabled) 0
+ }
+
+ no-install {
+ set ::teaish__Config(install-enabled) 0
+ }
+
+ full-dist {
+ set ::teaish__Config(dist-full-enabled) 1
+ }
+
+ no-full-dist {
+ set ::teaish__Config(dist-full-enabled) 0
+ }
+
+ no-dll {
+ set ::teaish__Config(dll-enabled) 0
+ }
+
+ no-vsatisfies-error {
+ set ::teaish__Config(vsatisfies-error) 0
+ }
+
+ no-tester {
+ define TEAISH_TESTER_TCL_IN ""
+ define TEAISH_TESTER_TCL ""
+ }
+
+ default {
+ proj-error "Unknown flag: $arg"
+ }
+ }
+ }
+}
+
+#
+# @teaish-pkginfo-set ...flags
+#
+# The way to set up the initial package state. Used like:
+#
+# teaish-pkginfo-set -name foo -version 0.1.2
+#
+# Or:
+#
+# teaish-pkginfo-set ?-vars|-subst? {-name foo -version 0.1.2}
+#
+# The latter may be easier to write for a multi-line invocation.
+#
+# For the second call form, passing the -vars flag tells it to perform
+# a [subst] of (only) variables in the {...} part from the calling
+# scope. The -subst flag will cause it to [subst] the {...} with
+# command substitution as well (but no backslash substitution). When
+# using -subst for string concatenation, e.g. with -libDir
+# foo[get-version-number], be sure to wrap the value in braces:
+# -libDir {foo[get-version-number]}.
+#
+# Each pkginfo flag corresponds to one piece of extension package
+# info. Teaish provides usable default values for all of these flags,
+# but at least the -name and -version should be set by clients.
+# e.g. the default -name is the directory name the extension lives in,
+# which may change (e.g. when building it from a "make dist" bundle).
+#
+# The flags:
+#
+# -name theName: The extension's name. It defaults to the name of the
+# directory containing the extension. (In TEA this would be the
+# PACKAGE_NAME, not to be confused with...)
+#
+# -name.pkg pkg-provide-name: The extension's name for purposes of
+# Tcl_PkgProvide(), [package require], and friends. It defaults to
+# the `-name`, and is normally the same, but some projects (like
+# SQLite) have a different name here than they do in their
+# historical TEA PACKAGE_NAME.
+#
+# -version version: The extension's package version. Defaults to
+# 0.0.0.
+#
+# -libDir dirName: The base name of the directory into which this
+# extension should be installed. It defaults to a concatenation of
+# `-name.pkg` and `-version`.
+#
+# -loadPrefix prefix: For use as the second argument passed to
+# Tcl's `load` command in the package-loading process. It defaults
+# to title-cased `-name.pkg` because Tcl's `load` plugin system
+# expects it in that form.
+#
+# -options {...}: If provided, it must be a list compatible with
+# Autosetup's `options-add` function. These can also be set up via
+# `teaish-options`.
+#
+# -vsatisfies {{...} ...}: Expects a list-of-lists of conditions
+# for Tcl's `package vsatisfies` command: each list entry is a
+# sub-list of `{PkgName Condition...}`. Teaish inserts those
+# checks via its default pkgIndex.tcl.in and _teaish.tester.tcl.in
+# templates to verify that the system's package dependencies meet
+# these requirements. The default value is `{{Tcl 8.5-}}` (recall
+# that it's a list-of-lists), as 8.5 is the minimum Tcl version
+# teaish will run on, but some extensions may require newer
+# versions or dependencies on other packages. As a special case,
+# if `-vsatisfies` is given a single token, e.g. `8.6-`, then it
+# is transformed into `{Tcl $thatToken}`, i.e. it checks the Tcl
+# version which the package is being run with. If given multiple
+# lists, each `package provides` check is run in the given
+# order. Failure to meet a `vsatisfies` condition triggers an
+# error.
+#
+# -url {...}: an optional URL for the extension.
+#
+# -pragmas {...} A list of infrequently-needed lower-level
+# directives which can influence teaish, including:
+#
+# static-pkgIndex.tcl: tells teaish that the client manages their
+# own pkgIndex.tcl, so that teaish won't try to overwrite it
+# using a template.
+#
+# no-dist: tells teaish to elide the "make dist" recipe from the
+# makefile so that the client can implement it.
+#
+# no-dll: tells teaish to elide the makefile rules which build
+# the DLL, as well as any templated test script and pkgIndex.tcl
+# references to them. The intent here is to (A) support
+# client-defined build rules for the DLL and (B) eventually
+# support script-only extensions.
+#
+# Unsupported flags or pragmas will trigger an error.
+#
+# Potential pothole: setting certain state, e.g. -version, after the
+# initial call requires recalculating of some [define]s. Any such
+# changes should be made as early as possible in teaish-configure so
+# that any later use of those [define]s gets recorded properly (not
+# with the old value). This is particularly relevant when it is not
+# possible to determine the -version or -name until teaish-configure
+# has been called, and it's updated dynamically from
+# teaish-configure. Notably:
+#
+# - If -version or -name are updated, -libDir will almost certainly
+# need to be explicitly set along with them.
+#
+# - If -name is updated, -loadPrefix probably needs to be as well.
+#
+proc teaish-pkginfo-set {args} {
+ set doVars 0
+ set doCommands 0
+ set xargs $args
+ set recalc {}
+ foreach arg $args {
+ switch -exact -- $arg {
+ -vars {
+ incr doVars
+ set xargs [lassign $xargs -]
+ }
+ -subst {
+ incr doVars
+ incr doCommands
+ set xargs [lassign $xargs -]
+ }
+ default {
+ break
+ }
+ }
+ }
+ set args $xargs
+ unset xargs
+ if {1 == [llength $args] && [llength [lindex $args 0]] > 1} {
+ # Transform a single {...} arg into the canonical call form
+ set a [list {*}[lindex $args 0]]
+ if {$doVars || $doCommands} {
+ set sflags -nobackslashes
+ if {!$doCommands} {
+ lappend sflags -nocommands
+ }
+ set a [uplevel 1 [list subst {*}$sflags $a]]
+ }
+ set args $a
+ }
+ set sentinel "<nope>"
+ set flagDefs [list]
+ foreach {f d} $::teaish__Config(pkginfo-f2d) {
+ lappend flagDefs $f => $sentinel
+ }
+ proj-parse-simple-flags args flags $flagDefs
+ if {[llength $args]} {
+ proj-error -up "Too many (or unknown) arguments to [proj-scope]: $args"
+ }
+ foreach {f d} $::teaish__Config(pkginfo-f2d) {
+ if {$sentinel eq [set v $flags($f)]} continue
+ switch -exact -- $f {
+
+ -options {
+ proj-assert {"" eq $d}
+ options-add $v
+ }
+
+ -pragmas {
+ teaish__pragma {*}$v
+ }
+
+ -vsatisfies {
+ if {1 == [llength $v] && 1 == [llength [lindex $v 0]]} {
+ # Transform X to {Tcl $X}
+ set v [list [join [list Tcl $v]]]
+ }
+ define $d $v
+ }
+
+ -pkgInit.tcl -
+ -pkgInit.tcl.in {
+ if {0x22 & $::teaish__Config(pkginit-policy)} {
+ proj-fatal "Cannot use -pkgInit.tcl(.in) more than once."
+ }
+ set x [file join $::teaish__Config(extension-dir) $v]
+ set tTail [file tail $v]
+ if {"-pkgInit.tcl.in" eq $f} {
+ # Generate pkginit file X from X.in
+ set pI 0x02
+ set tIn $x
+ set tOut [file rootname $tTail]
+ set other -pkgInit.tcl
+ } else {
+ # Static pkginit file X
+ set pI 0x20
+ set tIn ""
+ set tOut $x
+ set other -pkgInit.tcl.in
+ }
+ set ::teaish__Config(pkginit-policy) $pI
+ set ::teaish__PkgInfo($other) {}
+ define TEAISH_PKGINIT_TCL_IN $tIn
+ define TEAISH_PKGINIT_TCL $tOut
+ define TEAISH_PKGINIT_TCL_TAIL $tTail
+ teaish-dist-add $v
+ set v $x
+ }
+
+ -tm.tcl -
+ -tm.tcl.in {
+ if {0x30 & $::teaish__Config(pkgindex-policy)} {
+ proj-fatal "Cannot use $f together with a pkgIndex.tcl."
+ } elseif {$::teaish__Config(tm-policy)} {
+ proj-fatal "Cannot use -tm.tcl(.in) more than once."
+ }
+ set x [file join $::teaish__Config(extension-dir) $v]
+ if {"-tm.tcl.in" eq $f} {
+ # Generate tm file X from X.in
+ set pT 0x02
+ set pI 0x100
+ set tIn $x
+ set tOut [file rootname [file tail $v]]
+ set other -tm.tcl
+ } else {
+ # Static tm file X
+ set pT 0x20
+ set pI 0x200
+ set tIn ""
+ set tOut $x
+ set other -tm.tcl.in
+ }
+ set ::teaish__Config(pkgindex-policy) $pI
+ set ::teaish__Config(tm-policy) $pT
+ set ::teaish__PkgInfo($other) {}
+ define TEAISH_TM_TCL_IN $tIn
+ define TEAISH_TM_TCL $tOut
+ define TEAISH_PKGINDEX_TCL ""
+ define TEAISH_PKGINDEX_TCL_IN ""
+ define TEAISH_PKGINDEX_TCL_TAIL ""
+ teaish-dist-add $v
+ teaish__pragma no-dll
+ set v $x
+ }
+
+ default {
+ proj-assert {"" ne $d}
+ define $d $v
+ }
+ }
+ set ::teaish__PkgInfo($f) $v
+ if {$f in {-name -version -libDir -loadPrefix}} {
+ lappend recalc $f
+ }
+ }
+ if {"" ne $recalc} {
+ teaish__define_pkginfo_derived $recalc
+ }
+}
+
+#
+# @teaish-pkginfo-get ?arg?
+#
+# If passed no arguments, it returns the extension config info in the
+# same form accepted by teaish-pkginfo-set.
+#
+# If passed one -flagname arg then it returns the value of that config
+# option.
+#
+# Else it treats arg as the name of caller-scoped variable to
+# which this function assigns an array containing the configuration
+# state of this extension, in the same structure accepted by
+# teaish-pkginfo-set. In this case it returns an empty string.
+#
+proc teaish-pkginfo-get {args} {
+ set cases {}
+ set argc [llength $args]
+ set rv {}
+ switch -exact $argc {
+ 0 {
+ # Return a list of (-flag value) pairs
+ lappend cases default {{
+ if {[info exists ::teaish__PkgInfo($flag)]} {
+ lappend rv $flag $::teaish__PkgInfo($flag)
+ } else {
+ lappend rv $flag [get-define $defName]
+ }
+ }}
+ }
+
+ 1 {
+ set arg $args
+ if {[string match -* $arg]} {
+ # Return the corresponding -flag's value
+ lappend cases $arg {{
+ if {[info exists ::teaish__PkgInfo($flag)]} {
+ return $::teaish__PkgInfo($flag)
+ } else {
+ return [get-define $defName]
+ }
+ }}
+ } else {
+ # Populate target with an array of (-flag value).
+ upvar $arg tgt
+ array set tgt {}
+ lappend cases default {{
+ if {[info exists ::teaish__PkgInfo($flag)]} {
+ set tgt($flag) $::teaish__PkgInfo($flag)
+ } else {
+ set tgt($flag) [get-define $defName]
+ }
+ }}
+ }
+ }
+
+ default {
+ proj-error "invalid arg count from [proj-scope 1]"
+ }
+ }
+
+ foreach {flag defName} $::teaish__Config(pkginfo-f2d) {
+ switch -exact -- $flag [join $cases]
+ }
+ if {0 == $argc} { return $rv }
+}
+
+# (Re)set some defines based on pkginfo state. $flags is the list of
+# pkginfo -flags which triggered this, or "*" for the initial call.
+proc teaish__define_pkginfo_derived {flags} {
+ set all [expr {{*} in $flags}]
+ if {$all || "-version" in $flags || "-name" in $flags} {
+ set name $::teaish__PkgInfo(-name) ; # _not_ -name.pkg
+ if {[info exists ::teaish__PkgInfo(-version)]} {
+ set pkgver $::teaish__PkgInfo(-version)
+ set libname "lib"
+ if {[string match *-cygwin [get-define host]]} {
+ set libname cyg
+ }
+ define TEAISH_DLL8_BASENAME $libname$name$pkgver
+ define TEAISH_DLL9_BASENAME ${libname}tcl9$name$pkgver
+ set ext [get-define TARGET_DLLEXT]
+ define TEAISH_DLL8 [get-define TEAISH_DLL8_BASENAME]$ext
+ define TEAISH_DLL9 [get-define TEAISH_DLL9_BASENAME]$ext
+ }
+ }
+ if {$all || "-libDir" in $flags} {
+ if {[info exists ::teaish__PkgInfo(-libDir)]} {
+ define TCLLIBDIR \
+ [file dirname [get-define TCLLIBDIR]]/$::teaish__PkgInfo(-libDir)
+ }
+ }
+}
+
+#
+# @teaish-checks-queue -pre|-post args...
+#
+# Queues one or more arbitrary "feature test" functions to be run when
+# teaish-checks-run is called. $flag must be one of -pre or -post to
+# specify whether the tests should be run before or after
+# teaish-configure is run. Each additional arg is the name of a
+# feature-test proc.
+#
+proc teaish-checks-queue {flag args} {
+ if {$flag ni {-pre -post}} {
+ proj-error "illegal flag: $flag"
+ }
+ lappend ::teaish__Config(queued-checks${flag}) {*}$args
+}
+
+#
+# @teaish-checks-run -pre|-post
+#
+# Runs all feature checks queued using teaish-checks-queue
+# then cleares the queue.
+#
+proc teaish-checks-run {flag} {
+ if {$flag ni {-pre -post}} {
+ proj-error "illegal flag: $flag"
+ }
+ #puts "*** running $flag: $::teaish__Config(queued-checks${flag})"
+ set foo 0
+ foreach f $::teaish__Config(queued-checks${flag}) {
+ if {![teaish-feature-cache-check $f foo]} {
+ set v [$f]
+ teaish-feature-cache-set $f $v
+ }
+ }
+ set ::teaish__Config(queued-checks${flag}) {}
+}
+
+#
+# A general-purpose getter for various teaish state. Requires one
+# flag, which determines its result value. Flags marked with [L] below
+# are safe for using at load-time, before teaish-pkginfo-set is called
+#
+# -dir [L]: returns the extension's directory, which may differ from
+# the teaish core dir or the build dir.
+#
+# -teaish-home [L]: the "home" dir of teaish itself, which may
+# differ from the extension dir or build dir.
+#
+# -build-dir [L]: the build directory (typically the current working
+# -dir).
+#
+# Any of the teaish-pkginfo-get/get flags: returns the same as
+# teaish-pkginfo-get. Not safe for use until teaish-pkginfo-set has
+# been called.
+#
+# Triggers an error if passed an unknown flag.
+#
+proc teaish-get {flag} {
+ #-teaish.tcl {return $::teaish__Config(teaish.tcl)}
+ switch -exact -- $flag {
+ -dir {
+ return $::teaish__Config(extension-dir)
+ }
+ -teaish-home {
+ return $::autosetup(srcdir)
+ }
+ -build-dir {
+ return $::autosetup(builddir)
+ }
+ default {
+ if {[info exists ::teaish__PkgInfo($flag)]} {
+ return $::teaish__PkgInfo($flag)
+ }
+ }
+ }
+ proj-error "Unhandled flag: $flag"
+}
+
+#
+# Handles --teaish-create-extension=TARGET-DIR
+#
+proc teaish__create_extension {dir} {
+ set force [opt-bool teaish-force]
+ if {"" eq $dir} {
+ proj-error "--teaish-create-extension=X requires a directory name."
+ }
+ file mkdir $dir/generic
+ set cwd [pwd]
+ #set dir [file-normalize [file join $cwd $dir]]
+ teaish__verbose 1 msg-result "Created dir $dir"
+ cd $dir
+ if {!$force} {
+ # Ensure that we don't blindly overwrite anything
+ foreach f {
+ generic/teaish.c
+ teaish.tcl
+ teaish.make.in
+ teaish.test.tcl
+ } {
+ if {[file exists $f]} {
+ error "Cowardly refusing to overwrite $dir/$f. Use --teaish-force to overwrite."
+ }
+ }
+ }
+
+ set name [file tail $dir]
+ set pkgName $name
+ set version 0.0.1
+ set loadPrefix [string totitle $pkgName]
+ set content {teaish-pkginfo-set }
+ #puts "0 content=$content"
+ if {[opt-str teaish-extension-pkginfo epi]} {
+ set epi [string trim $epi]
+ if {[string match "*\n*" $epi]} {
+ set epi "{$epi}"
+ } elseif {![string match "{*}" $epi]} {
+ append content "\{" $epi "\}"
+ } else {
+ append content $epi
+ }
+ #puts "2 content=$content\nepi=$epi"
+ } else {
+ append content [subst -nocommands -nobackslashes {{
+ -name ${name}
+ -name.pkg ${pkgName}
+ -name.dist ${pkgName}
+ -version ${version}
+ -loadPrefix $loadPrefix
+ -libDir ${name}${version}
+ -vsatisfies {{Tcl 8.5-}}
+ -url {}
+ -options {}
+ -pragmas {full-dist}
+ }}]
+ #puts "3 content=$content"
+ }
+ #puts "1 content=$content"
+ append content "\n" {
+#proc teaish-options {} {
+ # Return a list and/or use \[options-add\] to add new
+ # configure flags. This is called before teaish's
+ # bootstrapping is finished, so only teaish-*
+ # APIs which are explicitly noted as being safe
+ # early on may be used here. Any autosetup-related
+ # APIs may be used here.
+ #
+ # Return an empty string if there are no options to
+ # add or if they are added using \[options-add\].
+ #
+ # If there are no options to add, this proc need
+ # not be defined.
+#}
+
+# Called by teaish once bootstrapping is complete.
+# This function is responsible for the client-specific
+# parts of the configuration process.
+proc teaish-configure {} {
+ teaish-src-add -dir -dist generic/teaish.c
+ teaish-define-to-cflag -quote TEAISH_PKGNAME TEAISH_VERSION
+
+ # TODO: your code goes here..
+}
+}; # $content
+ proj-file-write teaish.tcl $content
+ teaish__verbose 1 msg-result "Created teaish.tcl"
+
+ set content "# Teaish test script.
+# When this tcl script is invoked via 'make test' it will have loaded
+# the package, run any teaish.pkginit.tcl code, and loaded
+# autosetup/teaish/tester.tcl.
+"
+ proj-file-write teaish.test.tcl $content
+ teaish__verbose 1 msg-result "Created teaish.test.tcl"
+
+ set content [subst -nocommands -nobackslashes {
+#include <tcl.h>
+static int
+${loadPrefix}_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]){
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("this is the ${name} extension", -1));
+ return TCL_OK;
+}
+
+extern int DLLEXPORT ${loadPrefix}_Init(Tcl_Interp *interp){
+ if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
+ return TCL_ERROR;
+ }
+ if (Tcl_PkgProvide(interp, TEAISH_PKGNAME, TEAISH_VERSION) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ Tcl_CreateObjCommand(interp, TEAISH_PKGNAME, ${loadPrefix}_Cmd, NULL, NULL);
+ return TCL_OK;
+}
+}]
+ proj-file-write generic/teaish.c $content
+ teaish__verbose 1 msg-result "Created generic/teaish.c"
+
+ set content "# teaish makefile for the ${name} extension
+# tx.src = \$(tx.dir)/generic/teaish.c
+# tx.LDFLAGS =
+# tx.CFLAGS =
+"
+ proj-file-write teaish.make.in $content
+ teaish__verbose 1 msg-result "Created teaish.make.in"
+
+ msg-result "Created new extension \[$dir\]."
+
+ cd $cwd
+ set ::teaish__Config(install-ext-dir) $dir
+}
+
+#
+# Internal helper for teaish__install
+#
+proc teaish__install_file {f destDir force} {
+ set dest $destDir/[file tail $f]
+ if {[file isdirectory $f]} {
+ file mkdir $dest
+ } elseif {!$force && [file exists $dest]} {
+ array set st1 [file stat $f]
+ array set st2 [file stat $dest]
+ if {($st1(mtime) == $st2(mtime))
+ && ($st1(size) == $st2(size))} {
+ if {[file tail $f] in {
+ pkgIndex.tcl.in
+ _teaish.tester.tcl.in
+ }} {
+ # Assume they're the same. In the scope of the "make dist"
+ # rules, this happens legitimately when an extension with a
+ # copy of teaish installed in the same dir assumes that the
+ # pkgIndex.tcl.in and _teaish.tester.tcl.in belong to the
+ # extension, whereas teaish believes they belong to teaish.
+ # So we end up with dupes of those.
+ return
+ }
+ }
+ proj-error -up "Cowardly refusing to overwrite \[$dest\]." \
+ "Use --teaish-force to enable overwriting."
+ } else {
+ # file copy -force $f $destDir; # loses +x bit
+ #
+ # JimTcl doesn't have [file attribute], so we can't use that here
+ # (in the context of an autosetup configure script).
+ exec cp -p $f $dest
+ }
+}
+
+#
+# Installs a copy of teaish, with autosetup, to $dDest, which defaults
+# to the --teaish-install=X or --teash-create-extension=X dir. Won't
+# overwrite files unless --teaish-force is used.
+#
+proc teaish__install {{dDest ""}} {
+ if {$dDest in {auto ""}} {
+ set dDest [opt-val teaish-install]
+ if {$dDest in {auto ""}} {
+ if {[info exists ::teaish__Config(install-ext-dir)]} {
+ set dDest $::teaish__Config(install-ext-dir)
+ }
+ }
+ }
+ set force [opt-bool teaish-force]
+ if {$dDest in {auto ""}} {
+ proj-error "Cannot determine installation directory."
+ } elseif {!$force && [file exists $dDest/auto.def]} {
+ proj-error \
+ "Target dir looks like it already contains teaish and/or autosetup: $dDest" \
+ "\nUse --teaish-force to overwrite it."
+ }
+
+ set dSrc $::autosetup(srcdir)
+ set dAS $::autosetup(libdir)
+ set dAST $::teaish__Config(core-dir)
+ set dASTF $dAST/feature
+ teaish__verbose 1 msg-result "Installing teaish to \[$dDest\]..."
+ if {$::teaish__Config(verbose)>1} {
+ msg-result "dSrc = $dSrc"
+ msg-result "dAS = $dAS"
+ msg-result "dAST = $dAST"
+ msg-result "dASTF = $dASTF"
+ msg-result "dDest = $dDest"
+ }
+
+ # Dest subdirs...
+ set ddAS $dDest/autosetup
+ set ddAST $ddAS/teaish
+ set ddASTF $ddAST/feature
+ foreach {srcDir destDir} [list \
+ $dAS $ddAS \
+ $dAST $ddAST \
+ $dASTF $ddASTF \
+ ] {
+ teaish__verbose 1 msg-result "Copying files to $destDir..."
+ file mkdir $destDir
+ foreach f [glob -directory $srcDir *] {
+ if {[string match {*~} $f] || [string match "#*#" [file tail $f]]} {
+ # Editor-generated backups and emacs lock files
+ continue
+ }
+ teaish__verbose 2 msg-result "\t$f"
+ teaish__install_file $f $destDir $force
+ }
+ }
+ teaish__verbose 1 msg-result "Copying files to $dDest..."
+ foreach f {
+ auto.def configure Makefile.in pkgIndex.tcl.in
+ _teaish.tester.tcl.in
+ } {
+ teaish__verbose 2 msg-result "\t$f"
+ teaish__install_file $dSrc/$f $dDest $force
+ }
+ set ::teaish__Config(install-self-dir) $dDest
+ msg-result "Teaish $::teaish__Config(version) installed in \[$dDest\]."
+}
diff --git a/contrib/sqlite3/autosetup/teaish/feature.tcl b/contrib/sqlite3/autosetup/teaish/feature.tcl
new file mode 100644
index 000000000000..6c927d1a77e5
--- /dev/null
+++ b/contrib/sqlite3/autosetup/teaish/feature.tcl
@@ -0,0 +1,214 @@
+########################################################################
+# 2025 April 7
+#
+# 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.
+#
+########################################################################
+# ----- @module feature-tests.tcl -----
+# @section TEA-ish collection of feature tests.
+#
+# Functions in this file with a prefix of teaish__ are
+# private/internal APIs. Those with a prefix of teaish- are
+# public APIs.
+
+
+# @teaish-check-libz
+#
+# Checks for zlib.h and the function deflate in libz. If found,
+# prepends -lz to the extension's ldflags and returns 1, else returns
+# 0. It also defines LDFLAGS_LIBZ to the libs flag.
+#
+proc teaish-check-libz {} {
+ teaish-check-cached "Checking for libz" {
+ set rc 0
+ if {[msg-quiet cc-check-includes zlib.h] && [msg-quiet proj-check-function-in-lib deflate z]} {
+ teaish-ldflags-prepend [define LDFLAGS_LIBZ [get-define lib_deflate]]
+ undefine lib_deflate
+ incr rc
+ }
+ expr $rc
+ }
+}
+
+# @teaish-check-librt ?funclist?
+#
+# Checks whether -lrt is needed for any of the given functions. If
+# so, appends -lrt via [teaish-ldflags-prepend] and returns 1, else
+# returns 0. It also defines LDFLAGS_LIBRT to the libs flag or an
+# empty string.
+#
+# Some systems (ex: SunOS) require -lrt in order to use nanosleep.
+#
+proc teaish-check-librt {{funclist {fdatasync nanosleep}}} {
+ teaish-check-cached -nostatus "Checking whether ($funclist) need librt" {
+ define LDFLAGS_LIBRT ""
+ foreach func $funclist {
+ if {[msg-quiet proj-check-function-in-lib $func rt]} {
+ set ldrt [get-define lib_${func}]
+ undefine lib_${func}
+ if {"" ne $ldrt} {
+ teaish-ldflags-prepend -r [define LDFLAGS_LIBRT $ldrt]
+ msg-result $ldrt
+ return 1
+ } else {
+ msg-result "no lib needed"
+ return 1
+ }
+ }
+ }
+ msg-result "not found"
+ return 0
+ }
+}
+
+# @teaish-check-stdint
+#
+# A thin proxy for [cc-with] which checks for <stdint.h> and the
+# various fixed-size int types it declares. It defines HAVE_STDINT_T
+# to 0 or 1 and (if it's 1) defines HAVE_XYZ_T for each XYZ int type
+# to 0 or 1, depending on whether its available.
+proc teaish-check-stdint {} {
+ teaish-check-cached "Checking for stdint.h" {
+ msg-quiet cc-with {-includes stdint.h} \
+ {cc-check-types int8_t int16_t int32_t int64_t intptr_t \
+ uint8_t uint16_t uint32_t uint64_t uintptr_t}
+ }
+}
+
+# @teaish-is-mingw
+#
+# Returns 1 if building for mingw, else 0.
+proc teaish-is-mingw {} {
+ return [expr {
+ [string match *mingw* [get-define host]] &&
+ ![file exists /dev/null]
+ }]
+}
+
+# @teaish-check-libdl
+#
+# Checks for whether dlopen() can be found and whether it requires
+# -ldl for linking. If found, returns 1, defines LDFLAGS_DLOPEN to the
+# linker flags (if any), and passes those flags to
+# teaish-ldflags-prepend. It unconditionally defines HAVE_DLOPEN to 0
+# or 1 (the its return result value).
+proc teaish-check-dlopen {} {
+ teaish-check-cached -nostatus "Checking for dlopen()" {
+ set rc 0
+ set lfl ""
+ if {[cc-with {-includes dlfcn.h} {
+ cctest -link 1 -declare "extern char* dlerror(void);" -code "dlerror();"}]} {
+ msg-result "-ldl not needed"
+ incr rc
+ } elseif {[cc-check-includes dlfcn.h]} {
+ incr rc
+ if {[cc-check-function-in-lib dlopen dl]} {
+ set lfl [get-define lib_dlopen]
+ undefine lib_dlopen
+ msg-result " dlopen() needs $lfl"
+ } else {
+ msg-result " - dlopen() not found in libdl. Assuming dlopen() is built-in."
+ }
+ } else {
+ msg-result "not found"
+ }
+ teaish-ldflags-prepend [define LDFLAGS_DLOPEN $lfl]
+ define HAVE_DLOPEN $rc
+ }
+}
+
+#
+# @teaish-check-libmath
+#
+# Handles the --enable-math flag. Returns 1 if found, else 0.
+# If found, it prepends -lm (if needed) to the linker flags.
+proc teaish-check-libmath {} {
+ teaish-check-cached "Checking for libc math library" {
+ set lfl ""
+ set rc 0
+ if {[msg-quiet proj-check-function-in-lib ceil m]} {
+ incr rc
+ set lfl [get-define lib_ceil]
+ undefine lib_ceil
+ teaish-ldflags-prepend $lfl
+ msg-checking "$lfl "
+ }
+ define LDFLAGS_LIBMATH $lfl
+ expr $rc
+ }
+}
+
+# @teaish-import-features ?-flags? feature-names...
+#
+# For each $name in feature-names... it invokes:
+#
+# use teaish/feature/$name
+#
+# to load TEAISH_AUTOSETUP_DIR/feature/$name.tcl
+#
+# By default, if a proc named teaish-check-${name}-options is defined
+# after sourcing a file, it is called and its result is passed to
+# proj-append-options. This can be suppressed with the -no-options
+# flag.
+#
+# Flags:
+#
+# -no-options: disables the automatic running of
+# teaish-check-NAME-options,
+#
+# -run: if the function teaish-check-NAME exists after importing
+# then it is called. This flag must not be used when calling this
+# function from teaish-options. This trumps both -pre and -post.
+#
+# -pre: if the function teaish-check-NAME exists after importing
+# then it is passed to [teaish-checks-queue -pre].
+#
+# -post: works like -pre but instead uses[teaish-checks-queue -post].
+proc teaish-import-features {args} {
+ set pk ""
+ set doOpt 1
+ proj-parse-simple-flags args flags {
+ -no-options 0 {set doOpt 0}
+ -run 0 {expr 1}
+ -pre 0 {set pk -pre}
+ -post 0 {set pk -post}
+ }
+ #
+ # TODO: never import the same module more than once. The "use"
+ # command is smart enough to not do that but we would need to
+ # remember whether or not any teaish-check-${arg}* procs have been
+ # called before, and skip them.
+ #
+ if {$flags(-run) && "" ne $pk} {
+ proj-error "Cannot use both -run and $pk" \
+ " (called from [proj-scope 1])"
+ }
+
+ foreach arg $args {
+ uplevel "use teaish/feature/$arg"
+ if {$doOpt} {
+ set n "teaish-check-${arg}-options"
+ if {[llength [info proc $n]] > 0} {
+ if {"" ne [set x [$n]]} {
+ options-add $x
+ }
+ }
+ }
+ if {$flags(-run)} {
+ set n "teaish-check-${arg}"
+ if {[llength [info proc $n]] > 0} {
+ uplevel 1 $n
+ }
+ } elseif {"" ne $pk} {
+ set n "teaish-check-${arg}"
+ if {[llength [info proc $n]] > 0} {
+ teaish-checks-queue {*}$pk $n
+ }
+ }
+ }
+}
diff --git a/contrib/sqlite3/autosetup/teaish/tester.tcl b/contrib/sqlite3/autosetup/teaish/tester.tcl
new file mode 100644
index 000000000000..d8b5f7a0e8c2
--- /dev/null
+++ b/contrib/sqlite3/autosetup/teaish/tester.tcl
@@ -0,0 +1,228 @@
+########################################################################
+# 2025 April 5
+#
+# 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.
+#
+########################################################################
+#
+# Helper routines for running tests on teaish extensions
+#
+########################################################################
+# ----- @module teaish/tester.tcl -----
+#
+# @section TEA-ish Testing APIs.
+#
+# Though these are part of the autosup dir hierarchy, they are not
+# intended to be run from autosetup code. Rather, they're for use
+# with/via teaish.tester.tcl and target canonical Tcl only, not JimTcl
+# (which the autosetup pieces do target).
+
+#
+# @test-current-scope ?lvl?
+#
+# Returns the name of the _calling_ proc from ($lvl + 1) levels up the
+# call stack (where the caller's level will be 1 up from _this_
+# call). If $lvl would resolve to global scope "global scope" is
+# returned and if it would be negative then a string indicating such
+# is returned (as opposed to throwing an error).
+#
+proc test-current-scope {{lvl 0}} {
+ #uplevel [expr {$lvl + 1}] {lindex [info level 0] 0}
+ set ilvl [info level]
+ set offset [expr {$ilvl - $lvl - 1}]
+ if { $offset < 0} {
+ return "invalid scope ($offset)"
+ } elseif { $offset == 0} {
+ return "global scope"
+ } else {
+ return [lindex [info level $offset] 0]
+ }
+}
+
+# @test-msg
+#
+# Emits all arugments to stdout.
+#
+proc test-msg {args} {
+ puts "$args"
+}
+
+# @test-warn
+#
+# Emits all arugments to stderr.
+#
+proc test-warn {args} {
+ puts stderr "WARNING: $args"
+}
+
+#
+# @test-error msg
+#
+# Triggers a test-failed error with a string describing the calling
+# scope and the provided message.
+#
+proc test-fail {args} {
+ #puts stderr "ERROR: \[[test-current-scope 1]]: $msg"
+ #exit 1
+ error "FAIL: \[[test-current-scope 1]]: $args"
+}
+
+array set ::test__Counters {}
+array set ::test__Config {
+ verbose-assert 0 verbose-affirm 0
+}
+
+# Internal impl for affirm and assert.
+#
+# $args = ?-v? script {msg-on-fail ""}
+proc test__affert {failMode args} {
+ if {$failMode} {
+ set what assert
+ } else {
+ set what affirm
+ }
+ set verbose $::test__Config(verbose-$what)
+ if {"-v" eq [lindex $args 0]} {
+ lassign $args - script msg
+ if {1 == [llength $args]} {
+ # If -v is the only arg, toggle default verbose mode
+ set ::test__Config(verbose-$what) [expr {!$::test__Config(verbose-$what)}]
+ return
+ }
+ incr verbose
+ } else {
+ lassign $args script msg
+ }
+ incr ::test__Counters($what)
+ if {![uplevel 1 [concat expr [list $script]]]} {
+ if {"" eq $msg} {
+ set msg $script
+ }
+ set txt [join [list $what # $::test__Counters($what) "failed:" $msg]]
+ if {$failMode} {
+ puts stderr $txt
+ exit 1
+ } else {
+ error $txt
+ }
+ } elseif {$verbose} {
+ puts stderr [join [list $what # $::test__Counters($what) "passed:" $script]]
+ }
+}
+
+#
+# @affirm ?-v? script ?msg?
+#
+# Works like a conventional assert method does, but reports failures
+# using [error] instead of [exit]. If -v is used, it reports passing
+# assertions to stderr. $script is evaluated in the caller's scope as
+# an argument to [expr].
+#
+proc affirm {args} {
+ tailcall test__affert 0 {*}$args
+}
+
+#
+# @assert ?-v? script ?msg?
+#
+# Works like [affirm] but exits on error.
+#
+proc assert {args} {
+ tailcall test__affert 1 {*}$args
+}
+
+#
+# @test-assert testId script ?msg?
+#
+# Works like [assert] but emits $testId to stdout first.
+#
+proc test-assert {testId script {msg ""}} {
+ puts "test $testId"
+ tailcall test__affert 1 $script $msg
+}
+
+#
+# @test-expect testId script result
+#
+# Runs $script in the calling scope and compares its result to
+# $result, minus any leading or trailing whitespace. If they differ,
+# it triggers an [assert].
+#
+proc test-expect {testId script result} {
+ puts "test $testId"
+ set x [string trim [uplevel 1 $script]]
+ set result [string trim $result]
+ tailcall test__affert 0 [list $x eq $result] \
+ "\nEXPECTED: <<$result>>\nGOT: <<$x>>"
+}
+
+#
+# @test-catch cmd ?...args?
+#
+# Runs [cmd ...args], repressing any exception except to possibly log
+# the failure. Returns 1 if it caught anything, 0 if it didn't.
+#
+proc test-catch {cmd args} {
+ if {[catch {
+ $cmd {*}$args
+ } rc xopts]} {
+ puts "[test-current-scope] ignoring failure of: $cmd [lindex $args 0]: $rc"
+ return 1
+ }
+ return 0
+}
+
+if {![array exists ::teaish__BuildFlags]} {
+ array set ::teaish__BuildFlags {}
+}
+
+#
+# @teaish-build-flag3 flag tgtVar ?dflt?
+#
+# If the current build has the configure-time flag named $flag set
+# then tgtVar is assigned its value and 1 is returned, else tgtVal is
+# assigned $dflt and 0 is returned.
+#
+# Caveat #1: only valid when called in the context of teaish's default
+# "make test" recipe, e.g. from teaish.test.tcl. It is not valid from
+# a teaish.tcl configure script because (A) the state it relies on
+# doesn't fully exist at that point and (B) that level of the API has
+# more direct access to the build state. This function requires that
+# an external script have populated its internal state, which is
+# normally handled via teaish.tester.tcl.in.
+#
+# Caveat #2: defines in the style of HAVE_FEATURENAME with a value of
+# 0 are, by long-standing configure script conventions, treated as
+# _undefined_ here.
+#
+proc teaish-build-flag3 {flag tgtVar {dflt ""}} {
+ upvar $tgtVar tgt
+ if {[info exists ::teaish__BuildFlags($flag)]} {
+ set tgt $::teaish__BuildFlags($flag)
+ return 1;
+ } elseif {0==[array size ::teaish__BuildFlags]} {
+ test-warn \
+ "\[[test-current-scope]] was called from " \
+ "[test-current-scope 1] without the build flags imported."
+ }
+ set tgt $dflt
+ return 0
+}
+
+#
+# @teaish-build-flag flag ?dflt?
+#
+# Convenience form of teaish-build-flag3 which returns the
+# configure-time-defined value of $flag or "" if it's not defined (or
+# if it's an empty string).
+#
+proc teaish-build-flag {flag {dflt ""}} {
+ set tgt ""
+ teaish-build-flag3 $flag tgt $dflt
+ return $tgt
+}
diff --git a/contrib/sqlite3/compile b/contrib/sqlite3/compile
deleted file mode 100755
index df363c8fbfbc..000000000000
--- a/contrib/sqlite3/compile
+++ /dev/null
@@ -1,348 +0,0 @@
-#! /bin/sh
-# Wrapper for compilers which do not understand '-c -o'.
-
-scriptversion=2018-03-07.03; # UTC
-
-# Copyright (C) 1999-2021 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/contrib/sqlite3/configure b/contrib/sqlite3/configure
index fcab0424fc5a..64b60f8b358f 100755
--- a/contrib/sqlite3/configure
+++ b/contrib/sqlite3/configure
@@ -1,16887 +1,4 @@
-#! /bin/sh
-# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for sqlite 3.46.1.
-#
-# Report bugs to <http://www.sqlite.org>.
-#
-#
-# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
-# Inc.
-#
-#
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-as_nop=:
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else $as_nop
- case `(set -o) 2>/dev/null` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac
-fi
-
-
-
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
-as_nl='
-'
-export as_nl
-IFS=" "" $as_nl"
-
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
-if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
-
-# The user is always right.
-if ${PATH_SEPARATOR+false} :; 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
-
-
-# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
- as_myself=$0
-fi
-if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
- exit 1
-fi
-
-
-# Use a proper internal environment variable to ensure we don't fall
- # into an infinite loop, continuously re-executing ourselves.
- if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
- _as_can_reexec=no; export _as_can_reexec;
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
- fi
- # We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
-if test "x$CONFIG_SHELL" = x; then
- as_bourne_compatible="as_nop=:
-if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '\${1+\"\$@\"}'='\"\$@\"'
- setopt NO_GLOB_SUBST
-else \$as_nop
- case \`(set -o) 2>/dev/null\` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac
-fi
-"
- as_required="as_fn_return () { (exit \$1); }
-as_fn_success () { as_fn_return 0; }
-as_fn_failure () { as_fn_return 1; }
-as_fn_ret_success () { return 0; }
-as_fn_ret_failure () { return 1; }
-
-exitcode=0
-as_fn_success || { exitcode=1; echo as_fn_success failed.; }
-as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
-as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
-as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" )
-then :
-
-else \$as_nop
- exitcode=1; echo positional parameters were not saved.
-fi
-test x\$exitcode = x0 || exit 1
-blah=\$(echo \$(echo blah))
-test x\"\$blah\" = xblah || exit 1
-test -x / || exit 1"
- as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
- as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
- eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
- test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
-
- test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
- ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
- ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
- ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
- PATH=/empty FPATH=/empty; export PATH FPATH
- test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
- || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
-test \$(( 1 + 1 )) = 2 || exit 1"
- if (eval "$as_required") 2>/dev/null
-then :
- as_have_required=yes
-else $as_nop
- as_have_required=no
-fi
- if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
-then :
-
-else $as_nop
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- as_found=:
- case $as_dir in #(
- /*)
- for as_base in sh bash ksh sh5; do
- # Try only shells that exist, to save several forks.
- as_shell=$as_dir$as_base
- if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
- as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
- CONFIG_SHELL=$as_shell as_have_required=yes
- if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
-then :
- break 2
-fi
-fi
- done;;
- esac
- as_found=false
-done
-IFS=$as_save_IFS
-if $as_found
-then :
-
-else $as_nop
- if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
- as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
- CONFIG_SHELL=$SHELL as_have_required=yes
-fi
-fi
-
-
- if test "x$CONFIG_SHELL" != x
-then :
- export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
-fi
-
- if test x$as_have_required = xno
-then :
- printf "%s\n" "$0: This script requires a shell more modern than all"
- printf "%s\n" "$0: the shells that I found on your system."
- if test ${ZSH_VERSION+y} ; then
- printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
- printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
- else
- printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and
-$0: http://www.sqlite.org about your system, including any
-$0: error possibly output before this message. Then install
-$0: a modern shell, or manually run the script under such a
-$0: shell if you do have one."
- fi
- exit 1
-fi
-fi
-fi
-SHELL=${CONFIG_SHELL-/bin/sh}
-export SHELL
-# Unset more variables known to interfere with behavior of common tools.
-CLICOLOR_FORCE= GREP_OPTIONS=
-unset CLICOLOR_FORCE GREP_OPTIONS
-
-## --------------------- ##
-## M4sh Shell Functions. ##
-## --------------------- ##
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
- { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
- return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
- set +e
- as_fn_set_status $1
- exit $1
-} # as_fn_exit
-# as_fn_nop
-# ---------
-# Do nothing but, unlike ":", preserve the value of $?.
-as_fn_nop ()
-{
- return $?
-}
-as_nop=as_fn_nop
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
- case $as_dir in #(
- -*) as_dir=./$as_dir;;
- esac
- test -d "$as_dir" || eval $as_mkdir_p || {
- as_dirs=
- while :; do
- case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
- *) as_qdir=$as_dir;;
- esac
- as_dirs="'$as_qdir' $as_dirs"
- as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_dir" : 'X\(//\)[^/]' \| \
- X"$as_dir" : 'X\(//\)$' \| \
- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- test -d "$as_dir" && break
- done
- test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
-then :
- eval 'as_fn_append ()
- {
- eval $1+=\$2
- }'
-else $as_nop
- as_fn_append ()
- {
- eval $1=\$$1\$2
- }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
-then :
- eval 'as_fn_arith ()
- {
- as_val=$(( $* ))
- }'
-else $as_nop
- as_fn_arith ()
- {
- as_val=`expr "$@" || test $? -eq 1`
- }
-fi # as_fn_arith
-
-# as_fn_nop
-# ---------
-# Do nothing but, unlike ":", preserve the value of $?.
-as_fn_nop ()
-{
- return $?
-}
-as_nop=as_fn_nop
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
- fi
- printf "%s\n" "$as_me: error: $2" >&2
- as_fn_exit $as_status
-} # as_fn_error
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
- test "X`expr 00001 : '.*\(...\)'`" = X001; then
- as_expr=expr
-else
- as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
- as_basename=basename
-else
- as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
- as_dirname=dirname
-else
- as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
- X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{
- s//\1/
- q
- }
- /^X\/\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\/\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-
- as_lineno_1=$LINENO as_lineno_1a=$LINENO
- as_lineno_2=$LINENO as_lineno_2a=$LINENO
- eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
- test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
- # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
- sed -n '
- p
- /[$]LINENO/=
- ' <$as_myself |
- sed '
- s/[$]LINENO.*/&-/
- t lineno
- b
- :lineno
- N
- :loop
- s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
- t loop
- s/-\n.*//
- ' >$as_me.lineno &&
- chmod +x "$as_me.lineno" ||
- { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
-
- # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
- # already done that, so ensure we don't try to do so again and fall
- # in an infinite loop. This has already happened in practice.
- _as_can_reexec=no; export _as_can_reexec
- # Don't try to exec as it changes $[0], causing all sort of problems
- # (the dirname of $[0] is not the place where we might find the
- # original and so on. Autoconf is especially sensitive to this).
- . "./$as_me.lineno"
- # Exit status is that of the last command.
- exit
-}
-
-
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
- case `echo 'xy\c'` in
- *c*) ECHO_T=' ';; # ECHO_T is single tab character.
- xy) ECHO_C='\c';;
- *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
- ECHO_T=' ';;
- esac;;
-*)
- ECHO_N='-n';;
-esac
-
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
-
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
- rm -f conf$$.dir/conf$$.file
-else
- rm -f conf$$.dir
- mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
- if ln -s conf$$.file conf$$ 2>/dev/null; then
- as_ln_s='ln -s'
- # ... but there are two gotchas:
- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
- elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
- else
- as_ln_s='cp -pR'
- fi
-else
- as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-if mkdir -p . 2>/dev/null; then
- as_mkdir_p='mkdir -p "$as_dir"'
-else
- test -d ./-p && rmdir ./-p
- as_mkdir_p=false
-fi
-
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-
-test -n "$DJDIR" || exec 7<&0 </dev/null
-exec 6>&1
-
-# Name of the host.
-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
-# so uname gets run too.
-ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
-
-#
-# Initializations.
-#
-ac_default_prefix=/usr/local
-ac_clean_files=
-ac_config_libobj_dir=.
-LIBOBJS=
-cross_compiling=no
-subdirs=
-MFLAGS=
-MAKEFLAGS=
-
-# Identity of this package.
-PACKAGE_NAME='sqlite'
-PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.46.1'
-PACKAGE_STRING='sqlite 3.46.1'
-PACKAGE_BUGREPORT='http://www.sqlite.org'
-PACKAGE_URL=''
-
-ac_unique_file="sqlite3.c"
-# Factoring default headers for most tests.
-ac_includes_default="\
-#include <stddef.h>
-#ifdef HAVE_STDIO_H
-# include <stdio.h>
-#endif
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif"
-
-ac_header_c_list=
-ac_subst_vars='am__EXEEXT_FALSE
-am__EXEEXT_TRUE
-LTLIBOBJS
-LIBOBJS
-SHELL_CFLAGS
-EXTRA_SHELL_OBJ
-READLINE_LIBS
-BUILD_CFLAGS
-LT_SYS_LIBRARY_PATH
-OTOOL64
-OTOOL
-LIPO
-NMEDIT
-DSYMUTIL
-MANIFEST_TOOL
-RANLIB
-ac_ct_AR
-AR
-DLLTOOL
-OBJDUMP
-LN_S
-NM
-ac_ct_DUMPBIN
-DUMPBIN
-LD
-FGREP
-EGREP
-GREP
-SED
-host_os
-host_vendor
-host_cpu
-host
-build_os
-build_vendor
-build_cpu
-build
-LIBTOOL
-am__fastdepCC_FALSE
-am__fastdepCC_TRUE
-CCDEPMODE
-am__nodep
-AMDEPBACKSLASH
-AMDEP_FALSE
-AMDEP_TRUE
-am__include
-DEPDIR
-OBJEXT
-EXEEXT
-ac_ct_CC
-CPPFLAGS
-LDFLAGS
-CFLAGS
-CC
-AM_BACKSLASH
-AM_DEFAULT_VERBOSITY
-AM_DEFAULT_V
-AM_V
-CSCOPE
-ETAGS
-CTAGS
-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
-target_alias
-host_alias
-build_alias
-LIBS
-ECHO_T
-ECHO_N
-ECHO_C
-DEFS
-mandir
-localedir
-libdir
-psdir
-pdfdir
-dvidir
-htmldir
-infodir
-docdir
-oldincludedir
-includedir
-runstatedir
-localstatedir
-sharedstatedir
-sysconfdir
-datadir
-datarootdir
-libexecdir
-sbindir
-bindir
-program_transform_name
-prefix
-exec_prefix
-PACKAGE_URL
-PACKAGE_BUGREPORT
-PACKAGE_STRING
-PACKAGE_VERSION
-PACKAGE_TARNAME
-PACKAGE_NAME
-PATH_SEPARATOR
-SHELL
-am__quote'
-ac_subst_files=''
-ac_user_opts='
-enable_option_checking
-enable_silent_rules
-enable_largefile
-enable_dependency_tracking
-enable_shared
-enable_static
-with_pic
-enable_fast_install
-with_aix_soname
-with_gnu_ld
-with_sysroot
-enable_libtool_lock
-enable_editline
-enable_readline
-enable_threadsafe
-enable_dynamic_extensions
-enable_math
-enable_fts4
-enable_fts3
-enable_fts5
-enable_rtree
-enable_session
-enable_debug
-enable_static_shell
-'
- ac_precious_vars='build_alias
-host_alias
-target_alias
-CC
-CFLAGS
-LDFLAGS
-LIBS
-CPPFLAGS
-LT_SYS_LIBRARY_PATH'
-
-
-# Initialize some variables set by options.
-ac_init_help=
-ac_init_version=false
-ac_unrecognized_opts=
-ac_unrecognized_sep=
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-cache_file=/dev/null
-exec_prefix=NONE
-no_create=
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-verbose=
-x_includes=NONE
-x_libraries=NONE
-
-# Installation directory options.
-# These are left unexpanded so users can "make install exec_prefix=/foo"
-# and all the variables that are supposed to be based on exec_prefix
-# by default will actually change.
-# Use braces instead of parens because sh, perl, etc. also accept them.
-# (The list follows the same order as the GNU Coding Standards.)
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datarootdir='${prefix}/share'
-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}'
-infodir='${datarootdir}/info'
-htmldir='${docdir}'
-dvidir='${docdir}'
-pdfdir='${docdir}'
-psdir='${docdir}'
-libdir='${exec_prefix}/lib'
-localedir='${datarootdir}/locale'
-mandir='${datarootdir}/man'
-
-ac_prev=
-ac_dashdash=
-for ac_option
-do
- # If the previous option needs an argument, assign it.
- if test -n "$ac_prev"; then
- eval $ac_prev=\$ac_option
- ac_prev=
- continue
- fi
-
- case $ac_option in
- *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
- *=) ac_optarg= ;;
- *) ac_optarg=yes ;;
- esac
-
- case $ac_dashdash$ac_option in
- --)
- ac_dashdash=yes ;;
-
- -bindir | --bindir | --bindi | --bind | --bin | --bi)
- ac_prev=bindir ;;
- -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
- bindir=$ac_optarg ;;
-
- -build | --build | --buil | --bui | --bu)
- ac_prev=build_alias ;;
- -build=* | --build=* | --buil=* | --bui=* | --bu=*)
- build_alias=$ac_optarg ;;
-
- -cache-file | --cache-file | --cache-fil | --cache-fi \
- | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
- ac_prev=cache_file ;;
- -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
- | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
- cache_file=$ac_optarg ;;
-
- --config-cache | -C)
- cache_file=config.cache ;;
-
- -datadir | --datadir | --datadi | --datad)
- ac_prev=datadir ;;
- -datadir=* | --datadir=* | --datadi=* | --datad=*)
- datadir=$ac_optarg ;;
-
- -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
- | --dataroo | --dataro | --datar)
- ac_prev=datarootdir ;;
- -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
- | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
- datarootdir=$ac_optarg ;;
-
- -disable-* | --disable-*)
- ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"enable_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval enable_$ac_useropt=no ;;
-
- -docdir | --docdir | --docdi | --doc | --do)
- ac_prev=docdir ;;
- -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
- docdir=$ac_optarg ;;
-
- -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
- ac_prev=dvidir ;;
- -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
- dvidir=$ac_optarg ;;
-
- -enable-* | --enable-*)
- ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"enable_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval enable_$ac_useropt=\$ac_optarg ;;
-
- -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
- | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
- | --exec | --exe | --ex)
- ac_prev=exec_prefix ;;
- -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
- | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
- | --exec=* | --exe=* | --ex=*)
- exec_prefix=$ac_optarg ;;
-
- -gas | --gas | --ga | --g)
- # Obsolete; use --with-gas.
- with_gas=yes ;;
-
- -help | --help | --hel | --he | -h)
- ac_init_help=long ;;
- -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
- ac_init_help=recursive ;;
- -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
- ac_init_help=short ;;
-
- -host | --host | --hos | --ho)
- ac_prev=host_alias ;;
- -host=* | --host=* | --hos=* | --ho=*)
- host_alias=$ac_optarg ;;
-
- -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
- ac_prev=htmldir ;;
- -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
- | --ht=*)
- htmldir=$ac_optarg ;;
-
- -includedir | --includedir | --includedi | --included | --include \
- | --includ | --inclu | --incl | --inc)
- ac_prev=includedir ;;
- -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
- | --includ=* | --inclu=* | --incl=* | --inc=*)
- includedir=$ac_optarg ;;
-
- -infodir | --infodir | --infodi | --infod | --info | --inf)
- ac_prev=infodir ;;
- -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
- infodir=$ac_optarg ;;
-
- -libdir | --libdir | --libdi | --libd)
- ac_prev=libdir ;;
- -libdir=* | --libdir=* | --libdi=* | --libd=*)
- libdir=$ac_optarg ;;
-
- -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
- | --libexe | --libex | --libe)
- ac_prev=libexecdir ;;
- -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
- | --libexe=* | --libex=* | --libe=*)
- libexecdir=$ac_optarg ;;
-
- -localedir | --localedir | --localedi | --localed | --locale)
- ac_prev=localedir ;;
- -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
- localedir=$ac_optarg ;;
-
- -localstatedir | --localstatedir | --localstatedi | --localstated \
- | --localstate | --localstat | --localsta | --localst | --locals)
- ac_prev=localstatedir ;;
- -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
- | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
- localstatedir=$ac_optarg ;;
-
- -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
- ac_prev=mandir ;;
- -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
- mandir=$ac_optarg ;;
-
- -nfp | --nfp | --nf)
- # Obsolete; use --without-fp.
- with_fp=no ;;
-
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c | -n)
- no_create=yes ;;
-
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
- no_recursion=yes ;;
-
- -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
- | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
- | --oldin | --oldi | --old | --ol | --o)
- ac_prev=oldincludedir ;;
- -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
- | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
- | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
- oldincludedir=$ac_optarg ;;
-
- -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
- ac_prev=prefix ;;
- -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
- prefix=$ac_optarg ;;
-
- -program-prefix | --program-prefix | --program-prefi | --program-pref \
- | --program-pre | --program-pr | --program-p)
- ac_prev=program_prefix ;;
- -program-prefix=* | --program-prefix=* | --program-prefi=* \
- | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
- program_prefix=$ac_optarg ;;
-
- -program-suffix | --program-suffix | --program-suffi | --program-suff \
- | --program-suf | --program-su | --program-s)
- ac_prev=program_suffix ;;
- -program-suffix=* | --program-suffix=* | --program-suffi=* \
- | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
- program_suffix=$ac_optarg ;;
-
- -program-transform-name | --program-transform-name \
- | --program-transform-nam | --program-transform-na \
- | --program-transform-n | --program-transform- \
- | --program-transform | --program-transfor \
- | --program-transfo | --program-transf \
- | --program-trans | --program-tran \
- | --progr-tra | --program-tr | --program-t)
- ac_prev=program_transform_name ;;
- -program-transform-name=* | --program-transform-name=* \
- | --program-transform-nam=* | --program-transform-na=* \
- | --program-transform-n=* | --program-transform-=* \
- | --program-transform=* | --program-transfor=* \
- | --program-transfo=* | --program-transf=* \
- | --program-trans=* | --program-tran=* \
- | --progr-tra=* | --program-tr=* | --program-t=*)
- program_transform_name=$ac_optarg ;;
-
- -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
- ac_prev=pdfdir ;;
- -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
- pdfdir=$ac_optarg ;;
-
- -psdir | --psdir | --psdi | --psd | --ps)
- ac_prev=psdir ;;
- -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
- psdir=$ac_optarg ;;
-
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -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=* \
- | --sbi=* | --sb=*)
- sbindir=$ac_optarg ;;
-
- -sharedstatedir | --sharedstatedir | --sharedstatedi \
- | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
- | --sharedst | --shareds | --shared | --share | --shar \
- | --sha | --sh)
- ac_prev=sharedstatedir ;;
- -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
- | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
- | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
- | --sha=* | --sh=*)
- sharedstatedir=$ac_optarg ;;
-
- -site | --site | --sit)
- ac_prev=site ;;
- -site=* | --site=* | --sit=*)
- site=$ac_optarg ;;
-
- -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
- ac_prev=srcdir ;;
- -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
- srcdir=$ac_optarg ;;
-
- -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
- | --syscon | --sysco | --sysc | --sys | --sy)
- ac_prev=sysconfdir ;;
- -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
- | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
- sysconfdir=$ac_optarg ;;
-
- -target | --target | --targe | --targ | --tar | --ta | --t)
- ac_prev=target_alias ;;
- -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
- target_alias=$ac_optarg ;;
-
- -v | -verbose | --verbose | --verbos | --verbo | --verb)
- verbose=yes ;;
-
- -version | --version | --versio | --versi | --vers | -V)
- ac_init_version=: ;;
-
- -with-* | --with-*)
- ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"with_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval with_$ac_useropt=\$ac_optarg ;;
-
- -without-* | --without-*)
- ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"with_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval with_$ac_useropt=no ;;
-
- --x)
- # Obsolete; use --with-x.
- with_x=yes ;;
-
- -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
- | --x-incl | --x-inc | --x-in | --x-i)
- ac_prev=x_includes ;;
- -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
- | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
- x_includes=$ac_optarg ;;
-
- -x-libraries | --x-libraries | --x-librarie | --x-librari \
- | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
- ac_prev=x_libraries ;;
- -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
- | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
- x_libraries=$ac_optarg ;;
-
- -*) as_fn_error $? "unrecognized option: \`$ac_option'
-Try \`$0 --help' for more information"
- ;;
-
- *=*)
- ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
- # Reject names that are not valid shell variable names.
- case $ac_envvar in #(
- '' | [0-9]* | *[!_$as_cr_alnum]* )
- as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
- esac
- eval $ac_envvar=\$ac_optarg
- export $ac_envvar ;;
-
- *)
- # FIXME: should be removed in autoconf 3.0.
- printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2
- expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
- printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2
- : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
- ;;
-
- esac
-done
-
-if test -n "$ac_prev"; then
- ac_option=--`echo $ac_prev | sed 's/_/-/g'`
- as_fn_error $? "missing argument to $ac_option"
-fi
-
-if test -n "$ac_unrecognized_opts"; then
- case $enable_option_checking in
- no) ;;
- fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
- *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
- esac
-fi
-
-# Check all directory arguments for consistency.
-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 runstatedir
-do
- eval ac_val=\$$ac_var
- # Remove trailing slashes.
- case $ac_val in
- */ )
- ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
- eval $ac_var=\$ac_val;;
- esac
- # Be sure to have absolute directory names.
- case $ac_val in
- [\\/$]* | ?:[\\/]* ) continue;;
- NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
- esac
- as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
-done
-
-# There might be people who depend on the old broken behavior: `$host'
-# used to hold the argument of --host etc.
-# FIXME: To remove some day.
-build=$build_alias
-host=$host_alias
-target=$target_alias
-
-# FIXME: To remove some day.
-if test "x$host_alias" != x; then
- if test "x$build_alias" = x; then
- cross_compiling=maybe
- elif test "x$build_alias" != "x$host_alias"; then
- cross_compiling=yes
- fi
-fi
-
-ac_tool_prefix=
-test -n "$host_alias" && ac_tool_prefix=$host_alias-
-
-test "$silent" = yes && exec 6>/dev/null
-
-
-ac_pwd=`pwd` && test -n "$ac_pwd" &&
-ac_ls_di=`ls -di .` &&
-ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
- as_fn_error $? "working directory cannot be determined"
-test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
- as_fn_error $? "pwd does not report name of working directory"
-
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
- ac_srcdir_defaulted=yes
- # Try the directory containing this script, then the parent directory.
- ac_confdir=`$as_dirname -- "$as_myself" ||
-$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_myself" : 'X\(//\)[^/]' \| \
- X"$as_myself" : 'X\(//\)$' \| \
- X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_myself" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- srcdir=$ac_confdir
- if test ! -r "$srcdir/$ac_unique_file"; then
- srcdir=..
- fi
-else
- ac_srcdir_defaulted=no
-fi
-if test ! -r "$srcdir/$ac_unique_file"; then
- test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
- as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
-fi
-ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
-ac_abs_confdir=`(
- cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
- pwd)`
-# When building in place, set srcdir=.
-if test "$ac_abs_confdir" = "$ac_pwd"; then
- srcdir=.
-fi
-# Remove unnecessary trailing slashes from srcdir.
-# Double slashes in file names in object file debugging info
-# mess up M-x gdb in Emacs.
-case $srcdir in
-*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
-esac
-for ac_var in $ac_precious_vars; do
- eval ac_env_${ac_var}_set=\${${ac_var}+set}
- eval ac_env_${ac_var}_value=\$${ac_var}
- eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
- eval ac_cv_env_${ac_var}_value=\$${ac_var}
-done
-
-#
-# Report the --help message.
-#
-if test "$ac_init_help" = "long"; then
- # Omit some internal or obsolete options to make the list less imposing.
- # This message is too long to be a string in the A/UX 3.1 sh.
- cat <<_ACEOF
-\`configure' configures sqlite 3.46.1 to adapt to many kinds of systems.
-
-Usage: $0 [OPTION]... [VAR=VALUE]...
-
-To assign environment variables (e.g., CC, CFLAGS...), specify them as
-VAR=VALUE. See below for descriptions of some of the useful variables.
-
-Defaults for the options are specified in brackets.
-
-Configuration:
- -h, --help display this help and exit
- --help=short display options specific to this package
- --help=recursive display the short help of all the included packages
- -V, --version display version information and exit
- -q, --quiet, --silent do not print \`checking ...' messages
- --cache-file=FILE cache test results in FILE [disabled]
- -C, --config-cache alias for \`--cache-file=config.cache'
- -n, --no-create do not create output files
- --srcdir=DIR find the sources in DIR [configure dir or \`..']
-
-Installation directories:
- --prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
- --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
-
-By default, \`make install' will install all the files in
-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
-an installation prefix other than \`$ac_default_prefix' using \`--prefix',
-for instance \`--prefix=\$HOME'.
-
-For better control, use the options below.
-
-Fine tuning of the installation directories:
- --bindir=DIR user executables [EPREFIX/bin]
- --sbindir=DIR system admin executables [EPREFIX/sbin]
- --libexecdir=DIR program executables [EPREFIX/libexec]
- --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]
- --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
- --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
- --infodir=DIR info documentation [DATAROOTDIR/info]
- --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
- --mandir=DIR man documentation [DATAROOTDIR/man]
- --docdir=DIR documentation root [DATAROOTDIR/doc/sqlite]
- --htmldir=DIR html documentation [DOCDIR]
- --dvidir=DIR dvi documentation [DOCDIR]
- --pdfdir=DIR pdf documentation [DOCDIR]
- --psdir=DIR ps documentation [DOCDIR]
-_ACEOF
-
- cat <<\_ACEOF
-
-Program names:
- --program-prefix=PREFIX prepend PREFIX to installed program names
- --program-suffix=SUFFIX append SUFFIX to installed program names
- --program-transform-name=PROGRAM run sed PROGRAM on installed program names
-
-System types:
- --build=BUILD configure for building on BUILD [guessed]
- --host=HOST cross-compile to build programs to run on HOST [BUILD]
-_ACEOF
-fi
-
-if test -n "$ac_init_help"; then
- case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.46.1:";;
- esac
- cat <<\_ACEOF
-
-Optional Features:
- --disable-option-checking ignore unrecognized --enable/--with options
- --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
- --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
- --enable-silent-rules less verbose build output (undo: "make V=1")
- --disable-silent-rules verbose build output (undo: "make V=0")
- --disable-largefile omit support for large files
- --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-editline use BSD libedit
- --enable-readline use readline
- --enable-threadsafe build a thread-safe library [default=yes]
- --enable-dynamic-extensions
- support loadable extensions [default=yes]
- --enable-math SQL math functions [default=yes]
- --enable-fts4 include fts4 support [default=yes]
- --enable-fts3 include fts3 support [default=no]
- --enable-fts5 include fts5 support [default=yes]
- --enable-rtree include rtree support [default=yes]
- --enable-session enable the session extension [default=no]
- --enable-debug build with debugging features enabled [default=no]
- --enable-static-shell statically link libsqlite3 into shell tool
- [default=yes]
-
-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).
-
-Some influential environment variables:
- CC C compiler command
- CFLAGS C compiler flags
- LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
- LIBS libraries to pass to the linker, e.g. -l<library>
- CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
- LT_SYS_LIBRARY_PATH
- User-defined run-time library search path.
-
-Use these variables to override the choices made by `configure' or to help
-it to find libraries and programs with nonstandard names/locations.
-
-Report bugs to <http://www.sqlite.org>.
-_ACEOF
-ac_status=$?
-fi
-
-if test "$ac_init_help" = "recursive"; then
- # If there are subdirs, report their specific --help.
- for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
- test -d "$ac_dir" ||
- { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
- continue
- ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
- # A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
- case $ac_top_builddir_sub in
- "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
- esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
- .) # We are building in place.
- ac_srcdir=.
- ac_top_srcdir=$ac_top_builddir_sub
- ac_abs_top_srcdir=$ac_pwd ;;
- [\\/]* | ?:[\\/]* ) # Absolute name.
- ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir
- ac_abs_top_srcdir=$srcdir ;;
- *) # Relative name.
- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_build_prefix$srcdir
- ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
- cd "$ac_dir" || { ac_status=$?; continue; }
- # Check for configure.gnu first; this name is used for a wrapper for
- # Metaconfig's "Configure" on case-insensitive file systems.
- if test -f "$ac_srcdir/configure.gnu"; then
- echo &&
- $SHELL "$ac_srcdir/configure.gnu" --help=recursive
- elif test -f "$ac_srcdir/configure"; then
- echo &&
- $SHELL "$ac_srcdir/configure" --help=recursive
- else
- printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2
- fi || ac_status=$?
- cd "$ac_pwd" || { ac_status=$?; break; }
- done
-fi
-
-test -n "$ac_init_help" && exit $ac_status
-if $ac_init_version; then
- cat <<\_ACEOF
-sqlite configure 3.46.1
-generated by GNU Autoconf 2.71
-
-Copyright (C) 2021 Free Software Foundation, Inc.
-This configure script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it.
-_ACEOF
- exit
-fi
-
-## ------------------------ ##
-## Autoconf initialization. ##
-## ------------------------ ##
-
-# ac_fn_c_try_compile LINENO
-# --------------------------
-# Try to compile conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_compile ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest.beam
- if { { ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compile") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest.$ac_objext
-then :
- ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1
-fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_compile
-
-# ac_fn_c_try_link LINENO
-# -----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_link ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest$ac_exeext && {
- test "$cross_compiling" = yes ||
- test -x conftest$ac_exeext
- }
-then :
- ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1
-fi
- # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
- # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
- # interfere with the next link command; also delete a directory that is
- # left behind by Apple's compiler. We do this before executing the actions.
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_link
-
-# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists and can be compiled using the include files in
-# INCLUDES, setting the cache variable VAR accordingly.
-ac_fn_c_check_header_compile ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- eval "$3=yes"
-else $as_nop
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_compile
-
-# ac_fn_c_check_func LINENO FUNC VAR
-# ----------------------------------
-# Tests whether FUNC exists, setting the cache variable VAR accordingly
-ac_fn_c_check_func ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
- For example, HP-UX 11i <limits.h> declares gettimeofday. */
-#define $2 innocuous_$2
-
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $2 (); below. */
-
-#include <limits.h>
-#undef $2
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $2 ();
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined __stub_$2 || defined __stub___$2
-choke me
-#endif
-
-int
-main (void)
-{
-return $2 ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- eval "$3=yes"
-else $as_nop
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_func
-
-# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR
-# ------------------------------------------------------------------
-# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
-# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR.
-ac_fn_check_decl ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- as_decl_name=`echo $2|sed 's/ *(.*//'`
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
-printf %s "checking whether $as_decl_name is declared... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
- eval ac_save_FLAGS=\$$6
- as_fn_append $6 " $5"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main (void)
-{
-#ifndef $as_decl_name
-#ifdef __cplusplus
- (void) $as_decl_use;
-#else
- (void) $as_decl_name;
-#endif
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- eval "$3=yes"
-else $as_nop
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- eval $6=\$ac_save_FLAGS
-
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_check_decl
-ac_configure_args_raw=
-for ac_arg
-do
- case $ac_arg in
- *\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- as_fn_append ac_configure_args_raw " '$ac_arg'"
-done
-
-case $ac_configure_args_raw in
- *$as_nl*)
- ac_safe_unquote= ;;
- *)
- ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab.
- ac_unsafe_a="$ac_unsafe_z#~"
- ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g"
- ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
-esac
-
-cat >config.log <<_ACEOF
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-
-It was created by sqlite $as_me 3.46.1, which was
-generated by GNU Autoconf 2.71. Invocation command line was
-
- $ $0$ac_configure_args_raw
-
-_ACEOF
-exec 5>>config.log
-{
-cat <<_ASUNAME
-## --------- ##
-## Platform. ##
-## --------- ##
-
-hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
-
-/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
-/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
-/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
-
-_ASUNAME
-
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- printf "%s\n" "PATH: $as_dir"
- done
-IFS=$as_save_IFS
-
-} >&5
-
-cat >&5 <<_ACEOF
-
-
-## ----------- ##
-## Core tests. ##
-## ----------- ##
-
-_ACEOF
-
-
-# Keep a trace of the command line.
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Strip out --silent because we don't want to record it for future runs.
-# Also quote any args containing shell meta-characters.
-# Make two passes to allow for proper duplicate-argument suppression.
-ac_configure_args=
-ac_configure_args0=
-ac_configure_args1=
-ac_must_keep_next=false
-for ac_pass in 1 2
-do
- for ac_arg
- do
- case $ac_arg in
- -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil)
- continue ;;
- *\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- case $ac_pass in
- 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
- 2)
- as_fn_append ac_configure_args1 " '$ac_arg'"
- if test $ac_must_keep_next = true; then
- ac_must_keep_next=false # Got value, back to normal.
- else
- case $ac_arg in
- *=* | --config-cache | -C | -disable-* | --disable-* \
- | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
- | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
- | -with-* | --with-* | -without-* | --without-* | --x)
- case "$ac_configure_args0 " in
- "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
- esac
- ;;
- -* ) ac_must_keep_next=true ;;
- esac
- fi
- as_fn_append ac_configure_args " '$ac_arg'"
- ;;
- esac
- done
-done
-{ ac_configure_args0=; unset ac_configure_args0;}
-{ ac_configure_args1=; unset ac_configure_args1;}
-
-# When interrupted or exit'd, cleanup temporary files, and complete
-# config.log. We remove comments because anyway the quotes in there
-# would cause problems or look ugly.
-# WARNING: Use '\'' to represent an apostrophe within the trap.
-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
-trap 'exit_status=$?
- # Sanitize IFS.
- IFS=" "" $as_nl"
- # Save into config.log some information that might help in debugging.
- {
- echo
-
- printf "%s\n" "## ---------------- ##
-## Cache variables. ##
-## ---------------- ##"
- echo
- # The following way of writing the cache mishandles newlines in values,
-(
- for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
- eval ac_val=\$$ac_var
- case $ac_val in #(
- *${as_nl}*)
- case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
- esac
- case $ac_var in #(
- _ | IFS | as_nl) ;; #(
- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
- *) { eval $ac_var=; unset $ac_var;} ;;
- esac ;;
- esac
- done
- (set) 2>&1 |
- case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
- *${as_nl}ac_space=\ *)
- sed -n \
- "s/'\''/'\''\\\\'\'''\''/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
- ;; #(
- *)
- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
- ;;
- esac |
- sort
-)
- echo
-
- printf "%s\n" "## ----------------- ##
-## Output variables. ##
-## ----------------- ##"
- echo
- for ac_var in $ac_subst_vars
- do
- eval ac_val=\$$ac_var
- case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
- esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
- done | sort
- echo
-
- if test -n "$ac_subst_files"; then
- printf "%s\n" "## ------------------- ##
-## File substitutions. ##
-## ------------------- ##"
- echo
- for ac_var in $ac_subst_files
- do
- eval ac_val=\$$ac_var
- case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
- esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
- done | sort
- echo
- fi
-
- if test -s confdefs.h; then
- printf "%s\n" "## ----------- ##
-## confdefs.h. ##
-## ----------- ##"
- echo
- cat confdefs.h
- echo
- fi
- test "$ac_signal" != 0 &&
- printf "%s\n" "$as_me: caught signal $ac_signal"
- printf "%s\n" "$as_me: exit $exit_status"
- } >&5
- rm -f core *.core core.conftest.* &&
- rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
- exit $exit_status
-' 0
-for ac_signal in 1 2 13 15; do
- trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
-done
-ac_signal=0
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -f -r conftest* confdefs.h
-
-printf "%s\n" "/* confdefs.h */" > confdefs.h
-
-# Predefined preprocessor variables.
-
-printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h
-
-
-# Let the site file select an alternate cache file if it wants to.
-# Prefer an explicitly selected file to automatically selected ones.
-if test -n "$CONFIG_SITE"; then
- ac_site_files="$CONFIG_SITE"
-elif test "x$prefix" != xNONE; then
- ac_site_files="$prefix/share/config.site $prefix/etc/config.site"
-else
- ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
-fi
-
-for ac_site_file in $ac_site_files
-do
- case $ac_site_file in #(
- */*) :
- ;; #(
- *) :
- ac_site_file=./$ac_site_file ;;
-esac
- if test -f "$ac_site_file" && test -r "$ac_site_file"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;}
- sed 's/^/| /' "$ac_site_file" >&5
- . "$ac_site_file" \
- || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed to load site script $ac_site_file
-See \`config.log' for more details" "$LINENO" 5; }
- fi
-done
-
-if test -r "$cache_file"; then
- # Some versions of bash will fail to source /dev/null (special files
- # actually), so we avoid doing that. DJGPP emulates it as a regular file.
- if test /dev/null != "$cache_file" && test -f "$cache_file"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-printf "%s\n" "$as_me: loading cache $cache_file" >&6;}
- case $cache_file in
- [\\/]* | ?:[\\/]* ) . "$cache_file";;
- *) . "./$cache_file";;
- esac
- fi
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-printf "%s\n" "$as_me: creating cache $cache_file" >&6;}
- >$cache_file
-fi
-
-# Test code for whether the C compiler supports C89 (global declarations)
-ac_c_conftest_c89_globals='
-/* Does the compiler advertise C89 conformance?
- Do not test the value of __STDC__, because some compilers set it to 0
- while being otherwise adequately conformant. */
-#if !defined __STDC__
-# error "Compiler does not advertise C89 conformance"
-#endif
-
-#include <stddef.h>
-#include <stdarg.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */
-struct buf { int x; };
-struct buf * (*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 do not provoke an error unfortunately, instead are silently treated
- as an "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 is necessary to write \x00 == 0 to get something
- that is 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 **, int *(*)(struct buf *, struct stat *, int),
- int, int);'
-
-# Test code for whether the C compiler supports C89 (body of main).
-ac_c_conftest_c89_main='
-ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]);
-'
-
-# Test code for whether the C compiler supports C99 (global declarations)
-ac_c_conftest_c99_globals='
-// Does the compiler advertise C99 conformance?
-#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
-# error "Compiler does not advertise C99 conformance"
-#endif
-
-#include <stdbool.h>
-extern int puts (const char *);
-extern int printf (const char *, ...);
-extern int dprintf (int, const char *, ...);
-extern void *malloc (size_t);
-
-// Check varargs macros. These examples are taken from C99 6.10.3.5.
-// dprintf is used instead of fprintf to avoid needing to declare
-// FILE and stderr.
-#define debug(...) dprintf (2, __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
- #error "your preprocessor is broken"
-#endif
-#if BIG_OK
-#else
- #error "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 bool
-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 = 0;
- float fnumber = 0;
-
- 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);
-
- return *str && number && fnumber;
-}
-'
-
-# Test code for whether the C compiler supports C99 (body of main).
-ac_c_conftest_c99_main='
- // Check bool.
- _Bool success = false;
- success |= (argc != 0);
-
- // Check restrict.
- if (test_restrict ("String literal") == 0)
- success = true;
- char *restrict newvar = "Another string";
-
- // Check varargs.
- success &= 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[0] = argv[0][0];
- dynamic_array[ni.number - 1] = 543;
-
- // work around unused variable warnings
- ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\''
- || dynamic_array[ni.number - 1] != 543);
-'
-
-# Test code for whether the C compiler supports C11 (global declarations)
-ac_c_conftest_c11_globals='
-// Does the compiler advertise C11 conformance?
-#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
-# error "Compiler does not advertise C11 conformance"
-#endif
-
-// Check _Alignas.
-char _Alignas (double) aligned_as_double;
-char _Alignas (0) no_special_alignment;
-extern char aligned_as_int;
-char _Alignas (0) _Alignas (int) aligned_as_int;
-
-// Check _Alignof.
-enum
-{
- int_alignment = _Alignof (int),
- int_array_alignment = _Alignof (int[100]),
- char_alignment = _Alignof (char)
-};
-_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
-
-// Check _Noreturn.
-int _Noreturn does_not_return (void) { for (;;) continue; }
-
-// Check _Static_assert.
-struct test_static_assert
-{
- int x;
- _Static_assert (sizeof (int) <= sizeof (long int),
- "_Static_assert does not work in struct");
- long int y;
-};
-
-// Check UTF-8 literals.
-#define u8 syntax error!
-char const utf8_literal[] = u8"happens to be ASCII" "another string";
-
-// Check duplicate typedefs.
-typedef long *long_ptr;
-typedef long int *long_ptr;
-typedef long_ptr long_ptr;
-
-// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
-struct anonymous
-{
- union {
- struct { int i; int j; };
- struct { int k; long int l; } w;
- };
- int m;
-} v1;
-'
-
-# Test code for whether the C compiler supports C11 (body of main).
-ac_c_conftest_c11_main='
- _Static_assert ((offsetof (struct anonymous, i)
- == offsetof (struct anonymous, w.k)),
- "Anonymous union alignment botch");
- v1.i = 2;
- v1.w.k = 5;
- ok |= v1.i != 5;
-'
-
-# Test code for whether the C compiler supports C11 (complete).
-ac_c_conftest_c11_program="${ac_c_conftest_c89_globals}
-${ac_c_conftest_c99_globals}
-${ac_c_conftest_c11_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- ${ac_c_conftest_c99_main}
- ${ac_c_conftest_c11_main}
- return ok;
-}
-"
-
-# Test code for whether the C compiler supports C99 (complete).
-ac_c_conftest_c99_program="${ac_c_conftest_c89_globals}
-${ac_c_conftest_c99_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- ${ac_c_conftest_c99_main}
- return ok;
-}
-"
-
-# Test code for whether the C compiler supports C89 (complete).
-ac_c_conftest_c89_program="${ac_c_conftest_c89_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- return ok;
-}
-"
-
-as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H"
-as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H"
-as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H"
-as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
-as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
-as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
-as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
-as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
-as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
-
-# Auxiliary files required by this configure script.
-ac_aux_files="config.guess config.sub ltmain.sh compile missing install-sh"
-
-# Locations in which to look for auxiliary files.
-ac_aux_dir_candidates="${srcdir}/."
-
-# Search for a directory containing all of the required auxiliary files,
-# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates.
-# If we don't find one directory that contains all the files we need,
-# we report the set of missing files from the *first* directory in
-# $ac_aux_dir_candidates and give up.
-ac_missing_aux_files=""
-ac_first_candidate=:
-printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in $ac_aux_dir_candidates
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- as_found=:
-
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5
- ac_aux_dir_found=yes
- ac_install_sh=
- for ac_aux in $ac_aux_files
- do
- # As a special case, if "install-sh" is required, that requirement
- # can be satisfied by any of "install-sh", "install.sh", or "shtool",
- # and $ac_install_sh is set appropriately for whichever one is found.
- if test x"$ac_aux" = x"install-sh"
- then
- if test -f "${as_dir}install-sh"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5
- ac_install_sh="${as_dir}install-sh -c"
- elif test -f "${as_dir}install.sh"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5
- ac_install_sh="${as_dir}install.sh -c"
- elif test -f "${as_dir}shtool"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5
- ac_install_sh="${as_dir}shtool install -c"
- else
- ac_aux_dir_found=no
- if $ac_first_candidate; then
- ac_missing_aux_files="${ac_missing_aux_files} install-sh"
- else
- break
- fi
- fi
- else
- if test -f "${as_dir}${ac_aux}"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5
- else
- ac_aux_dir_found=no
- if $ac_first_candidate; then
- ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}"
- else
- break
- fi
- fi
- fi
- done
- if test "$ac_aux_dir_found" = yes; then
- ac_aux_dir="$as_dir"
- break
- fi
- ac_first_candidate=false
-
- as_found=false
-done
-IFS=$as_save_IFS
-if $as_found
-then :
-
-else $as_nop
- as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5
-fi
-
-
-# These three variables are undocumented and unsupported,
-# and are intended to be withdrawn in a future Autoconf release.
-# They can cause serious problems if a builder's source tree is in a directory
-# whose full name contains unusual characters.
-if test -f "${ac_aux_dir}config.guess"; then
- ac_config_guess="$SHELL ${ac_aux_dir}config.guess"
-fi
-if test -f "${ac_aux_dir}config.sub"; then
- ac_config_sub="$SHELL ${ac_aux_dir}config.sub"
-fi
-if test -f "$ac_aux_dir/configure"; then
- ac_configure="$SHELL ${ac_aux_dir}configure"
-fi
-
-# Check that the precious variables saved in the cache have kept the same
-# value.
-ac_cache_corrupted=false
-for ac_var in $ac_precious_vars; do
- eval ac_old_set=\$ac_cv_env_${ac_var}_set
- eval ac_new_set=\$ac_env_${ac_var}_set
- eval ac_old_val=\$ac_cv_env_${ac_var}_value
- eval ac_new_val=\$ac_env_${ac_var}_value
- case $ac_old_set,$ac_new_set in
- set,)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,set)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,);;
- *)
- if test "x$ac_old_val" != "x$ac_new_val"; then
- # differences in whitespace do not lead to failure.
- ac_old_val_w=`echo x $ac_old_val`
- ac_new_val_w=`echo x $ac_new_val`
- if test "$ac_old_val_w" != "$ac_new_val_w"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
- ac_cache_corrupted=:
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
- eval $ac_var=\$ac_old_val
- fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
-printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
-printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;}
- fi;;
- esac
- # Pass precious variables to config.status.
- if test "$ac_new_set" = set; then
- case $ac_new_val in
- *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
- *) ac_arg=$ac_var=$ac_new_val ;;
- esac
- case " $ac_configure_args " in
- *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
- *) as_fn_append ac_configure_args " '$ac_arg'" ;;
- esac
- fi
-done
-if $ac_cache_corrupted; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file'
- and start over" "$LINENO" 5
-fi
-## -------------------- ##
-## Main body of script. ##
-## -------------------- ##
-
-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
-
-
-
-
-
-# Use automake.
-am__api_version='1.16'
-
-
-
- # 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.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
-printf %s "checking for a BSD-compatible install... " >&6; }
-if test -z "$INSTALL"; then
-if test ${ac_cv_path_install+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- # Account for fact that we put trailing slashes in our PATH walk.
-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+y}; 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
-printf "%s\n" "$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}'
-
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
-
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
-printf %s "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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "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=`printf "%s\n" "$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
- MISSING="\${SHELL} '$am_aux_dir/missing'"
-fi
-# Use eval to expand $SHELL
-if eval "$MISSING --is-lightweight"; then
- am_missing_run="$MISSING "
-else
- am_missing_run=
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
-printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
-fi
-
-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}strip", so it can be a program name with args.
-set dummy ${ac_tool_prefix}strip; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_STRIP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_STRIP="${ac_tool_prefix}strip"
- printf "%s\n" "$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
-STRIP=$ac_cv_prog_STRIP
-if test -n "$STRIP"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
-printf "%s\n" "$STRIP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_STRIP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_STRIP="strip"
- printf "%s\n" "$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_STRIP=$ac_cv_prog_ac_ct_STRIP
-if test -n "$ac_ct_STRIP"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
-printf "%s\n" "$ac_ct_STRIP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_STRIP" = x; then
- STRIP=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- STRIP=$ac_ct_STRIP
- fi
-else
- STRIP="$ac_cv_prog_STRIP"
-fi
-
-fi
-INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5
-printf %s "checking for a race-free mkdir -p... " >&6; }
-if test -z "$MKDIR_P"; then
- if test ${ac_cv_path_mkdir+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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 ('*'coreutils) '* | \
- 'BusyBox '* | \
- '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
-
- test -d ./--version && rmdir ./--version
- if test ${ac_cv_path_mkdir+y}; 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
-printf "%s\n" "$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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_AWK+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
-printf "%s\n" "$AWK" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$AWK" && break
-done
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
-printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
-set x ${MAKE-make}
-ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
-if eval test \${ac_cv_prog_make_${ac_make}_set+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- SET_MAKE=
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- SET_MAKE="MAKE=${MAKE-make}"
-fi
-
-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
-
-# Check whether --enable-silent-rules was given.
-if test ${enable_silent_rules+y}
-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}
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
-printf %s "checking whether $am_make supports nested variables... " >&6; }
-if test ${am_cv_make_support_nested_variables+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if printf "%s\n" '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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
-printf "%s\n" "$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
-
-
-# Define the identity of the package.
- PACKAGE='sqlite'
- VERSION='3.46.1'
-
-
-printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
-
-
-printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h
-
-# 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}"}
-
-
-AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
-
-
-MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
-
-# 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 -'
-
-
-
-
-
-# Variables for tags utilities; see am/tags.am
-if test -z "$CTAGS"; then
- CTAGS=ctags
-fi
-
-if test -z "$ETAGS"; then
- ETAGS=etags
-fi
-
-if test -z "$CSCOPE"; then
- CSCOPE=cscope
-fi
-
-
-
-# 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
- as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
- fi
-fi
-
-
-
-
-
-
-
-
-
-
-
-DEPDIR="${am__leading_dot}deps"
-
-ac_config_commands="$ac_config_commands depfiles"
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5
-printf %s "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.*
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5
-printf "%s\n" "${_am_result}" >&6; }
-
-# Check whether --enable-dependency-tracking was given.
-if test ${enable_dependency_tracking+y}
-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
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$ac_ct_CC" && break
-done
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
-set dummy ${ac_tool_prefix}clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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}clang"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "clang", so it can be a program name with args.
-set dummy clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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="clang"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-
-fi
-
-
-test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$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.
-printf "%s\n" "$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 -version; 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\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
- 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
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-done
-
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
-# Try to create an executable without -o first, disregard a.out.
-# It will help us diagnose broken compilers, and finding out an intuition
-# of exeext.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-printf %s "checking whether the C compiler works... " >&6; }
-ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-
-# The possible output files:
-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
-
-ac_rmfiles=
-for ac_file in $ac_files
-do
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
- * ) ac_rmfiles="$ac_rmfiles $ac_file";;
- esac
-done
-rm -f $ac_rmfiles
-
-if { { ac_try="$ac_link_default"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link_default") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
-# in a Makefile. We should not override ac_cv_exeext if it was cached,
-# so that the user can short-circuit this test for compilers unknown to
-# Autoconf.
-for ac_file in $ac_files ''
-do
- test -f "$ac_file" || continue
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
- ;;
- [ab].out )
- # We found the default executable, but exeext='' is most
- # certainly right.
- break;;
- *.* )
- if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no;
- then :; else
- ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- fi
- # We set ac_cv_exeext here because the later test for it is not
- # safe: cross compilers may not add the suffix if given an `-o'
- # argument, so we may need to know it at that point already.
- # Even if this section looks crufty: it has the advantage of
- # actually working.
- break;;
- * )
- break;;
- esac
-done
-test "$ac_cv_exeext" = no && ac_cv_exeext=
-
-else $as_nop
- ac_file=''
-fi
-if test -z "$ac_file"
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "C compiler cannot create executables
-See \`config.log' for more details" "$LINENO" 5; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-printf %s "checking for C compiler default output file name... " >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-printf "%s\n" "$ac_file" >&6; }
-ac_exeext=$ac_cv_exeext
-
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
-ac_clean_files=$ac_clean_files_save
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-printf %s "checking for suffix of executables... " >&6; }
-if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- # If both `conftest.exe' and `conftest' are `present' (well, observable)
-# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
-# work properly (i.e., refer to `conftest.exe'), while it won't with
-# `rm'.
-for ac_file in conftest.exe conftest conftest.*; do
- test -f "$ac_file" || continue
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
- *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- break;;
- * ) break;;
- esac
-done
-else $as_nop
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest conftest$ac_cv_exeext
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-printf "%s\n" "$ac_cv_exeext" >&6; }
-
-rm -f conftest.$ac_ext
-EXEEXT=$ac_cv_exeext
-ac_exeext=$EXEEXT
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdio.h>
-int
-main (void)
-{
-FILE *f = fopen ("conftest.out", "w");
- return ferror (f) || fclose (f) != 0;
-
- ;
- return 0;
-}
-_ACEOF
-ac_clean_files="$ac_clean_files conftest.out"
-# Check that the compiler produces executables we can run. If not, either
-# the compiler is broken, or we cross compile.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-printf %s "checking whether we are cross compiling... " >&6; }
-if test "$cross_compiling" != yes; then
- { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- if { ac_try='./conftest$ac_cv_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }; then
- cross_compiling=no
- else
- if test "$cross_compiling" = maybe; then
- cross_compiling=yes
- else
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details" "$LINENO" 5; }
- fi
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-printf "%s\n" "$cross_compiling" >&6; }
-
-rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
-ac_clean_files=$ac_clean_files_save
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-printf %s "checking for suffix of object files... " >&6; }
-if test ${ac_cv_objext+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.o conftest.obj
-if { { ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compile") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- for ac_file in conftest.o conftest.obj conftest.*; do
- test -f "$ac_file" || continue;
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
- *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
- break;;
- esac
-done
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest.$ac_cv_objext conftest.$ac_ext
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-printf "%s\n" "$ac_cv_objext" >&6; }
-OBJEXT=$ac_cv_objext
-ac_objext=$OBJEXT
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
-printf %s "checking whether the compiler supports GNU C... " >&6; }
-if test ${ac_cv_c_compiler_gnu+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_compiler_gnu=yes
-else $as_nop
- ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-if test $ac_compiler_gnu = yes; then
- GCC=yes
-else
- GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+y}
-ac_save_CFLAGS=$CFLAGS
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-printf %s "checking whether $CC accepts -g... " >&6; }
-if test ${ac_cv_prog_cc_g+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_g=yes
-else $as_nop
- CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else $as_nop
- ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- 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.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
-if test $ac_test_CFLAGS; 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
-ac_prog_cc_stdc=no
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
-printf %s "checking for $CC option to enable C11 features... " >&6; }
-if test ${ac_cv_prog_cc_c11+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c11=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c11_program
-_ACEOF
-for ac_arg in '' -std=gnu11
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c11=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c11" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c11" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c11" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
-printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
- CC="$CC $ac_cv_prog_cc_c11"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
- ac_prog_cc_stdc=c11
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
-printf %s "checking for $CC option to enable C99 features... " >&6; }
-if test ${ac_cv_prog_cc_c99+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c99=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c99_program
-_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
-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 conftest.beam
- test "x$ac_cv_prog_cc_c99" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c99" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c99" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
- CC="$CC $ac_cv_prog_cc_c99"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
- ac_prog_cc_stdc=c99
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
-printf %s "checking for $CC option to enable C89 features... " >&6; }
-if test ${ac_cv_prog_cc_c89+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c89_program
-_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 conftest.beam
- test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c89" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c89" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
- CC="$CC $ac_cv_prog_cc_c89"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
- ac_prog_cc_stdc=c89
-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=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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
-printf %s "checking whether $CC understands -c and -o together... " >&6; }
-if test ${am_cv_prog_cc_c_o+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
-printf "%s\n" "$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=
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
-printf %s "checking dependency style of $depcc... " >&6; }
-if test ${am_cv_CC_dependencies_compiler_type+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
-printf "%s\n" "$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
-
-
-
-# Check whether --enable-largefile was given.
-if test ${enable_largefile+y}
-then :
- enableval=$enable_largefile;
-fi
-
-if test "$enable_largefile" != no; then
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
-printf %s "checking for special C compiler options needed for large files... " >&6; }
-if test ${ac_cv_sys_largefile_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_sys_largefile_CC=no
- if test "$GCC" != yes; then
- ac_save_CC=$CC
- while :; do
- # IRIX 6.2 and later do not support large files by default,
- # so use the C compiler's -n32 option if that helps.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
- if ac_fn_c_try_compile "$LINENO"
-then :
- break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- CC="$CC -n32"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_largefile_CC=' -n32'; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- break
- done
- CC=$ac_save_CC
- rm -f conftest.$ac_ext
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
-printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; }
- if test "$ac_cv_sys_largefile_CC" != no; then
- CC=$CC$ac_cv_sys_largefile_CC
- fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
-printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
-if test ${ac_cv_sys_file_offset_bits+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- while :; do
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_file_offset_bits=no; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#define _FILE_OFFSET_BITS 64
-#include <sys/types.h>
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_file_offset_bits=64; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_cv_sys_file_offset_bits=unknown
- break
-done
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
-printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; }
-case $ac_cv_sys_file_offset_bits in #(
- no | unknown) ;;
- *)
-printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h
-;;
-esac
-rm -rf conftest*
- if test $ac_cv_sys_file_offset_bits = unknown; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
-printf %s "checking for _LARGE_FILES value needed for large files... " >&6; }
-if test ${ac_cv_sys_large_files+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- while :; do
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_large_files=no; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#define _LARGE_FILES 1
-#include <sys/types.h>
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_large_files=1; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_cv_sys_large_files=unknown
- break
-done
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
-printf "%s\n" "$ac_cv_sys_large_files" >&6; }
-case $ac_cv_sys_large_files in #(
- no | unknown) ;;
- *)
-printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h
-;;
-esac
-rm -rf conftest*
- fi
-fi
-
-
-# Check for required programs.
-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 -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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$ac_ct_CC" && break
-done
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
-set dummy ${ac_tool_prefix}clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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}clang"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "clang", so it can be a program name with args.
-set dummy clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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="clang"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-
-fi
-
-
-test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$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.
-printf "%s\n" "$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 -version; 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\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
- 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
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-done
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
-printf %s "checking whether the compiler supports GNU C... " >&6; }
-if test ${ac_cv_c_compiler_gnu+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_compiler_gnu=yes
-else $as_nop
- ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-if test $ac_compiler_gnu = yes; then
- GCC=yes
-else
- GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+y}
-ac_save_CFLAGS=$CFLAGS
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-printf %s "checking whether $CC accepts -g... " >&6; }
-if test ${ac_cv_prog_cc_g+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_g=yes
-else $as_nop
- CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else $as_nop
- ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- 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.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
-if test $ac_test_CFLAGS; 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
-ac_prog_cc_stdc=no
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
-printf %s "checking for $CC option to enable C11 features... " >&6; }
-if test ${ac_cv_prog_cc_c11+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c11=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c11_program
-_ACEOF
-for ac_arg in '' -std=gnu11
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c11=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c11" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c11" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c11" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
-printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
- CC="$CC $ac_cv_prog_cc_c11"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
- ac_prog_cc_stdc=c11
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
-printf %s "checking for $CC option to enable C99 features... " >&6; }
-if test ${ac_cv_prog_cc_c99+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c99=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c99_program
-_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
-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 conftest.beam
- test "x$ac_cv_prog_cc_c99" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c99" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c99" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
- CC="$CC $ac_cv_prog_cc_c99"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
- ac_prog_cc_stdc=c99
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
-printf %s "checking for $CC option to enable C89 features... " >&6; }
-if test ${ac_cv_prog_cc_c89+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c89_program
-_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 conftest.beam
- test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c89" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c89" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
- CC="$CC $ac_cv_prog_cc_c89"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
- ac_prog_cc_stdc=c89
-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=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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
-printf %s "checking whether $CC understands -c and -o together... " >&6; }
-if test ${am_cv_prog_cc_c_o+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
-printf "%s\n" "$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=
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
-printf %s "checking dependency style of $depcc... " >&6; }
-if test ${am_cv_CC_dependencies_compiler_type+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
-printf "%s\n" "$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
-
-
-case `pwd` in
- *\ * | *\ *)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
-printf "%s\n" "$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
-
-
-
- # 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
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-printf %s "checking build system type... " >&6; }
-if test ${ac_cv_build+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
- ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"`
-test "x$ac_build_alias" = x &&
- as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` ||
- as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-printf "%s\n" "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-printf %s "checking host system type... " >&6; }
-if test ${ac_cv_host+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test "x$host_alias" = x; then
- ac_cv_host=$ac_cv_build
-else
- ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` ||
- as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5
-fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-printf "%s\n" "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
-
-# 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
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
-printf %s "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*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5
-printf "%s\n" "printf" >&6; } ;;
- print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
-printf "%s\n" "print -r" >&6; } ;;
- *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5
-printf "%s\n" "cat" >&6; } ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
-printf %s "checking for a sed that does not truncate output... " >&6; }
-if test ${ac_cv_path_SED+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
- for ac_i in 1 2 3 4 5 6 7; do
- ac_script="$ac_script$as_nl$ac_script"
- done
- echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
- { ac_script=; unset ac_script;}
- if test -z "$SED"; then
- ac_path_SED_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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in sed gsed
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_SED="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_SED" || continue
-# Check for GNU ac_path_SED and select it if it is found.
- # Check for GNU $ac_path_SED
-case `"$ac_path_SED" --version 2>&1` in
-*GNU*)
- ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" '' >> "conftest.nl"
- "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_SED_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_SED="$ac_path_SED"
- ac_path_SED_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_SED_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_SED"; then
- as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
- fi
-else
- ac_cv_path_SED=$SED
-fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
-printf "%s\n" "$ac_cv_path_SED" >&6; }
- SED="$ac_cv_path_SED"
- rm -f conftest.sed
-
-test -z "$SED" && SED=sed
-Xsed="$SED -e 1s/^X//"
-
-
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-printf %s "checking for grep that handles long lines and -e... " >&6; }
-if test ${ac_cv_path_GREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -z "$GREP"; then
- ac_path_GREP_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$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in grep ggrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_GREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
- # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'GREP' >> "conftest.nl"
- "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_GREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_GREP="$ac_path_GREP"
- ac_path_GREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_GREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_GREP"; then
- as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-printf "%s\n" "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-printf %s "checking for egrep... " >&6; }
-if test ${ac_cv_path_EGREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
- then ac_cv_path_EGREP="$GREP -E"
- else
- if test -z "$EGREP"; then
- ac_path_EGREP_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$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in egrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
- # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'EGREP' >> "conftest.nl"
- "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_EGREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_EGREP="$ac_path_EGREP"
- ac_path_EGREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_EGREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_EGREP"; then
- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_EGREP=$EGREP
-fi
-
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-printf "%s\n" "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
-printf %s "checking for fgrep... " >&6; }
-if test ${ac_cv_path_FGREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
- then ac_cv_path_FGREP="$GREP -F"
- else
- if test -z "$FGREP"; then
- ac_path_FGREP_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$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in fgrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_FGREP" || continue
-# Check for GNU ac_path_FGREP and select it if it is found.
- # Check for GNU $ac_path_FGREP
-case `"$ac_path_FGREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'FGREP' >> "conftest.nl"
- "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_FGREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_FGREP="$ac_path_FGREP"
- ac_path_FGREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_FGREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_FGREP"; then
- as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_FGREP=$FGREP
-fi
-
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
-printf "%s\n" "$ac_cv_path_FGREP" >&6; }
- FGREP="$ac_cv_path_FGREP"
-
-
-test -z "$GREP" && GREP=grep
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# Check whether --with-gnu-ld was given.
-if test ${with_gnu_ld+y}
-then :
- withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
-else $as_nop
- with_gnu_ld=no
-fi
-
-ac_prog=ld
-if test yes = "$GCC"; then
- # Check if gcc -print-prog-name=ld gives a path.
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
-printf %s "checking for ld used by $CC... " >&6; }
- case $host in
- *-*-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` ;;
- esac
- case $ac_prog in
- # Accept absolute paths.
- [\\/]* | ?:[\\/]*)
- re_direlt='/[^/][^/]*/\.\./'
- # Canonicalize the pathname of ld
- ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
- 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
- ;;
- "")
- # If it fails, then pretend we aren't using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
-elif test yes = "$with_gnu_ld"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
-printf %s "checking for GNU ld... " >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
-printf %s "checking for non-GNU ld... " >&6; }
-fi
-if test ${lt_cv_path_LD+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -z "$LD"; then
- lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH; do
- 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
- # 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 no != "$with_gnu_ld" && break
- ;;
- *)
- test yes != "$with_gnu_ld" && break
- ;;
- esac
- fi
- done
- IFS=$lt_save_ifs
-else
- lt_cv_path_LD=$LD # Let the user override the test with a path.
-fi
-fi
-
-LD=$lt_cv_path_LD
-if test -n "$LD"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
-printf "%s\n" "$LD" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
-printf %s "checking if the linker ($LD) is GNU ld... " >&6; }
-if test ${lt_cv_prog_gnu_ld+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- # I'd rather use --version here, but apparently some GNU lds only accept -v.
-case `$LD -v 2>&1 </dev/null` in
-*GNU* | *'with BFD'*)
- lt_cv_prog_gnu_ld=yes
- ;;
-*)
- lt_cv_prog_gnu_ld=no
- ;;
-esac
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
-printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; }
-with_gnu_ld=$lt_cv_prog_gnu_ld
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
-printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
-if test ${lt_cv_path_NM+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$NM"; then
- # Let the user override the test.
- lt_cv_path_NM=$NM
-else
- 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
- for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
- 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
- # Check to see if the nm accepts a BSD-compat flag.
- # 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
- # 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 2
- ;;
- *)
- case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
- */dev/null*)
- lt_cv_path_NM="$tmp_nm -p"
- break 2
- ;;
- *)
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
- ;;
- esac
- ;;
- esac
- fi
- done
- IFS=$lt_save_ifs
- done
- : ${lt_cv_path_NM=no}
-fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
-printf "%s\n" "$lt_cv_path_NM" >&6; }
-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
- if test -n "$ac_tool_prefix"; then
- for ac_prog in dumpbin "link -dump"
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_DUMPBIN+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$DUMPBIN"; then
- ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_DUMPBIN="$ac_tool_prefix$ac_prog"
- printf "%s\n" "$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
-DUMPBIN=$ac_cv_prog_DUMPBIN
-if test -n "$DUMPBIN"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
-printf "%s\n" "$DUMPBIN" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$DUMPBIN" && break
- done
-fi
-if test -z "$DUMPBIN"; then
- ac_ct_DUMPBIN=$DUMPBIN
- for ac_prog in dumpbin "link -dump"
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_DUMPBIN+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_DUMPBIN"; then
- ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_DUMPBIN="$ac_prog"
- printf "%s\n" "$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_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
-if test -n "$ac_ct_DUMPBIN"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
-printf "%s\n" "$ac_ct_DUMPBIN" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$ac_ct_DUMPBIN" && break
-done
-
- if test "x$ac_ct_DUMPBIN" = x; then
- DUMPBIN=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- DUMPBIN=$ac_ct_DUMPBIN
- fi
-fi
-
- case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
- *COFF*)
- DUMPBIN="$DUMPBIN -symbols -headers"
- ;;
- *)
- DUMPBIN=:
- ;;
- esac
- fi
-
- if test : != "$DUMPBIN"; then
- NM=$DUMPBIN
- fi
-fi
-test -z "$NM" && NM=nm
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
-printf %s "checking the name lister ($NM) interface... " >&6; }
-if test ${lt_cv_nm_interface+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_nm_interface="BSD nm"
- echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
- (eval "$ac_compile" 2>conftest.err)
- cat conftest.err >&5
- (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
- (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
- cat conftest.err >&5
- (eval echo "\"\$as_me:$LINENO: output\"" >&5)
- cat conftest.out >&5
- if $GREP 'External.*some_variable' conftest.out > /dev/null; then
- lt_cv_nm_interface="MS dumpbin"
- fi
- rm -f conftest*
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
-printf "%s\n" "$lt_cv_nm_interface" >&6; }
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
-printf %s "checking whether ln -s works... " >&6; }
-LN_S=$as_ln_s
-if test "$LN_S" = "ln -s"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
-printf "%s\n" "no, using $LN_S" >&6; }
-fi
-
-# find the maximum length of command line arguments
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
-printf %s "checking the maximum length of command line arguments... " >&6; }
-if test ${lt_cv_sys_max_cmd_len+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- i=0
- teststring=ABCD
-
- case $build_os in
- msdosdjgpp*)
- # On DJGPP, this test can blow up pretty badly due to problems in libc
- # (any single argument exceeding 2000 bytes causes a buffer overrun
- # during glob expansion). Even if it were fixed, the result of this
- # check would be larger than it should be.
- lt_cv_sys_max_cmd_len=12288; # 12K is about right
- ;;
-
- gnu*)
- # Under GNU Hurd, this test is not required because there is
- # no limit to the length of command line arguments.
- # Libtool will interpret -1 as no limit whatsoever
- lt_cv_sys_max_cmd_len=-1;
- ;;
-
- cygwin* | mingw* | cegcc*)
- # On Win9x/ME, this test blows up -- it succeeds, but takes
- # about 5 minutes as the teststring grows exponentially.
- # Worse, since 9x/ME are not pre-emptively multitasking,
- # you end up with a "frozen" computer, even though with patience
- # the test eventually succeeds (with a max line length of 256k).
- # Instead, let's just punt: use the minimum linelength reported by
- # all of the supported platforms: 8192 (on NT/2K/XP).
- 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;
- ;;
-
- 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`
- elif test -x /usr/sbin/sysctl; then
- lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
- else
- lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
- fi
- # And add a safety zone
- 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`
- ;;
-
- interix*)
- # We know the value 262144 and hardcode it with a safety zone (like BSD)
- lt_cv_sys_max_cmd_len=196608
- ;;
-
- os2*)
- # The test takes a long time on OS/2.
- lt_cv_sys_max_cmd_len=8192
- ;;
-
- osf*)
- # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
- # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
- # nice to cause kernel panics so lets avoid the loop below.
- # First set a reasonable default.
- lt_cv_sys_max_cmd_len=16384
- #
- if test -x /sbin/sysconfig; then
- case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
- *1*) lt_cv_sys_max_cmd_len=-1 ;;
- esac
- fi
- ;;
- sco3.2v5*)
- lt_cv_sys_max_cmd_len=102400
- ;;
- sysv5* | sco5v6* | sysv4.2uw2*)
- kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
- if test -n "$kargmax"; then
- lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
- else
- lt_cv_sys_max_cmd_len=32768
- fi
- ;;
- *)
- 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
- 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
- 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` \
- = "X$teststring$teststring"; } >/dev/null 2>&1 &&
- test 17 != "$i" # 1/2 MB should be enough
- do
- i=`expr $i + 1`
- teststring=$teststring$teststring
- done
- # Only check the string length outside the loop.
- lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
- teststring=
- # Add a significant safety factor because C++ compilers can tack on
- # massive amounts of additional arguments before passing them to the
- # linker. It appears as though 1/2 is a usable value.
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
- fi
- ;;
- esac
-
-fi
-
-if test -n "$lt_cv_sys_max_cmd_len"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
-printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5
-printf "%s\n" "none" >&6; }
-fi
-max_cmd_len=$lt_cv_sys_max_cmd_len
-
-
-
-
-
-
-: ${CP="cp -f"}
-: ${MV="mv -f"}
-: ${RM="rm -f"}
-
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
- lt_unset=unset
-else
- lt_unset=false
-fi
-
-
-
-
-
-# test EBCDIC or ASCII
-case `echo X|tr X '\101'` in
- A) # ASCII based system
- # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
- lt_SP2NL='tr \040 \012'
- lt_NL2SP='tr \015\012 \040\040'
- ;;
- *) # EBCDIC based system
- lt_SP2NL='tr \100 \n'
- lt_NL2SP='tr \r\n \100\100'
- ;;
-esac
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
-printf %s "checking how to convert $build file names to $host format... " >&6; }
-if test ${lt_cv_to_host_file_cmd+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- case $host in
- *-*-mingw* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
- ;;
- *-*-cygwin* )
- lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
- ;;
- * ) # otherwise, assume *nix
- lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
- ;;
- esac
- ;;
- *-*-cygwin* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
- ;;
- *-*-cygwin* )
- lt_cv_to_host_file_cmd=func_convert_file_noop
- ;;
- * ) # otherwise, assume *nix
- lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
- ;;
- esac
- ;;
- * ) # unhandled hosts (and "normal" native builds)
- lt_cv_to_host_file_cmd=func_convert_file_noop
- ;;
-esac
-
-fi
-
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
-printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; }
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
-printf %s "checking how to convert $build file names to toolchain format... " >&6; }
-if test ${lt_cv_to_tool_file_cmd+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- #assume ordinary cross tools, or native build.
-lt_cv_to_tool_file_cmd=func_convert_file_noop
-case $host in
- *-*-mingw* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
- ;;
- esac
- ;;
-esac
-
-fi
-
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
-printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; }
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
-printf %s "checking for $LD option to reload object files... " >&6; }
-if test ${lt_cv_ld_reload_flag+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_ld_reload_flag='-r'
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
-printf "%s\n" "$lt_cv_ld_reload_flag" >&6; }
-reload_flag=$lt_cv_ld_reload_flag
-case $reload_flag in
-"" | " "*) ;;
-*) reload_flag=" $reload_flag" ;;
-esac
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
- if test yes != "$GCC"; then
- reload_cmds=false
- fi
- ;;
- darwin*)
- 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
- ;;
-esac
-
-
-
-
-
-
-
-
-
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_OBJDUMP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
-printf "%s\n" "$OBJDUMP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_OBJDUMP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
-printf "%s\n" "$ac_ct_OBJDUMP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_OBJDUMP" = x; then
- OBJDUMP="false"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$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
-
-test -z "$OBJDUMP" && OBJDUMP=objdump
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
-printf %s "checking how to recognize dependent libraries... " >&6; }
-if test ${lt_cv_deplibs_check_method+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-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.
-# '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
-# 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]*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-beos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-bsdi[45]*)
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- lt_cv_file_magic_test_file=/shlib/libc.so
- ;;
-
-cygwin*)
- # func_win32_libid is a shell function defined in ltmain.sh
- lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
- lt_cv_file_magic_cmd='func_win32_libid'
- ;;
-
-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.
- 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
- # Keep this pattern in sync with the one in func_win32_libid.
- lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- fi
- ;;
-
-cegcc*)
- # use the weaker test based on 'objdump'. See mingw*.
- lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- ;;
-
-darwin* | rhapsody*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-freebsd* | dragonfly*)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
- case $host_cpu in
- i*86 )
- # Not sure whether the presence of OpenBSD here was a mistake.
- # Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- ;;
- esac
- else
- lt_cv_deplibs_check_method=pass_all
- fi
- ;;
-
-haiku*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-hpux10.20* | hpux11*)
- lt_cv_file_magic_cmd=/usr/bin/file
- case $host_cpu in
- ia64*)
- lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
- lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
- ;;
- hppa*64*)
- lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
- lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
- ;;
- *)
- lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
- lt_cv_file_magic_test_file=/usr/lib/libc.sl
- ;;
- esac
- ;;
-
-interix[3-9]*)
- # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
- lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
- ;;
-
-irix5* | irix6* | nonstopux*)
- case $LD in
- *-32|*"-32 ") libmagic=32-bit;;
- *-n32|*"-n32 ") libmagic=N32;;
- *-64|*"-64 ") libmagic=64-bit;;
- *) libmagic=never-match;;
- esac
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-netbsd* | netbsdelf*-gnu)
- 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
- lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
- fi
- ;;
-
-newos6*)
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libnls.so
- ;;
-
-*nto* | *qnx*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-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)$'
- fi
- ;;
-
-osf3* | osf4* | osf5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-rdos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-solaris*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv4 | sysv4.3*)
- case $host_vendor in
- motorola)
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
- ;;
- ncr)
- lt_cv_deplibs_check_method=pass_all
- ;;
- sequent)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
- ;;
- sni)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
- siemens)
- lt_cv_deplibs_check_method=pass_all
- ;;
- pc)
- lt_cv_deplibs_check_method=pass_all
- ;;
- esac
- ;;
-
-tpf*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-os2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-esac
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
-printf "%s\n" "$lt_cv_deplibs_check_method" >&6; }
-
-file_magic_glob=
-want_nocaseglob=no
-if test "$build" = "$host"; then
- case $host_os in
- mingw* | pw32*)
- if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
- want_nocaseglob=yes
- else
- file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
- fi
- ;;
- esac
-fi
-
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_DLLTOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
-printf "%s\n" "$DLLTOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_DLLTOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
-printf "%s\n" "$ac_ct_DLLTOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_DLLTOOL" = x; then
- DLLTOOL="false"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$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
-
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
-printf %s "checking how to associate runtime and link libraries... " >&6; }
-if test ${lt_cv_sharedlib_from_linklib_cmd+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_sharedlib_from_linklib_cmd='unknown'
-
-case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
- # 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
- ;;
- *)
- lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
- ;;
- esac
- ;;
-*)
- # fallback: assume linklib IS sharedlib
- lt_cv_sharedlib_from_linklib_cmd=$ECHO
- ;;
-esac
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
-printf "%s\n" "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
-sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
-test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
- for ac_prog in ar
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_AR+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
-printf "%s\n" "$AR" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$AR" && break
- done
-fi
-if test -z "$AR"; then
- ac_ct_AR=$AR
- for ac_prog in ar
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_AR+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
-printf "%s\n" "$ac_ct_AR" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "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:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$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}
-: ${AR_FLAGS=cr}
-
-
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
-printf %s "checking for archiver @FILE support... " >&6; }
-if test ${lt_cv_ar_at_file+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_ar_at_file=no
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- echo conftest.$ac_objext > conftest.lst
- lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
- { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
- (eval $lt_ar_try) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- 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
- (eval $lt_ar_try) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- if test 0 -ne "$ac_status"; then
- lt_cv_ar_at_file=@
- fi
- fi
- rm -f conftest.* libconftest.a
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
-printf "%s\n" "$lt_cv_ar_at_file" >&6; }
-
-if test no = "$lt_cv_ar_at_file"; then
- archiver_list_spec=
-else
- archiver_list_spec=$lt_cv_ar_at_file
-fi
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
-set dummy ${ac_tool_prefix}strip; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_STRIP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_STRIP="${ac_tool_prefix}strip"
- printf "%s\n" "$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
-STRIP=$ac_cv_prog_STRIP
-if test -n "$STRIP"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
-printf "%s\n" "$STRIP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_STRIP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_STRIP="strip"
- printf "%s\n" "$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_STRIP=$ac_cv_prog_ac_ct_STRIP
-if test -n "$ac_ct_STRIP"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
-printf "%s\n" "$ac_ct_STRIP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_STRIP" = x; then
- STRIP=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- STRIP=$ac_ct_STRIP
- fi
-else
- STRIP="$ac_cv_prog_STRIP"
-fi
-
-test -z "$STRIP" && STRIP=:
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_RANLIB="${ac_tool_prefix}ranlib"
- printf "%s\n" "$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
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-printf "%s\n" "$RANLIB" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
- ac_ct_RANLIB=$RANLIB
- # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_RANLIB"; then
- ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_RANLIB="ranlib"
- printf "%s\n" "$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_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-printf "%s\n" "$ac_ct_RANLIB" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_RANLIB" = x; then
- RANLIB=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- RANLIB=$ac_ct_RANLIB
- fi
-else
- RANLIB="$ac_cv_prog_RANLIB"
-fi
-
-test -z "$RANLIB" && RANLIB=:
-
-
-
-
-
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
- case $host_os in
- bitrig* | openbsd*)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
- ;;
- *)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
- ;;
- esac
- old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
-fi
-
-case $host_os in
- darwin*)
- lock_old_archive_extraction=yes ;;
- *)
- lock_old_archive_extraction=no ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
-printf %s "checking command to parse $NM output from $compiler object... " >&6; }
-if test ${lt_cv_sys_global_symbol_pipe+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix. What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[BCDEGRST]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
-
-# Define system-specific variables.
-case $host_os in
-aix*)
- symcode='[BCDT]'
- ;;
-cygwin* | mingw* | pw32* | cegcc*)
- symcode='[ABCDGISTW]'
- ;;
-hpux*)
- if test ia64 = "$host_cpu"; then
- symcode='[ABCDEGRST]'
- fi
- ;;
-irix* | nonstopux*)
- symcode='[BCDEGRST]'
- ;;
-osf*)
- symcode='[BCDEGQRST]'
- ;;
-solaris*)
- symcode='[BDRT]'
- ;;
-sco3.2v5*)
- symcode='[DT]'
- ;;
-sysv4.2uw2*)
- symcode='[DT]'
- ;;
-sysv5* | sco5v6* | unixware* | OpenUNIX*)
- symcode='[ABDT]'
- ;;
-sysv4)
- symcode='[DFNSTU]'
- ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-case `$NM -V 2>&1` in
-*GNU* | *'with BFD'*)
- 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"\
-$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"\
-$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=
-case $build_os in
-mingw*)
- opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
- ;;
-esac
-
-# Try without a prefix underscore, then with it.
-for ac_symprfx in "" "_"; do
-
- # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
- symxfrm="\\1 $ac_symprfx\\2 \\2"
-
- # 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,
- # 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=\"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'"
- fi
- lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
-
- # Check to see that the pipe works correctly.
- pipe_works=no
-
- rm -f conftest*
- cat > conftest.$ac_ext <<_LT_EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(void);
-void nm_test_func(void){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-_LT_EOF
-
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- # Now try to grab the symbols.
- nlist=conftest.nm
- $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5
- if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then
- # Try sorting and uniquifying the output.
- if sort "$nlist" | uniq > "$nlist"T; then
- mv -f "$nlist"T "$nlist"
- else
- rm -f "$nlist"T
- fi
-
- # Make sure that we snagged all the symbols we need.
- if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
- 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 can't be const, because runtime
- relocations are performed -- see ld's documentation on pseudo-relocs. */
-# define LT_DLSYM_CONST
-#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
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-_LT_EOF
- # Now generate the symbol file.
- eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
-
- cat <<_LT_EOF >> conftest.$ac_ext
-
-/* The mapping between symbol names and symbols. */
-LT_DLSYM_CONST struct {
- const char *name;
- void *address;
-}
-lt__PROGRAM__LTX_preloaded_symbols[] =
-{
- { "@PROGRAM@", (void *) 0 },
-_LT_EOF
- $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
- cat <<\_LT_EOF >> conftest.$ac_ext
- {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
- return lt__PROGRAM__LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-_LT_EOF
- # Now try linking the two files.
- mv conftest.$ac_objext conftstm.$ac_objext
- lt_globsym_save_LIBS=$LIBS
- lt_globsym_save_CFLAGS=$CFLAGS
- 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=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && test -s conftest$ac_exeext; then
- pipe_works=yes
- fi
- LIBS=$lt_globsym_save_LIBS
- CFLAGS=$lt_globsym_save_CFLAGS
- else
- echo "cannot find nm_test_func in $nlist" >&5
- fi
- else
- echo "cannot find nm_test_var in $nlist" >&5
- fi
- else
- echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
- fi
- else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- fi
- rm -rf conftest* conftst*
-
- # Do not use the global_symbol_pipe unless it works.
- if test yes = "$pipe_works"; then
- break
- else
- lt_cv_sys_global_symbol_pipe=
- fi
-done
-
-fi
-
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
- lt_cv_sys_global_symbol_to_cdecl=
-fi
-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5
-printf "%s\n" "failed" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5
-printf "%s\n" "ok" >&6; }
-fi
-
-# Response file support.
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- nm_file_list_spec='@'
-elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
- nm_file_list_spec='@'
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
-printf %s "checking for sysroot... " >&6; }
-
-# Check whether --with-sysroot was given.
-if test ${with_sysroot+y}
-then :
- withval=$with_sysroot;
-else $as_nop
- with_sysroot=no
-fi
-
-
-lt_sysroot=
-case $with_sysroot in #(
- yes)
- if test yes = "$GCC"; then
- lt_sysroot=`$CC --print-sysroot 2>/dev/null`
- fi
- ;; #(
- /*)
- lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
- ;; #(
- no|'')
- ;; #(
- *)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
-printf "%s\n" "$with_sysroot" >&6; }
- as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
- ;;
-esac
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
-printf "%s\n" "${lt_sysroot:-no}" >&6; }
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
-printf %s "checking for a working dd... " >&6; }
-if test ${ac_cv_path_lt_DD+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
-printf "%s\n" "$ac_cv_path_lt_DD" >&6; }
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
-printf %s "checking how to truncate binary pipes... " >&6; }
-if test ${lt_cv_truncate_bin+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
-printf "%s\n" "$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+y}
-then :
- enableval=$enable_libtool_lock;
-fi
-
-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 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
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- case `/usr/bin/file conftest.$ac_objext` in
- *ELF-32*)
- HPUX_IA64_MODE=32
- ;;
- *ELF-64*)
- HPUX_IA64_MODE=64
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-*-*-irix6*)
- # 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=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- if test yes = "$lt_cv_prog_gnu_ld"; then
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -melf32bsmip"
- ;;
- *N32*)
- LD="${LD-ld} -melf32bmipn32"
- ;;
- *64-bit*)
- LD="${LD-ld} -melf64bmip"
- ;;
- esac
- else
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -32"
- ;;
- *N32*)
- LD="${LD-ld} -n32"
- ;;
- *64-bit*)
- LD="${LD-ld} -64"
- ;;
- esac
- fi
- fi
- 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=$?
- printf "%s\n" "$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 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
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- case `/usr/bin/file conftest.o` in
- *32-bit*)
- case $host in
- x86_64-*kfreebsd*-gnu)
- LD="${LD-ld} -m elf_i386_fbsd"
- ;;
- x86_64-*linux*)
- case `/usr/bin/file conftest.o` in
- *x86-64*)
- LD="${LD-ld} -m elf32_x86_64"
- ;;
- *)
- LD="${LD-ld} -m elf_i386"
- ;;
- esac
- ;;
- powerpc64le-*linux*)
- LD="${LD-ld} -m elf32lppclinux"
- ;;
- powerpc64-*linux*)
- LD="${LD-ld} -m elf32ppclinux"
- ;;
- s390x-*linux*)
- LD="${LD-ld} -m elf_s390"
- ;;
- sparc64-*linux*)
- LD="${LD-ld} -m elf32_sparc"
- ;;
- esac
- ;;
- *64-bit*)
- case $host in
- x86_64-*kfreebsd*-gnu)
- LD="${LD-ld} -m elf_x86_64_fbsd"
- ;;
- x86_64-*linux*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- powerpcle-*linux*)
- LD="${LD-ld} -m elf64lppc"
- ;;
- powerpc-*linux*)
- LD="${LD-ld} -m elf64ppc"
- ;;
- s390*-*linux*|s390*-*tpf*)
- LD="${LD-ld} -m elf64_s390"
- ;;
- sparc*-*linux*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- esac
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-
-*-*-sco3.2v5*)
- # On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS=$CFLAGS
- CFLAGS="$CFLAGS -belf"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
-printf %s "checking whether the C compiler needs -belf... " >&6; }
-if test ${lt_cv_cc_needs_belf+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- lt_cv_cc_needs_belf=yes
-else $as_nop
- lt_cv_cc_needs_belf=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
-printf "%s\n" "$lt_cv_cc_needs_belf" >&6; }
- 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
- fi
- ;;
-*-*solaris*)
- # 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
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- case `/usr/bin/file conftest.o` in
- *64-bit*)
- case $lt_cv_prog_gnu_ld in
- yes*)
- case $host in
- i?86-*-solaris*|x86_64-*-solaris*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- sparc*-*-solaris*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- 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
- fi
- ;;
- *)
- if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
- LD="${LD-ld} -64"
- fi
- ;;
- esac
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-esac
-
-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.
-set dummy ${ac_tool_prefix}mt; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_MANIFEST_TOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$MANIFEST_TOOL"; then
- ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_MANIFEST_TOOL="${ac_tool_prefix}mt"
- printf "%s\n" "$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
-MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
-if test -n "$MANIFEST_TOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
-printf "%s\n" "$MANIFEST_TOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
- ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
- # Extract the first word of "mt", so it can be a program name with args.
-set dummy mt; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_MANIFEST_TOOL"; then
- ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_MANIFEST_TOOL="mt"
- printf "%s\n" "$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_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
-if test -n "$ac_ct_MANIFEST_TOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
-printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_MANIFEST_TOOL" = x; then
- MANIFEST_TOOL=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
- fi
-else
- MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
-fi
-
-test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
-printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
-if test ${lt_cv_path_mainfest_tool+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_path_mainfest_tool=no
- echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
- $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
- cat conftest.err >&5
- if $GREP 'Manifest Tool' conftest.out > /dev/null; then
- lt_cv_path_mainfest_tool=yes
- fi
- rm -f conftest*
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
-printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; }
-if test yes != "$lt_cv_path_mainfest_tool"; then
- MANIFEST_TOOL=:
-fi
-
-
-
-
-
-
- case $host_os in
- rhapsody* | darwin*)
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
-set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_DSYMUTIL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$DSYMUTIL"; then
- ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_DSYMUTIL="${ac_tool_prefix}dsymutil"
- printf "%s\n" "$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
-DSYMUTIL=$ac_cv_prog_DSYMUTIL
-if test -n "$DSYMUTIL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
-printf "%s\n" "$DSYMUTIL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_DSYMUTIL"; then
- ac_ct_DSYMUTIL=$DSYMUTIL
- # Extract the first word of "dsymutil", so it can be a program name with args.
-set dummy dsymutil; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_DSYMUTIL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_DSYMUTIL"; then
- ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_DSYMUTIL="dsymutil"
- printf "%s\n" "$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_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
-if test -n "$ac_ct_DSYMUTIL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
-printf "%s\n" "$ac_ct_DSYMUTIL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_DSYMUTIL" = x; then
- DSYMUTIL=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- DSYMUTIL=$ac_ct_DSYMUTIL
- fi
-else
- DSYMUTIL="$ac_cv_prog_DSYMUTIL"
-fi
-
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
-set dummy ${ac_tool_prefix}nmedit; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_NMEDIT+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$NMEDIT"; then
- ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_NMEDIT="${ac_tool_prefix}nmedit"
- printf "%s\n" "$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
-NMEDIT=$ac_cv_prog_NMEDIT
-if test -n "$NMEDIT"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
-printf "%s\n" "$NMEDIT" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_NMEDIT"; then
- ac_ct_NMEDIT=$NMEDIT
- # Extract the first word of "nmedit", so it can be a program name with args.
-set dummy nmedit; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_NMEDIT+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_NMEDIT"; then
- ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_NMEDIT="nmedit"
- printf "%s\n" "$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_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
-if test -n "$ac_ct_NMEDIT"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
-printf "%s\n" "$ac_ct_NMEDIT" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_NMEDIT" = x; then
- NMEDIT=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- NMEDIT=$ac_ct_NMEDIT
- fi
-else
- NMEDIT="$ac_cv_prog_NMEDIT"
-fi
-
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
-set dummy ${ac_tool_prefix}lipo; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_LIPO+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$LIPO"; then
- ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_LIPO="${ac_tool_prefix}lipo"
- printf "%s\n" "$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
-LIPO=$ac_cv_prog_LIPO
-if test -n "$LIPO"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
-printf "%s\n" "$LIPO" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_LIPO"; then
- ac_ct_LIPO=$LIPO
- # Extract the first word of "lipo", so it can be a program name with args.
-set dummy lipo; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_LIPO+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_LIPO"; then
- ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_LIPO="lipo"
- printf "%s\n" "$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_LIPO=$ac_cv_prog_ac_ct_LIPO
-if test -n "$ac_ct_LIPO"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
-printf "%s\n" "$ac_ct_LIPO" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_LIPO" = x; then
- LIPO=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- LIPO=$ac_ct_LIPO
- fi
-else
- LIPO="$ac_cv_prog_LIPO"
-fi
-
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
-set dummy ${ac_tool_prefix}otool; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_OTOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$OTOOL"; then
- ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_OTOOL="${ac_tool_prefix}otool"
- printf "%s\n" "$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
-OTOOL=$ac_cv_prog_OTOOL
-if test -n "$OTOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
-printf "%s\n" "$OTOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_OTOOL"; then
- ac_ct_OTOOL=$OTOOL
- # Extract the first word of "otool", so it can be a program name with args.
-set dummy otool; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_OTOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_OTOOL"; then
- ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_OTOOL="otool"
- printf "%s\n" "$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_OTOOL=$ac_cv_prog_ac_ct_OTOOL
-if test -n "$ac_ct_OTOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
-printf "%s\n" "$ac_ct_OTOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_OTOOL" = x; then
- OTOOL=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- OTOOL=$ac_ct_OTOOL
- fi
-else
- OTOOL="$ac_cv_prog_OTOOL"
-fi
-
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
-set dummy ${ac_tool_prefix}otool64; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_OTOOL64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$OTOOL64"; then
- ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_OTOOL64="${ac_tool_prefix}otool64"
- printf "%s\n" "$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
-OTOOL64=$ac_cv_prog_OTOOL64
-if test -n "$OTOOL64"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
-printf "%s\n" "$OTOOL64" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_OTOOL64"; then
- ac_ct_OTOOL64=$OTOOL64
- # Extract the first word of "otool64", so it can be a program name with args.
-set dummy otool64; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_OTOOL64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_OTOOL64"; then
- ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_OTOOL64="otool64"
- printf "%s\n" "$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_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
-if test -n "$ac_ct_OTOOL64"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
-printf "%s\n" "$ac_ct_OTOOL64" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_OTOOL64" = x; then
- OTOOL64=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- OTOOL64=$ac_ct_OTOOL64
- fi
-else
- OTOOL64="$ac_cv_prog_OTOOL64"
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
-printf %s "checking for -single_module linker flag... " >&6; }
-if test ${lt_cv_apple_cc_single_mod+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_apple_cc_single_mod=no
- 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
- # link flags.
- rm -rf libconftest.dylib*
- echo "int foo(void){return 1;}" > conftest.c
- echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
--dynamiclib -Wl,-single_module conftest.c" >&5
- $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
- -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
- _lt_result=$?
- # If there is a non-empty error log, and "single_module"
- # appears in it, assume the flag caused a linker warning
- if test -s conftest.err && $GREP single_module conftest.err; then
- 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 0 = "$_lt_result"; then
- lt_cv_apple_cc_single_mod=yes
- else
- cat conftest.err >&5
- fi
- rm -rf libconftest.dylib*
- rm -f conftest.*
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
-printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; }
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
-printf %s "checking for -exported_symbols_list linker flag... " >&6; }
-if test ${lt_cv_ld_exported_symbols_list+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_ld_exported_symbols_list=no
- save_LDFLAGS=$LDFLAGS
- echo "_main" > conftest.sym
- LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- lt_cv_ld_exported_symbols_list=yes
-else $as_nop
- lt_cv_ld_exported_symbols_list=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- LDFLAGS=$save_LDFLAGS
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
-printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; }
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
-printf %s "checking for -force_load linker flag... " >&6; }
-if test ${lt_cv_ld_force_load+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_ld_force_load=no
- cat > conftest.c << _LT_EOF
-int forced_loaded() { return 2;}
-_LT_EOF
- echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
- $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
- echo "$AR cr libconftest.a conftest.o" >&5
- $AR cr libconftest.a conftest.o 2>&5
- echo "$RANLIB libconftest.a" >&5
- $RANLIB libconftest.a 2>&5
- cat > conftest.c << _LT_EOF
-int main() { return 0;}
-_LT_EOF
- echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
- $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
- _lt_result=$?
- if test -s conftest.err && $GREP force_load conftest.err; then
- cat conftest.err >&5
- 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
- fi
- rm -f conftest.err libconftest.a conftest conftest.c
- rm -rf conftest.dSYM
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
-printf "%s\n" "$lt_cv_ld_force_load" >&6; }
- case $host_os in
- rhapsody* | darwin1.[012])
- _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
- darwin1.*)
- _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[912]*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- 10.[012][,.]*)
- _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- 10.*|11.*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- esac
- ;;
- esac
- if test yes = "$lt_cv_apple_cc_single_mod"; then
- _lt_dar_single_mod='$single_module'
- fi
- 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'
- fi
- if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
- _lt_dsymutil='~$DSYMUTIL $lib || :'
- else
- _lt_dsymutil=
- fi
- ;;
- 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_header= ac_cache=
-for ac_item in $ac_header_c_list
-do
- if test $ac_cache; then
- ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
- if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
- printf "%s\n" "#define $ac_item 1" >> confdefs.h
- fi
- ac_header= ac_cache=
- elif test $ac_header; then
- ac_cache=$ac_item
- else
- ac_header=$ac_item
- fi
-done
-
-
-
-
-
-
-
-
-if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
-then :
-
-printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
-"
-if test "x$ac_cv_header_dlfcn_h" = xyes
-then :
- printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h
-
-fi
-
-
-
-
-
-# Set options
-
-
-
- enable_dlopen=no
-
-
- enable_win32_dll=no
-
-
- # Check whether --enable-shared was given.
-if test ${enable_shared+y}
-then :
- enableval=$enable_shared; p=${PACKAGE-default}
- case $enableval in
- yes) enable_shared=yes ;;
- no) enable_shared=no ;;
- *)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac
-else $as_nop
- enable_shared=yes
-fi
-
-
-
-
-
-
-
-
-
- # Check whether --enable-static was given.
-if test ${enable_static+y}
-then :
- enableval=$enable_static; p=${PACKAGE-default}
- case $enableval in
- yes) enable_static=yes ;;
- no) enable_static=no ;;
- *)
- enable_static=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_static=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac
-else $as_nop
- enable_static=yes
-fi
-
-
-
-
-
-
-
-
-
-
-# Check whether --with-pic was given.
-if test ${with_pic+y}
-then :
- withval=$with_pic; lt_p=${PACKAGE-default}
- case $withval in
- yes|no) pic_mode=$withval ;;
- *)
- pic_mode=default
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for lt_pkg in $withval; do
- IFS=$lt_save_ifs
- if test "X$lt_pkg" = "X$lt_p"; then
- pic_mode=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac
-else $as_nop
- pic_mode=default
-fi
-
-
-
-
-
-
-
-
- # Check whether --enable-fast-install was given.
-if test ${enable_fast_install+y}
-then :
- enableval=$enable_fast_install; p=${PACKAGE-default}
- case $enableval in
- yes) enable_fast_install=yes ;;
- no) enable_fast_install=no ;;
- *)
- 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,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_fast_install=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac
-else $as_nop
- enable_fast_install=yes
-fi
-
-
-
-
-
-
-
-
- shared_archive_member_spec=
-case $host,$enable_shared in
-power*-*-aix[5-9]*,yes)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
-printf %s "checking which variant of shared library versioning to provide... " >&6; }
-
-# Check whether --with-aix-soname was given.
-if test ${with_aix_soname+y}
-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 $as_nop
- if test ${lt_cv_with_aix_soname+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_with_aix_soname=aix
-fi
-
- with_aix_soname=$lt_cv_with_aix_soname
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
-printf "%s\n" "$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
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-test -z "$LN_S" && LN_S="ln -s"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-if test -n "${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
-printf %s "checking for objdir... " >&6; }
-if test ${lt_cv_objdir+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
- lt_cv_objdir=.libs
-else
- # MS-DOS does not allow filenames that begin with a dot.
- lt_cv_objdir=_libs
-fi
-rmdir .libs 2>/dev/null
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
-printf "%s\n" "$lt_cv_objdir" >&6; }
-objdir=$lt_cv_objdir
-
-
-
-
-
-printf "%s\n" "#define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h
-
-
-
-
-case $host_os in
-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 set != "${COLLECT_NAMES+set}"; then
- COLLECT_NAMES=
- export COLLECT_NAMES
- fi
- ;;
-esac
-
-# Global variables:
-ofile=libtool
-can_build_shared=yes
-
-# 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
-
-old_CC=$CC
-old_CFLAGS=$CFLAGS
-
-# Set sane defaults for various variables
-test -z "$CC" && CC=cc
-test -z "$LTCC" && LTCC=$CC
-test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
-test -z "$LD" && LD=ld
-test -z "$ac_objext" && ac_objext=o
-
-func_cc_basename $compiler
-cc_basename=$func_cc_basename_result
-
-
-# Only perform the check for file, if the check method requires it
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-case $deplibs_check_method in
-file_magic*)
- if test "$file_magic_cmd" = '$MAGIC_CMD'; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
-printf %s "checking for ${ac_tool_prefix}file... " >&6; }
-if test ${lt_cv_path_MAGIC_CMD+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- case $MAGIC_CMD in
-[\\/*] | ?:[\\/]*)
- 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
- ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
- for ac_dir in $ac_dummy; do
- 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 -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
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- $EGREP "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS=$lt_save_ifs
- MAGIC_CMD=$lt_save_MAGIC_CMD
- ;;
-esac
-fi
-
-MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-if test -n "$MAGIC_CMD"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
-printf "%s\n" "$MAGIC_CMD" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-
-
-
-if test -z "$lt_cv_path_MAGIC_CMD"; then
- if test -n "$ac_tool_prefix"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5
-printf %s "checking for file... " >&6; }
-if test ${lt_cv_path_MAGIC_CMD+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- case $MAGIC_CMD in
-[\\/*] | ?:[\\/]*)
- 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
- ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
- for ac_dir in $ac_dummy; do
- 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 -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
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- $EGREP "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS=$lt_save_ifs
- MAGIC_CMD=$lt_save_MAGIC_CMD
- ;;
-esac
-fi
-
-MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-if test -n "$MAGIC_CMD"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
-printf "%s\n" "$MAGIC_CMD" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- else
- MAGIC_CMD=:
- fi
-fi
-
- fi
- ;;
-esac
-
-# Use C for the default configuration in the libtool script
-
-lt_save_CC=$CC
-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
-
-
-# Source file extension for C test sources.
-ac_ext=c
-
-# Object file extension for compiled C test sources.
-objext=o
-objext=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="int some_variable = 0;"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='int main(){return(0);}'
-
-
-
-
-
-
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-
-# Save the default compiler, since it gets overwritten when the other
-# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
-compiler_DEFAULT=$CC
-
-# save warnings/boilerplate of simple test code
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_compile_test_code" >conftest.$ac_ext
-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_compiler_boilerplate=`cat conftest.err`
-$RM conftest*
-
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_link_test_code" >conftest.$ac_ext
-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_linker_boilerplate=`cat conftest.err`
-$RM -r conftest*
-
-
-if test -n "$compiler"; then
-
-lt_prog_compiler_no_builtin_flag=
-
-if test yes = "$GCC"; then
- case $cc_basename in
- nvcc*)
- lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
- *)
- lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
- esac
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
-printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
-if test ${lt_cv_prog_compiler_rtti_exceptions+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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" ## 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
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- # The option is referenced via a variable to avoid confusing sed.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
- (eval "$lt_compile" 2>conftest.err)
- ac_status=$?
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- if (exit $ac_status) && test -s "$ac_outfile"; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings other than the usual output.
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_rtti_exceptions=yes
- fi
- fi
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
-printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
-
-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
- :
-fi
-
-fi
-
-
-
-
-
-
- lt_prog_compiler_wl=
-lt_prog_compiler_pic=
-lt_prog_compiler_static=
-
-
- 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 ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- lt_prog_compiler_static='-Bstatic'
- fi
- lt_prog_compiler_pic='-fPIC'
- ;;
-
- amigaos*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- lt_prog_compiler_pic='-fPIC'
- ;;
- 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'.
- lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
- ;;
- esac
- ;;
-
- beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
- # PIC is the default for these OSes.
- ;;
-
- 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).
- # 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*)
- # PIC is the default on this platform
- # Common symbols not allowed in MH_DYLIB files
- lt_prog_compiler_pic='-fno-common'
- ;;
-
- haiku*)
- # PIC is the default for Haiku.
- # The "-static" flag exists, but is broken.
- lt_prog_compiler_static=
- ;;
-
- hpux*)
- # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
- # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
- # sets the default TLS model and affects inlining.
- case $host_cpu in
- hppa*64*)
- # +Z the default
- ;;
- *)
- lt_prog_compiler_pic='-fPIC'
- ;;
- esac
- ;;
-
- interix[3-9]*)
- # Interix 3.x gcc -fpic/-fPIC options generate broken code.
- # Instead, we relocate shared libraries at runtime.
- ;;
-
- msdosdjgpp*)
- # Just because we use GCC doesn't mean we suddenly get shared libraries
- # on systems that don't support them.
- lt_prog_compiler_can_build_shared=no
- enable_shared=no
- ;;
-
- *nto* | *qnx*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- lt_prog_compiler_pic='-fPIC -shared'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- lt_prog_compiler_pic=-Kconform_pic
- fi
- ;;
-
- *)
- lt_prog_compiler_pic='-fPIC'
- ;;
- esac
-
- case $cc_basename in
- nvcc*) # Cuda Compiler Driver 2.2
- lt_prog_compiler_wl='-Xlinker '
- if test -n "$lt_prog_compiler_pic"; then
- lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
- fi
- ;;
- esac
- else
- # PORTME Check for flag to pass linker flags through the system compiler.
- case $host_os in
- aix*)
- lt_prog_compiler_wl='-Wl,'
- if test ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- lt_prog_compiler_static='-Bstatic'
- else
- lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
- 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*)
- lt_prog_compiler_wl='-Wl,'
- # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
- # not for PA HP-UX.
- case $host_cpu in
- hppa*64*|ia64*)
- # +Z the default
- ;;
- *)
- lt_prog_compiler_pic='+Z'
- ;;
- esac
- # Is there a better lt_prog_compiler_static that works with the bundled CC?
- lt_prog_compiler_static='$wl-a ${wl}archive'
- ;;
-
- irix5* | irix6* | nonstopux*)
- lt_prog_compiler_wl='-Wl,'
- # PIC (with -KPIC) is the default.
- lt_prog_compiler_static='-non_shared'
- ;;
-
- linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- case $cc_basename in
- # old Intel for x86_64, which still supported -KPIC.
- ecc*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-static'
- ;;
- # flang / f18. f95 an alias for gfortran or flang on Debian
- flang* | f18* | f95*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fPIC'
- lt_prog_compiler_static='-static'
- ;;
- # icc used to be incompatible with GCC.
- # ICC 10 doesn't accept -KPIC any more.
- icc* | ifort*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fPIC'
- lt_prog_compiler_static='-static'
- ;;
- # Lahey Fortran 8.1.
- lf95*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='--shared'
- lt_prog_compiler_static='--static'
- ;;
- nagfor*)
- # NAG Fortran compiler
- lt_prog_compiler_wl='-Wl,-Wl,,'
- 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)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fpic'
- lt_prog_compiler_static='-Bstatic'
- ;;
- ccc*)
- lt_prog_compiler_wl='-Wl,'
- # All Alpha code is PIC.
- lt_prog_compiler_static='-non_shared'
- ;;
- xl* | bgxl* | bgf* | mpixl*)
- # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-qpic'
- lt_prog_compiler_static='-qstaticlink'
- ;;
- *)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
- # Sun Fortran 8.3 passes all unrecognized flags to the linker
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- lt_prog_compiler_wl=''
- ;;
- *Sun\ F* | *Sun*Fortran*)
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- lt_prog_compiler_wl='-Qoption ld '
- ;;
- *Sun\ C*)
- # Sun C 5.9
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- lt_prog_compiler_wl='-Wl,'
- ;;
- *Intel*\ [CF]*Compiler*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fPIC'
- lt_prog_compiler_static='-static'
- ;;
- *Portland\ Group*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fpic'
- lt_prog_compiler_static='-Bstatic'
- ;;
- esac
- ;;
- esac
- ;;
-
- newsos6)
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- *nto* | *qnx*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- lt_prog_compiler_pic='-fPIC -shared'
- ;;
-
- osf3* | osf4* | osf5*)
- lt_prog_compiler_wl='-Wl,'
- # All OSF/1 code is PIC.
- lt_prog_compiler_static='-non_shared'
- ;;
-
- rdos*)
- lt_prog_compiler_static='-non_shared'
- ;;
-
- solaris*)
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- case $cc_basename in
- f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
- lt_prog_compiler_wl='-Qoption ld ';;
- *)
- lt_prog_compiler_wl='-Wl,';;
- esac
- ;;
-
- sunos4*)
- lt_prog_compiler_wl='-Qoption ld '
- lt_prog_compiler_pic='-PIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- sysv4 | sysv4.2uw2* | sysv4.3*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- lt_prog_compiler_pic='-Kconform_pic'
- lt_prog_compiler_static='-Bstatic'
- fi
- ;;
-
- sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- unicos*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_can_build_shared=no
- ;;
-
- uts4*)
- lt_prog_compiler_pic='-pic'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- *)
- lt_prog_compiler_can_build_shared=no
- ;;
- esac
- fi
-
-case $host_os in
- # For platforms that do not support PIC, -DPIC is meaningless:
- *djgpp*)
- lt_prog_compiler_pic=
- ;;
- *)
- lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
- ;;
-esac
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
-printf %s "checking for $compiler option to produce PIC... " >&6; }
-if test ${lt_cv_prog_compiler_pic+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
-printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; }
-lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
-
-#
-# Check to make sure the PIC flag actually works.
-#
-if test -n "$lt_prog_compiler_pic"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
-printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
-if test ${lt_cv_prog_compiler_pic_works+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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" ## 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
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- # The option is referenced via a variable to avoid confusing sed.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
- (eval "$lt_compile" 2>conftest.err)
- ac_status=$?
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- if (exit $ac_status) && test -s "$ac_outfile"; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings other than the usual output.
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_pic_works=yes
- fi
- fi
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
-printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; }
-
-if test yes = "$lt_cv_prog_compiler_pic_works"; then
- case $lt_prog_compiler_pic in
- "" | " "*) ;;
- *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
- esac
-else
- lt_prog_compiler_pic=
- lt_prog_compiler_can_build_shared=no
-fi
-
-fi
-
-
-
-
-
-
-
-
-
-
-
-#
-# Check to make sure the static flag actually works.
-#
-wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
-printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
-if test ${lt_cv_prog_compiler_static_works+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_static_works=no
- 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
- # The linker can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- # Append any errors to the config.log.
- cat conftest.err 1>&5
- $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if diff conftest.exp conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_static_works=yes
- fi
- else
- lt_cv_prog_compiler_static_works=yes
- fi
- fi
- $RM -r conftest*
- LDFLAGS=$save_LDFLAGS
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
-printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; }
-
-if test yes = "$lt_cv_prog_compiler_static_works"; then
- :
-else
- lt_prog_compiler_static=
-fi
-
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if test ${lt_cv_prog_compiler_c_o+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_c_o=no
- $RM -r conftest 2>/dev/null
- mkdir conftest
- cd conftest
- mkdir out
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- lt_compiler_flag="-o out/conftest2.$ac_objext"
- # 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
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
- (eval "$lt_compile" 2>out/conftest.err)
- ac_status=$?
- cat out/conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- if (exit $ac_status) && test -s out/conftest2.$ac_objext
- then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
- $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
- if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_c_o=yes
- fi
- fi
- chmod u+w . 2>&5
- $RM conftest*
- # SGI C++ compiler will create directory out/ii_files/ for
- # template instantiation
- test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
- $RM out/* && rmdir out
- cd ..
- $RM -r conftest
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
-printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; }
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if test ${lt_cv_prog_compiler_c_o+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_c_o=no
- $RM -r conftest 2>/dev/null
- mkdir conftest
- cd conftest
- mkdir out
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- lt_compiler_flag="-o out/conftest2.$ac_objext"
- # 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
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
- (eval "$lt_compile" 2>out/conftest.err)
- ac_status=$?
- cat out/conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- if (exit $ac_status) && test -s out/conftest2.$ac_objext
- then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
- $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
- if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_c_o=yes
- fi
- fi
- chmod u+w . 2>&5
- $RM conftest*
- # SGI C++ compiler will create directory out/ii_files/ for
- # template instantiation
- test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
- $RM out/* && rmdir out
- cd ..
- $RM -r conftest
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
-printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; }
-
-
-
-
-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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
-printf %s "checking if we can lock with hard links... " >&6; }
- hard_links=yes
- $RM conftest*
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- touch conftest.a
- ln conftest.a conftest.b 2>&5 || hard_links=no
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
-printf "%s\n" "$hard_links" >&6; }
- if test no = "$hard_links"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
-printf "%s\n" "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
- need_locks=warn
- fi
-else
- need_locks=no
-fi
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
-printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
-
- runpath_var=
- allow_undefined_flag=
- always_export_symbols=no
- archive_cmds=
- archive_expsym_cmds=
- compiler_needs_object=no
- enable_shared_with_static_runtimes=no
- export_dynamic_flag_spec=
- export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
- hardcode_automatic=no
- hardcode_direct=no
- hardcode_direct_absolute=no
- hardcode_libdir_flag_spec=
- hardcode_libdir_separator=
- hardcode_minus_L=no
- hardcode_shlibpath_var=unsupported
- inherit_rpath=no
- link_all_deplibs=unknown
- module_cmds=
- module_expsym_cmds=
- old_archive_from_new_cmds=
- old_archive_from_expsyms_cmds=
- thread_safe_flag_spec=
- whole_archive_flag_spec=
- # include_expsyms should be a list of space-separated symbols to be *always*
- # 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'.
- 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
- # the symbol is explicitly referenced. Since portable code cannot
- # rely on this symbol name, it's probably fine to never include it in
- # preloaded symbol tables.
- # Exclude shared library initialization/finalization symbols.
- extract_expsyms_cmds=
-
- case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
- # 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 yes != "$GCC"; then
- with_gnu_ld=no
- fi
- ;;
- interix*)
- # we just hope/assume this is gcc and not c89 (= MSVC++)
- with_gnu_ld=yes
- ;;
- openbsd* | bitrig*)
- with_gnu_ld=no
- ;;
- linux* | k*bsd*-gnu | gnu*)
- link_all_deplibs=no
- ;;
- esac
-
- ld_shlibs=yes
-
- # 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 yes = "$with_gnu_ld"; then
- case $host_os in
- aix*)
- # The AIX port of GNU ld has always aspired to compatibility
- # with the native linker. However, as the warning in the GNU ld
- # block says, versions before 2.19.5* couldn't really create working
- # shared libraries, regardless of the interface used.
- case `$LD -v 2>&1` in
- *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
- *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
- *\ \(GNU\ Binutils\)\ [3-9]*) ;;
- *)
- lt_use_gnu_ld_interface=yes
- ;;
- esac
- ;;
- *)
- lt_use_gnu_ld_interface=yes
- ;;
- esac
- fi
-
- if test yes = "$lt_use_gnu_ld_interface"; then
- # If archive_cmds runs LD, not CC, wlarc should be empty
- 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'
- # 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'
- else
- whole_archive_flag_spec=
- fi
- supports_anon_versioning=no
- 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 ...
- *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
- *\ 2.11.*) ;; # other 2.11 versions
- *) supports_anon_versioning=yes ;;
- esac
-
- # See if GNU ld supports shared libraries.
- case $host_os in
- aix[3-9]*)
- # On AIX/PPC, the GNU linker is very broken
- if test ia64 != "$host_cpu"; then
- ld_shlibs=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.19, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support. If you
-*** really care for shared libraries, you may want to install binutils
-*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
-*** You will then need to restart the configuration process.
-
-_LT_EOF
- fi
- ;;
-
- amigaos*)
- 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_expsym_cmds=''
- ;;
- m68k)
- archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- ;;
- esac
- ;;
-
- beos*)
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- 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'
- else
- ld_shlibs=no
- fi
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- # _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'
- allow_undefined_flag=unsupported
- always_export_symbols=no
- enable_shared_with_static_runtimes=yes
- export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
- 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, 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'
- 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'
- # 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'
- ;;
-
- gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
- tmp_diet=no
- 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 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'
- 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'
- tmp_addflag=' $pic_flag -Mnomain' ;;
- ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
- tmp_addflag=' -i_dynamic' ;;
- efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
- tmp_addflag=' -i_dynamic -nofor_main' ;;
- ifc* | ifort*) # Intel Fortran compiler
- tmp_addflag=' -nofor_main' ;;
- 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'
- 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'
- 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'
-
- 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'
- 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'
- archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
- 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'
- fi
- ;;
- esac
- else
- ld_shlibs=no
- fi
- ;;
-
- netbsd* | netbsdelf*-gnu)
- 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'
- fi
- ;;
-
- solaris*)
- if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
- ld_shlibs=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_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'
- else
- ld_shlibs=no
- fi
- ;;
-
- sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
- case `$LD -v 2>&1` in
- *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
- ld_shlibs=no
- cat <<_LT_EOF 1>&2
-
-*** 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
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
- ;;
- *)
- # For security reasons, it is highly recommended that you always
- # use absolute paths for naming shared libraries, and exclude the
- # 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'
- else
- ld_shlibs=no
- fi
- ;;
- esac
- ;;
-
- sunos4*)
- archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- wlarc=
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- *)
- 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'
- else
- ld_shlibs=no
- fi
- ;;
- esac
-
- if test no = "$ld_shlibs"; then
- runpath_var=
- hardcode_libdir_flag_spec=
- export_dynamic_flag_spec=
- whole_archive_flag_spec=
- fi
- else
- # PORTME fill in a description of your system's linker (not GNU ld)
- case $host_os in
- aix3*)
- allow_undefined_flag=unsupported
- always_export_symbols=yes
- archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
- # Note: this linker hardcodes the directories in LIBPATH if there
- # are no directories specified by -L.
- hardcode_minus_L=yes
- 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
- fi
- ;;
-
- aix[4-9]*)
- 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=
- else
- # If we're using GNU nm, then we don't want the "-C" option.
- # -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) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
- else
- 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
- # 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 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
-
- exp_sym_flag='-bexport'
- no_entry_flag='-bnoentry'
- fi
-
- # When large executables or shared objects are built, AIX ld can
- # have problems creating the table of contents. If linking a library
- # or program results in "error TOC overflow" add -mminimal-toc to
- # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
- # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
- archive_cmds=''
- hardcode_direct=yes
- hardcode_direct_absolute=yes
- hardcode_libdir_separator=':'
- link_all_deplibs=yes
- 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 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`
- if test -f "$collect2name" &&
- strings "$collect2name" | $GREP resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- :
- else
- # We have old collect2
- hardcode_direct=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- hardcode_minus_L=yes
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_libdir_separator=
- fi
- ;;
- esac
- shared_flag='-shared'
- 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 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 yes = "$aix_use_runtimelinking"; then
- shared_flag='$wl-G'
- else
- 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'
- # 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,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 set = "${lt_cv_aix_libpath+set}"; then
- aix_libpath=$lt_cv_aix_libpath
-else
- if test ${lt_cv_aix_libpath_+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-
- lt_aix_libpath_sed='
- /Import File Strings/,/^$/ {
- /^0/ {
- s/^0 *\([^ ]*\) *$/\1/
- p
- }
- }'
- lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- # Check for a 64-bit object if we didn't find anything.
- if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- fi
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_=/usr/lib:/lib
- fi
-
-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 -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 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"
- else
- # Determine the default libpath from the value encoded in an
- # empty executable.
- if test set = "${lt_cv_aix_libpath+set}"; then
- aix_libpath=$lt_cv_aix_libpath
-else
- if test ${lt_cv_aix_libpath_+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-
- lt_aix_libpath_sed='
- /Import File Strings/,/^$/ {
- /^0/ {
- s/^0 *\([^ ]*\) *$/\1/
- p
- }
- }'
- lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- # Check for a 64-bit object if we didn't find anything.
- if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- fi
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_=/usr/lib:/lib
- fi
-
-fi
-
- aix_libpath=$lt_cv_aix_libpath_
-fi
-
- 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 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'
- else
- # Exported symbols can be pulled into shared objects from archives
- whole_archive_flag_spec='$convenience'
- fi
- archive_cmds_need_lc=yes
- 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
- ;;
-
- amigaos*)
- 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_expsym_cmds=''
- ;;
- m68k)
- archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- ;;
- esac
- ;;
-
- bsdi[45]*)
- export_dynamic_flag_spec=-rdynamic
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- case $cc_basename in
- cl*)
- # Native MSVC
- hardcode_libdir_flag_spec=' '
- allow_undefined_flag=unsupported
- always_export_symbols=yes
- file_list_spec='@'
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- shrext_cmds=.dll
- # FIXME: Setting linknames here is a bad hack.
- 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
- exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
- export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
- # 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'
- ;;
- *)
- # Assume MSVC wrapper
- hardcode_libdir_flag_spec=' '
- allow_undefined_flag=unsupported
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- 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.
- old_archive_from_new_cmds='true'
- # FIXME: Should let the user specify the lib program.
- old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
- enable_shared_with_static_runtimes=yes
- ;;
- esac
- ;;
-
- darwin* | rhapsody*)
-
-
- archive_cmds_need_lc=no
- hardcode_direct=no
- hardcode_automatic=yes
- hardcode_shlibpath_var=unsupported
- 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
- case $cc_basename in
- ifort*|nagfor*) _lt_dar_can_shared=yes ;;
- *) _lt_dar_can_shared=$GCC ;;
- esac
- 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"
-
- else
- ld_shlibs=no
- fi
-
- ;;
-
- dgux*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
- # support. Future versions do this automatically, but an explicit c++rt0.o
- # does not break anything, and helps significantly (at the cost of a little
- # extra space).
- freebsd2.2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- # Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2.*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | dragonfly*)
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- hpux9*)
- 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 "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
- fi
- 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'
- ;;
-
- hpux10*)
- 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 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'
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L=yes
- fi
- ;;
-
- hpux11*)
- 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'
- ;;
- 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+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'
- ;;
- ia64*)
- archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- *)
-
- # Older versions of the 11.00 compiler do not understand -b yet
- # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
-printf %s "checking if $CC understands -b... " >&6; }
-if test ${lt_cv_prog_compiler__b+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler__b=no
- 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
- # The linker can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- # Append any errors to the config.log.
- cat conftest.err 1>&5
- $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if diff conftest.exp conftest.er2 >/dev/null; then
- lt_cv_prog_compiler__b=yes
- fi
- else
- lt_cv_prog_compiler__b=yes
- fi
- fi
- $RM -r conftest*
- LDFLAGS=$save_LDFLAGS
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
-printf "%s\n" "$lt_cv_prog_compiler__b" >&6; }
-
-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
-
- ;;
- esac
- fi
- if test no = "$with_gnu_ld"; then
- hardcode_libdir_flag_spec='$wl+b $wl$libdir'
- hardcode_libdir_separator=:
-
- case $host_cpu in
- hppa*64*|ia64*)
- hardcode_direct=no
- hardcode_shlibpath_var=no
- ;;
- *)
- hardcode_direct=yes
- hardcode_direct_absolute=yes
- 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
- ;;
- esac
- fi
- ;;
-
- irix5* | irix6* | nonstopux*)
- 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.
- # This should be the same for all languages, so no per-tag cache variable.
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
-printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
-if test ${lt_cv_irix_exported_symbol+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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; }
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- lt_cv_irix_exported_symbol=yes
-else $as_nop
- lt_cv_irix_exported_symbol=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- LDFLAGS=$save_LDFLAGS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
-printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; }
- 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
- link_all_deplibs=no
- 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'
- fi
- archive_cmds_need_lc='no'
- hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
- hardcode_libdir_separator=:
- inherit_rpath=yes
- link_all_deplibs=yes
- ;;
-
- 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* | netbsdelf*-gnu)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
- else
- archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
- fi
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- 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_separator=:
- hardcode_shlibpath_var=no
- ;;
-
- *nto* | *qnx*)
- ;;
-
- 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__`"; 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'
- else
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- hardcode_libdir_flag_spec='$wl-rpath,$libdir'
- fi
- else
- ld_shlibs=no
- fi
- ;;
-
- 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
- ;;
-
- osf3*)
- 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'
- fi
- archive_cmds_need_lc='no'
- hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
- hardcode_libdir_separator=:
- ;;
-
- osf4* | osf5*) # as osf3* with the addition of -msym flag
- 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_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'
-
- # Both c and cxx compiler support -rpath directly
- hardcode_libdir_flag_spec='-rpath $libdir'
- fi
- archive_cmds_need_lc='no'
- hardcode_libdir_separator=:
- ;;
-
- solaris*)
- no_undefined_flag=' -z defs'
- 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'
- 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_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'
- ;;
- *)
- 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'
- ;;
- esac
- fi
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_shlibpath_var=no
- case $host_os in
- 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 is careful enough not to reorder.
- # Supported since Solaris 2.6 (maybe 2.5.1?)
- 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
- ;;
- esac
- link_all_deplibs=yes
- ;;
-
- sunos4*)
- 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'
- else
- archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
- fi
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- sysv4)
- case $host_vendor in
- sni)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes # is this really true???
- ;;
- siemens)
- ## LD is ld it makes a PLAMLIB
- ## CC just makes a GrossModule.
- archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- reload_cmds='$CC -r -o $output$reload_objs'
- hardcode_direct=no
- ;;
- motorola)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=no #Motorola manual says yes, but my tests say they lie
- ;;
- esac
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
- ;;
-
- sysv4.3*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- export_dynamic_flag_spec='-Bexport'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ld_shlibs=yes
- fi
- ;;
-
- sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
- no_undefined_flag='$wl-z,text'
- archive_cmds_need_lc=no
- hardcode_shlibpath_var=no
- runpath_var='LD_RUN_PATH'
-
- 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'
- fi
- ;;
-
- sysv5* | sco3.2v5* | sco5v6*)
- # 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'
- archive_cmds_need_lc=no
- hardcode_shlibpath_var=no
- hardcode_libdir_flag_spec='$wl-R,$libdir'
- hardcode_libdir_separator=':'
- link_all_deplibs=yes
- export_dynamic_flag_spec='$wl-Bexport'
- runpath_var='LD_RUN_PATH'
-
- 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'
- fi
- ;;
-
- uts4*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- *)
- ld_shlibs=no
- ;;
- esac
-
- if test sni = "$host_vendor"; then
- case $host in
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- export_dynamic_flag_spec='$wl-Blargedynsym'
- ;;
- esac
- fi
- fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
-printf "%s\n" "$ld_shlibs" >&6; }
-test no = "$ld_shlibs" && can_build_shared=no
-
-with_gnu_ld=$with_gnu_ld
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-#
-# Do we need to explicitly link libc?
-#
-case "x$archive_cmds_need_lc" in
-x|xyes)
- # Assume -lc should be added
- archive_cmds_need_lc=yes
-
- if test yes,yes = "$GCC,$enable_shared"; then
- case $archive_cmds in
- *'~'*)
- # FIXME: we may have to deal with multi-command sequences.
- ;;
- '$CC '*)
- # Test whether the compiler implicitly links with -lc since on some
- # systems, -lgcc has to come before -lc. If gcc already passes -lc
- # to ld, don't add -lc before -lgcc.
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
-printf %s "checking whether -lc should be explicitly linked in... " >&6; }
-if test ${lt_cv_archive_cmds_need_lc+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- $RM conftest*
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } 2>conftest.err; then
- soname=conftest
- lib=conftest
- libobjs=conftest.$ac_objext
- deplibs=
- wl=$lt_prog_compiler_wl
- pic_flag=$lt_prog_compiler_pic
- compiler_flags=-v
- linker_flags=-v
- verstring=
- output_objdir=.
- libname=conftest
- lt_save_allow_undefined_flag=$allow_undefined_flag
- allow_undefined_flag=
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
- (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- then
- lt_cv_archive_cmds_need_lc=no
- else
- lt_cv_archive_cmds_need_lc=yes
- fi
- allow_undefined_flag=$lt_save_allow_undefined_flag
- else
- cat conftest.err 1>&5
- fi
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
-printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; }
- archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
- ;;
- esac
- fi
- ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
-printf %s "checking dynamic linker characteristics... " >&6; }
-
-if test yes = "$GCC"; then
- case $host_os in
- 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' ;;
- 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
- *\;*)
- # if the path contains ";" then we assume it to be the separator
- # otherwise default to the standard path separator (i.e. ":") - it is
- # assumed that no part of a normal pathname contains ";" but that should
- # okay in the real world where ";" in dirpaths is itself problematic.
- lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
- ;;
- *)
- lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
- ;;
- esac
- # Ok, now we have the path, separated by spaces, we can step through it
- # 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`
- # ...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"
- 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;
- 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;
- } else {
- lt_count--;
- }
- }
- }
- }
- if (lt_foo != "") { lt_freq[lt_foo]++; }
- if (lt_freq[lt_foo] == 1) { print lt_foo; }
-}'`
- # AWK program above erroneously prepends '/' to C:/dos/paths
- # 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'` ;;
- esac
- sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
-else
- sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-fi
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-shrext_cmds=.so
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-need_lib_prefix=unknown
-hardcode_into_libs=no
-
-# when you set need_version to no, make sure it does not cause -set_version
-# 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'
- 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'
- ;;
-
-aix[4-9]*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- hardcode_into_libs=yes
- 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'
- 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
- # 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
- :
- else
- can_build_shared=no
- fi
- ;;
- esac
- # 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.
- 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'
- ;;
- 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'
- ;;
- 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
- ;;
-
-amigaos*)
- case $host_cpu in
- 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'
- ;;
- 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%'\''`; $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'
- dynamic_linker="$host_os ld.so"
- shlibpath_var=LIBRARY_PATH
- ;;
-
-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'
- 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"
- sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
- # the default ld.so.conf also contains /usr/contrib/lib and
- # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
- # libtool to hard-code these into programs
- ;;
-
-cygwin* | mingw* | pw32* | cegcc*)
- version_type=windows
- shrext_cmds=.dll
- need_version=no
- need_lib_prefix=no
-
- case $GCC,$cc_basename in
- yes,*)
- # 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'\''`~
- 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'
- shlibpath_overrides_runpath=yes
-
- 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'
-
- 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'
- ;;
- 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'
- ;;
- esac
- dynamic_linker='Win32 ld.exe'
- ;;
-
- *,cl*)
- # Native MSVC
- libname_spec='$name'
- soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
- library_names_spec='$libname.dll.lib'
-
- case $build_os in
- mingw*)
- sys_lib_search_path_spec=
- lt_save_ifs=$IFS
- IFS=';'
- for lt_path in $LIB
- do
- IFS=$lt_save_ifs
- # Let DOS variable expansion print the short 8.3 style file name.
- lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
- sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
- done
- IFS=$lt_save_ifs
- # Convert to MSYS style.
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
- ;;
- cygwin*)
- # Convert to unix form, then to dos form, then back to unix form
- # but this time dos style (no spaces!) so that the unix form looks
- # like /cygdrive/c/PROGRA~1:/cygdr...
- sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
- sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
- 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
- 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'`
- else
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
- fi
- # FIXME: find the short name or the path components, as spaces are
- # common. (e.g. "Program Files" -> "PROGRA~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'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname'
- postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $RM \$dlpath'
- shlibpath_overrides_runpath=yes
- dynamic_linker='Win32 link.exe'
- ;;
-
- *)
- # Assume MSVC wrapper
- library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
- dynamic_linker='Win32 ld.exe'
- ;;
- esac
- # FIXME: first we should search . and the directory the executable is in
- shlibpath_var=PATH
- ;;
-
-darwin* | rhapsody*)
- dynamic_linker="$host_os dyld"
- 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'
- shlibpath_overrides_runpath=yes
- shlibpath_var=DYLD_LIBRARY_PATH
- shrext_cmds='`test .$module = .yes && echo .so || 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'
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-freebsd* | dragonfly*)
- # DragonFly does not have aout. When/if they implement a new
- # versioning mechanism, adjust this.
- if test -x /usr/bin/objformat; then
- objformat=`/usr/bin/objformat`
- else
- case $host_os in
- freebsd[23].*) objformat=aout ;;
- *) objformat=elf ;;
- esac
- fi
- version_type=freebsd-$objformat
- case $version_type in
- freebsd-elf*)
- 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'
- need_version=yes
- ;;
- esac
- shlibpath_var=LD_LIBRARY_PATH
- case $host_os in
- freebsd2.*)
- shlibpath_overrides_runpath=yes
- ;;
- freebsd3.[01]* | freebsdelf3.[01]*)
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
- freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
- freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
- *) # from 4.6 on, and DragonFly
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
- esac
- ;;
-
-haiku*)
- version_type=linux # correct to gnu/linux during the next big refactor
- 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'
- shlibpath_var=LIBRARY_PATH
- shlibpath_overrides_runpath=no
- sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
- hardcode_into_libs=yes
- ;;
-
-hpux9* | hpux10* | hpux11*)
- # Give a soname corresponding to the major version so that dld.sl refuses to
- # link against other versions.
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- case $host_cpu in
- ia64*)
- shrext_cmds='.so'
- hardcode_into_libs=yes
- 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 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
- ;;
- hppa*64*)
- shrext_cmds='.sl'
- hardcode_into_libs=yes
- 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'
- sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
- ;;
- *)
- shrext_cmds='.sl'
- 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'
- ;;
- esac
- # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
- postinstall_cmds='chmod 555 $lib'
- # or fails outright, so override atomically:
- install_override_mode=555
- ;;
-
-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'
- dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
-
-irix5* | irix6* | nonstopux*)
- case $host_os in
- nonstopux*) version_type=nonstopux ;;
- *)
- 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
- fi ;;
- 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'
- case $host_os in
- irix5* | nonstopux*)
- libsuff= shlibsuff=
- ;;
- *)
- case $LD in # libtool.m4 will add one of these switches to LD
- *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
- libsuff= shlibsuff= libmagic=32-bit;;
- *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
- libsuff=32 shlibsuff=N32 libmagic=N32;;
- *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
- libsuff=64 shlibsuff=64 libmagic=64-bit;;
- *) libsuff= shlibsuff= libmagic=never-match;;
- esac
- ;;
- 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"
- hardcode_into_libs=yes
- ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-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'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
-
- # Some binutils ld are patched to set DT_RUNPATH
- if test ${lt_cv_shlibpath_overrides_runpath+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_shlibpath_overrides_runpath=no
- save_LDFLAGS=$LDFLAGS
- save_libdir=$libdir
- eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
- LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null
-then :
- lt_cv_shlibpath_overrides_runpath=yes
-fi
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- LDFLAGS=$save_LDFLAGS
- libdir=$save_libdir
-
-fi
-
- shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
-
- # 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
-
- # 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"
- fi
-
- # We used to test for /lib/ld.so.1 and disable shared libraries on
- # powerpc, because MkLinux only supported shared libraries with the
- # GNU dynamic linker. Since this was broken with cross compilers,
- # most powerpc-linux boxes support dynamic linking these days and
- # people can always --disable-shared, the test was removed, and we
- # assume the GNU/Linux dynamic linker is in use.
- 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'
- 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'
- dynamic_linker='NetBSD ld.elf_so'
- fi
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- ;;
-
-*nto* | *qnx*)
- 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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- dynamic_linker='ldqnx.so'
- ;;
-
-openbsd* | bitrig*)
- version_type=sunos
- sys_lib_dlsearch_path_spec=/usr/lib
- need_lib_prefix=no
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
- need_version=no
- else
- 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'
- version_type=windows
- shrext_cmds=.dll
- need_version=no
- need_lib_prefix=no
- # 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=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'
- 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
- ;;
-
-rdos*)
- dynamic_linker=no
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- # ldd complains unless libraries are executable
- postinstall_cmds='chmod +x $lib'
- ;;
-
-sunos4*)
- version_type=sunos
- 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 yes = "$with_gnu_ld"; then
- need_lib_prefix=no
- fi
- need_version=yes
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- case $host_vendor in
- sni)
- shlibpath_overrides_runpath=no
- need_lib_prefix=no
- runpath_var=LD_RUN_PATH
- ;;
- siemens)
- need_lib_prefix=no
- ;;
- motorola)
- need_lib_prefix=no
- need_version=no
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
- ;;
- esac
- ;;
-
-sysv4*MP*)
- 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'
- shlibpath_var=LD_LIBRARY_PATH
- fi
- ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- 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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- 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'
- case $host_os in
- sco3.2v5*)
- sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
- ;;
- esac
- fi
- sys_lib_dlsearch_path_spec='/usr/lib'
- ;;
-
-tpf*)
- # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
- 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'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
-
-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'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-*)
- dynamic_linker=no
- ;;
-esac
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
-printf "%s\n" "$dynamic_linker" >&6; }
-test no = "$dynamic_linker" && can_build_shared=no
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test yes = "$GCC"; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-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 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
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
-printf %s "checking how to hardcode library paths into programs... " >&6; }
-hardcode_action=
-if test -n "$hardcode_libdir_flag_spec" ||
- test -n "$runpath_var" ||
- test yes = "$hardcode_automatic"; then
-
- # We can hardcode non-existent directories.
- 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" &&
- test no != "$hardcode_minus_L"; then
- # Linking always hardcodes the temporary library directory.
- hardcode_action=relink
- else
- # We can link without hardcoding, and we can hardcode nonexisting dirs.
- hardcode_action=immediate
- fi
-else
- # We cannot hardcode anything, or else we can only hardcode existing
- # directories.
- hardcode_action=unsupported
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
-printf "%s\n" "$hardcode_action" >&6; }
-
-if test relink = "$hardcode_action" ||
- test yes = "$inherit_rpath"; then
- # Fast installation is not supported
- enable_fast_install=no
-elif test yes = "$shlibpath_overrides_runpath" ||
- test no = "$enable_shared"; then
- # Fast installation is not necessary
- enable_fast_install=needless
-fi
-
-
-
-
-
-
- if test yes != "$enable_dlopen"; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
- lt_cv_dlopen=no
- lt_cv_dlopen_libs=
-
- case $host_os in
- beos*)
- 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_libs=
- ;;
-
- cygwin*)
- lt_cv_dlopen=dlopen
- lt_cv_dlopen_libs=
- ;;
-
- darwin*)
- # if libdl is installed we need to link against it
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-printf %s "checking for dlopen in -ldl... " >&6; }
-if test ${ac_cv_lib_dl_dlopen+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $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. */
-char dlopen ();
-int
-main (void)
-{
-return dlopen ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dl_dlopen=yes
-else $as_nop
- ac_cv_lib_dl_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-printf "%s\n" "$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
-else $as_nop
-
- lt_cv_dlopen=dyld
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
-
-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
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
-printf %s "checking for shl_load in -ldld... " >&6; }
-if test ${ac_cv_lib_dld_shl_load+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $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. */
-char shl_load ();
-int
-main (void)
-{
-return shl_load ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dld_shl_load=yes
-else $as_nop
- ac_cv_lib_dld_shl_load=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
-printf "%s\n" "$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
-else $as_nop
- ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
-if test "x$ac_cv_func_dlopen" = xyes
-then :
- lt_cv_dlopen=dlopen
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-printf %s "checking for dlopen in -ldl... " >&6; }
-if test ${ac_cv_lib_dl_dlopen+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $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. */
-char dlopen ();
-int
-main (void)
-{
-return dlopen ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dl_dlopen=yes
-else $as_nop
- ac_cv_lib_dl_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-printf "%s\n" "$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
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
-printf %s "checking for dlopen in -lsvld... " >&6; }
-if test ${ac_cv_lib_svld_dlopen+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsvld $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. */
-char dlopen ();
-int
-main (void)
-{
-return dlopen ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_svld_dlopen=yes
-else $as_nop
- ac_cv_lib_svld_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
-printf "%s\n" "$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
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
-printf %s "checking for dld_link in -ldld... " >&6; }
-if test ${ac_cv_lib_dld_dld_link+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $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. */
-char dld_link ();
-int
-main (void)
-{
-return dld_link ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dld_dld_link=yes
-else $as_nop
- ac_cv_lib_dld_dld_link=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
-printf "%s\n" "$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
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
- ;;
- esac
-
- 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 yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
- save_LDFLAGS=$LDFLAGS
- wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
- save_LIBS=$LIBS
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
-printf %s "checking whether a program can dlopen itself... " >&6; }
-if test ${lt_cv_dlopen_self+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test yes = "$cross_compiling"; then :
- lt_cv_dlopen_self=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<_LT_EOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-/* 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))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else
- {
- if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- else puts (dlerror ());
- }
- /* dlclose (self); */
- }
- else
- puts (dlerror ());
-
- return status;
-}
-_LT_EOF
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
- (./conftest; exit; ) >&5 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
-printf "%s\n" "$lt_cv_dlopen_self" >&6; }
-
- if test yes = "$lt_cv_dlopen_self"; then
- wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
-printf %s "checking whether a statically linked program can dlopen itself... " >&6; }
-if test ${lt_cv_dlopen_self_static+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test yes = "$cross_compiling"; then :
- lt_cv_dlopen_self_static=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<_LT_EOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-/* 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))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else
- {
- if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- else puts (dlerror ());
- }
- /* dlclose (self); */
- }
- else
- puts (dlerror ());
-
- return status;
-}
-_LT_EOF
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
- (./conftest; exit; ) >&5 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self_static=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
-printf "%s\n" "$lt_cv_dlopen_self_static" >&6; }
- fi
-
- CPPFLAGS=$save_CPPFLAGS
- LDFLAGS=$save_LDFLAGS
- LIBS=$save_LIBS
- ;;
- esac
-
- case $lt_cv_dlopen_self in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case $lt_cv_dlopen_self_static in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-striplib=
-old_striplib=
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
-printf %s "checking whether stripping libraries is possible... " >&6; }
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
-# FIXME - insert some real tests, host_os isn't really good enough
- case $host_os in
- darwin*)
- if test -n "$STRIP"; then
- striplib="$STRIP -x"
- old_striplib="$STRIP -S"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- fi
- ;;
- *)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- ;;
- esac
-fi
-
-
-
-
-
-
-
-
-
-
-
-
- # Report what library types will actually be built
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
-printf %s "checking if libtool supports shared libraries... " >&6; }
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
-printf "%s\n" "$can_build_shared" >&6; }
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
-printf %s "checking whether to build shared libraries... " >&6; }
- 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 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 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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
-printf "%s\n" "$enable_shared" >&6; }
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
-printf %s "checking whether to build static libraries... " >&6; }
- # Make sure either enable_shared or enable_static is yes.
- test yes = "$enable_shared" || enable_static=yes
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
-printf "%s\n" "$enable_static" >&6; }
-
-
-
-
-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
-
-CC=$lt_save_CC
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ac_config_commands="$ac_config_commands libtool"
-
-
-
-
-# Only expand once:
-
-
-
-
-# Check for library functions that SQLite can optionally use.
-ac_fn_c_check_func "$LINENO" "fdatasync" "ac_cv_func_fdatasync"
-if test "x$ac_cv_func_fdatasync" = xyes
-then :
- printf "%s\n" "#define HAVE_FDATASYNC 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "usleep" "ac_cv_func_usleep"
-if test "x$ac_cv_func_usleep" = xyes
-then :
- printf "%s\n" "#define HAVE_USLEEP 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "fullfsync" "ac_cv_func_fullfsync"
-if test "x$ac_cv_func_fullfsync" = xyes
-then :
- printf "%s\n" "#define HAVE_FULLFSYNC 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r"
-if test "x$ac_cv_func_localtime_r" = xyes
-then :
- printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "gmtime_r" "ac_cv_func_gmtime_r"
-if test "x$ac_cv_func_gmtime_r" = xyes
-then :
- printf "%s\n" "#define HAVE_GMTIME_R 1" >>confdefs.h
-
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
-printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
-if test ${ac_cv_c_undeclared_builtin_options+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_save_CFLAGS=$CFLAGS
- ac_cv_c_undeclared_builtin_options='cannot detect'
- for ac_arg in '' -fno-builtin; do
- CFLAGS="$ac_save_CFLAGS $ac_arg"
- # This test program should *not* compile successfully.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-(void) strchr;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else $as_nop
- # This test program should compile successfully.
- # No library function is consistently available on
- # freestanding implementations, so test against a dummy
- # declaration. Include always-available headers on the
- # off chance that they somehow elicit warnings.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <float.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stddef.h>
-extern void ac_decl (int, char *);
-
-int
-main (void)
-{
-(void) ac_decl (0, (char *) 0);
- (void) ac_decl;
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- if test x"$ac_arg" = x
-then :
- ac_cv_c_undeclared_builtin_options='none needed'
-else $as_nop
- ac_cv_c_undeclared_builtin_options=$ac_arg
-fi
- break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- done
- CFLAGS=$ac_save_CFLAGS
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5
-printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; }
- case $ac_cv_c_undeclared_builtin_options in #(
- 'cannot detect') :
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot make $CC report undeclared builtins
-See \`config.log' for more details" "$LINENO" 5; } ;; #(
- 'none needed') :
- ac_c_undeclared_builtin_options='' ;; #(
- *) :
- ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;;
-esac
-
-ac_fn_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS"
-if test "x$ac_cv_have_decl_strerror_r" = xyes
-then :
- ac_have_decl=1
-else $as_nop
- ac_have_decl=0
-fi
-printf "%s\n" "#define HAVE_DECL_STRERROR_R $ac_have_decl" >>confdefs.h
-
-
-if test $ac_cv_have_decl_strerror_r = yes; then
- # For backward compatibility's sake, define HAVE_STRERROR_R.
- # (We used to run AC_CHECK_FUNCS_ONCE for strerror_r, as well
- # as AC_CHECK_DECLS_ONCE.)
-
-printf "%s\n" "#define HAVE_STRERROR_R 1" >>confdefs.h
-
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5
-printf %s "checking whether strerror_r returns char *... " >&6; }
-if test ${ac_cv_func_strerror_r_char_p+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- ac_cv_func_strerror_r_char_p=no
- if test $ac_cv_have_decl_strerror_r = yes; then
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <string.h>
-int
-main (void)
-{
-
- char buf[100];
- char x = *strerror_r (0, buf, sizeof buf);
- char *p = strerror_r (0, buf, sizeof buf);
- return !p || x;
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_func_strerror_r_char_p=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-
- fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5
-printf "%s\n" "$ac_cv_func_strerror_r_char_p" >&6; }
-if test $ac_cv_func_strerror_r_char_p = yes; then
-
-printf "%s\n" "#define STRERROR_R_CHAR_P 1" >>confdefs.h
-
-fi
-
-
-ac_config_files="$ac_config_files Makefile sqlite3.pc"
-
-BUILD_CFLAGS=
-
-
-#-------------------------------------------------------------------------
-# Two options to enable readline compatible libraries:
-#
-# --enable-editline
-# --enable-readline
-#
-# Both are enabled by default. If, after command line processing both are
-# still enabled, the script searches for editline first and automatically
-# disables readline if it is found. So, to use readline explicitly, the
-# user must pass "--disable-editline". To disable command line editing
-# support altogether, "--disable-editline --disable-readline".
-#
-# When searching for either library, check for headers before libraries
-# as some distros supply packages that contain libraries but not header
-# files, which come as a separate development package.
-#
-# Check whether --enable-editline was given.
-if test ${enable_editline+y}
-then :
- enableval=$enable_editline;
-fi
-
-# Check whether --enable-readline was given.
-if test ${enable_readline+y}
-then :
- enableval=$enable_readline;
-fi
-
-
-if test x"$enable_editline" != xno
-then :
-
- for ac_header in editline/readline.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "editline/readline.h" "ac_cv_header_editline_readline_h" "$ac_includes_default"
-if test "x$ac_cv_header_editline_readline_h" = xyes
-then :
- printf "%s\n" "#define HAVE_EDITLINE_READLINE_H 1" >>confdefs.h
-
- sLIBS=$LIBS
- LIBS=""
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing readline" >&5
-printf %s "checking for library containing readline... " >&6; }
-if test ${ac_cv_search_readline+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char readline ();
-int
-main (void)
-{
-return readline ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' edit
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib -ltinfo $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_readline=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_readline+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_readline+y}
-then :
-
-else $as_nop
- ac_cv_search_readline=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_readline" >&5
-printf "%s\n" "$ac_cv_search_readline" >&6; }
-ac_res=$ac_cv_search_readline
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-
-printf "%s\n" "#define HAVE_EDITLINE 1" >>confdefs.h
-
- READLINE_LIBS="$LIBS -ltinfo"
- enable_readline=no
-
-fi
-
- { ac_cv_search_readline=; unset ac_cv_search_readline;}
- LIBS=$sLIBS
-
-fi
-
-done
-
-fi
-
-if test x"$enable_readline" != xno
-then :
-
- for ac_header in readline/readline.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default"
-if test "x$ac_cv_header_readline_readline_h" = xyes
-then :
- printf "%s\n" "#define HAVE_READLINE_READLINE_H 1" >>confdefs.h
-
- sLIBS=$LIBS
- LIBS=""
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5
-printf %s "checking for library containing tgetent... " >&6; }
-if test ${ac_cv_search_tgetent+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char tgetent ();
-int
-main (void)
-{
-return tgetent ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' termcap curses ncurses ncursesw
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_tgetent=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_tgetent+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_tgetent+y}
-then :
-
-else $as_nop
- ac_cv_search_tgetent=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5
-printf "%s\n" "$ac_cv_search_tgetent" >&6; }
-ac_res=$ac_cv_search_tgetent
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing readline" >&5
-printf %s "checking for library containing readline... " >&6; }
-if test ${ac_cv_search_readline+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char readline ();
-int
-main (void)
-{
-return readline ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' readline edit
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_readline=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_readline+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_readline+y}
-then :
-
-else $as_nop
- ac_cv_search_readline=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_readline" >&5
-printf "%s\n" "$ac_cv_search_readline" >&6; }
-ac_res=$ac_cv_search_readline
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-
-printf "%s\n" "#define HAVE_READLINE 1" >>confdefs.h
-
- READLINE_LIBS=$LIBS
-
-fi
-
- LIBS=$sLIBS
-
-fi
-
-done
-
-fi
-
-
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-threadsafe
-#
-# Check whether --enable-threadsafe was given.
-if test ${enable_threadsafe+y}
-then :
- enableval=$enable_threadsafe;
-else $as_nop
- enable_threadsafe=yes
-fi
-
-if test x"$enable_threadsafe" == "xno"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0"
-else
- BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5
-printf %s "checking for library containing pthread_create... " >&6; }
-if test ${ac_cv_search_pthread_create+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char pthread_create ();
-int
-main (void)
-{
-return pthread_create ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' pthread
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_pthread_create=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_pthread_create+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_pthread_create+y}
-then :
-
-else $as_nop
- ac_cv_search_pthread_create=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5
-printf "%s\n" "$ac_cv_search_pthread_create" >&6; }
-ac_res=$ac_cv_search_pthread_create
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_mutexattr_init" >&5
-printf %s "checking for library containing pthread_mutexattr_init... " >&6; }
-if test ${ac_cv_search_pthread_mutexattr_init+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char pthread_mutexattr_init ();
-int
-main (void)
-{
-return pthread_mutexattr_init ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' pthread
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_pthread_mutexattr_init=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_pthread_mutexattr_init+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_pthread_mutexattr_init+y}
-then :
-
-else $as_nop
- ac_cv_search_pthread_mutexattr_init=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_mutexattr_init" >&5
-printf "%s\n" "$ac_cv_search_pthread_mutexattr_init" >&6; }
-ac_res=$ac_cv_search_pthread_mutexattr_init
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-dynamic-extensions
-#
-# Check whether --enable-dynamic-extensions was given.
-if test ${enable_dynamic_extensions+y}
-then :
- enableval=$enable_dynamic_extensions;
-else $as_nop
- enable_dynamic_extensions=yes
-fi
-
-if test x"$enable_dynamic_extensions" != "xno"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
-printf %s "checking for library containing dlopen... " >&6; }
-if test ${ac_cv_search_dlopen+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char dlopen ();
-int
-main (void)
-{
-return dlopen ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' dl
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_dlopen=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_dlopen+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_dlopen+y}
-then :
-
-else $as_nop
- ac_cv_search_dlopen=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
-printf "%s\n" "$ac_cv_search_dlopen" >&6; }
-ac_res=$ac_cv_search_dlopen
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-else
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_OMIT_LOAD_EXTENSION=1"
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for whether to support dynamic extensions" >&5
-printf %s "checking for whether to support dynamic extensions... " >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dynamic_extensions" >&5
-printf "%s\n" "$enable_dynamic_extensions" >&6; }
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-math
-#
-# Check whether --enable-math was given.
-if test ${enable_math+y}
-then :
- enableval=$enable_math;
-else $as_nop
- enable_math=yes
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking SQL math functions" >&5
-printf %s "checking SQL math functions... " >&6; }
-if test x"$enable_math" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
-printf "%s\n" "enabled" >&6; }
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing ceil" >&5
-printf %s "checking for library containing ceil... " >&6; }
-if test ${ac_cv_search_ceil+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char ceil ();
-int
-main (void)
-{
-return ceil ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' m
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_ceil=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_ceil+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_ceil+y}
-then :
-
-else $as_nop
- ac_cv_search_ceil=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ceil" >&5
-printf "%s\n" "$ac_cv_search_ceil" >&6; }
-ac_res=$ac_cv_search_ceil
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
-printf "%s\n" "disabled" >&6; }
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts4
-#
-# Check whether --enable-fts4 was given.
-if test ${enable_fts4+y}
-then :
- enableval=$enable_fts4;
-else $as_nop
- enable_fts4=yes
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking FTS4 extension" >&5
-printf %s "checking FTS4 extension... " >&6; }
-if test x"$enable_fts4" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS4"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
-printf "%s\n" "enabled" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
-printf "%s\n" "disabled" >&6; }
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts3
-#
-# Check whether --enable-fts3 was given.
-if test ${enable_fts3+y}
-then :
- enableval=$enable_fts3;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking FTS3 extension" >&5
-printf %s "checking FTS3 extension... " >&6; }
-if test x"$enable_fts3" = "xyes" -a x"$enable_fts4" = "xno"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS3"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
-printf "%s\n" "enabled" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
-printf "%s\n" "disabled" >&6; }
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts5
-#
-# Check whether --enable-fts5 was given.
-if test ${enable_fts5+y}
-then :
- enableval=$enable_fts5;
-else $as_nop
- enable_fts5=yes
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking FTS5 extension" >&5
-printf %s "checking FTS5 extension... " >&6; }
-if test x"$enable_fts5" = "xyes"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
-printf "%s\n" "enabled" >&6; }
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
-printf %s "checking for library containing log... " >&6; }
-if test ${ac_cv_search_log+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char log ();
-int
-main (void)
-{
-return log ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' m
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_log=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_log+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_log+y}
-then :
-
-else $as_nop
- ac_cv_search_log=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_log" >&5
-printf "%s\n" "$ac_cv_search_log" >&6; }
-ac_res=$ac_cv_search_log
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS5"
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
-printf "%s\n" "disabled" >&6; }
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-rtree
-#
-# Check whether --enable-rtree was given.
-if test ${enable_rtree+y}
-then :
- enableval=$enable_rtree;
-else $as_nop
- enable_rtree=yes
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking RTREE extension" >&5
-printf %s "checking RTREE extension... " >&6; }
-if test x"$enable_rtree" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
-printf "%s\n" "enabled" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
-printf "%s\n" "disabled" >&6; }
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-session
-#
-# Check whether --enable-session was given.
-if test ${enable_session+y}
-then :
- enableval=$enable_session;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking Session extension" >&5
-printf %s "checking Session extension... " >&6; }
-if test x"$enable_session" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
-printf "%s\n" "enabled" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
-printf "%s\n" "disabled" >&6; }
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-debug
-#
-# Check whether --enable-debug was given.
-if test ${enable_debug+y}
-then :
- enableval=$enable_debug;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking Build type" >&5
-printf %s "checking Build type... " >&6; }
-if test x"$enable_debug" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_DEBUG -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
- CFLAGS="-g -O0"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: debug" >&5
-printf "%s\n" "debug" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: release" >&5
-printf "%s\n" "release" >&6; }
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-static-shell
-#
-# Check whether --enable-static-shell was given.
-if test ${enable_static_shell+y}
-then :
- enableval=$enable_static_shell;
-else $as_nop
- enable_static_shell=yes
-fi
-
-if test x"$enable_static_shell" = "xyes"; then
- EXTRA_SHELL_OBJ=sqlite3-sqlite3.$OBJEXT
-else
- EXTRA_SHELL_OBJ=libsqlite3.la
-fi
-
-#-----------------------------------------------------------------------
-
-ac_fn_c_check_func "$LINENO" "posix_fallocate" "ac_cv_func_posix_fallocate"
-if test "x$ac_cv_func_posix_fallocate" = xyes
-then :
- printf "%s\n" "#define HAVE_POSIX_FALLOCATE 1" >>confdefs.h
-
-fi
-
- for ac_header in zlib.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_zlib_h" = xyes
-then :
- printf "%s\n" "#define HAVE_ZLIB_H 1" >>confdefs.h
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing deflate" >&5
-printf %s "checking for library containing deflate... " >&6; }
-if test ${ac_cv_search_deflate+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char deflate ();
-int
-main (void)
-{
-return deflate ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' z
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_deflate=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_deflate+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_deflate+y}
-then :
-
-else $as_nop
- ac_cv_search_deflate=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_deflate" >&5
-printf "%s\n" "$ac_cv_search_deflate" >&6; }
-ac_res=$ac_cv_search_deflate
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_HAVE_ZLIB"
-fi
-
-
-fi
-
-done
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing system" >&5
-printf %s "checking for library containing system... " >&6; }
-if test ${ac_cv_search_system+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char system ();
-int
-main (void)
-{
-return system ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in ''
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_system=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_system+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_system+y}
-then :
-
-else $as_nop
- ac_cv_search_system=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_system" >&5
-printf "%s\n" "$ac_cv_search_system" >&6; }
-ac_res=$ac_cv_search_system
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-else $as_nop
- SHELL_CFLAGS="-DSQLITE_NOHAVE_SYSTEM"
-fi
-
-
-
-#-----------------------------------------------------------------------
-# UPDATE: Maybe it's better if users just set CFLAGS before invoking
-# configure. This option doesn't really add much...
-#
-# --enable-tempstore
-#
-# AC_ARG_ENABLE(tempstore, [AS_HELP_STRING(
-# [--enable-tempstore],
-# [in-memory temporary tables (never, no, yes, always) [default=no]])],
-# [], [enable_tempstore=no])
-# AC_MSG_CHECKING([for whether or not to store temp tables in-memory])
-# case "$enable_tempstore" in
-# never ) TEMP_STORE=0 ;;
-# no ) TEMP_STORE=1 ;;
-# always ) TEMP_STORE=3 ;;
-# yes ) TEMP_STORE=3 ;;
-# * )
-# TEMP_STORE=1
-# enable_tempstore=yes
-# ;;
-# esac
-# AC_MSG_RESULT($enable_tempstore)
-# AC_SUBST(TEMP_STORE)
-#-----------------------------------------------------------------------
-
-cat >confcache <<\_ACEOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs, see configure's option --config-cache.
-# It is not useful on other systems. If it contains results you don't
-# want to keep, you may remove or edit it.
-#
-# config.status only pays attention to the cache file if you give it
-# the --recheck option to rerun configure.
-#
-# `ac_cv_env_foo' variables (set or unset) will be overridden when
-# loading this file, other *unset* `ac_cv_foo' will be assigned the
-# following values.
-
-_ACEOF
-
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, we kill variables containing newlines.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(
- for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
- eval ac_val=\$$ac_var
- case $ac_val in #(
- *${as_nl}*)
- case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
- esac
- case $ac_var in #(
- _ | IFS | as_nl) ;; #(
- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
- *) { eval $ac_var=; unset $ac_var;} ;;
- esac ;;
- esac
- done
-
- (set) 2>&1 |
- case $as_nl`(ac_space=' '; set) 2>&1` in #(
- *${as_nl}ac_space=\ *)
- # `set' does not quote correctly, so add quotes: double-quote
- # substitution turns \\\\ into \\, and sed turns \\ into \.
- sed -n \
- "s/'/'\\\\''/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
- ;; #(
- *)
- # `set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
- ;;
- esac |
- sort
-) |
- sed '
- /^ac_cv_env_/b end
- t clear
- :clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/
- t end
- s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
- :end' >>confcache
-if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
- if test -w "$cache_file"; then
- if test "x$cache_file" != "x/dev/null"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-printf "%s\n" "$as_me: updating cache $cache_file" >&6;}
- if test ! -f "$cache_file" || test -h "$cache_file"; then
- cat confcache >"$cache_file"
- else
- case $cache_file in #(
- */* | ?:*)
- mv -f confcache "$cache_file"$$ &&
- mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
- mv -f confcache "$cache_file" ;;
- esac
- fi
- fi
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;}
- fi
-fi
-rm -f confcache
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-# Transform confdefs.h into DEFS.
-# Protect against shell expansion while executing Makefile rules.
-# Protect against Makefile macro expansion.
-#
-# If the first sed substitution is executed (which looks for macros that
-# take arguments), then branch to the quote section. Otherwise,
-# look for a macro that doesn't take arguments.
-ac_script='
-:mline
-/\\$/{
- N
- s,\\\n,,
- b mline
-}
-t clear
-:clear
-s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
-t quote
-s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
-t quote
-b any
-:quote
-s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
-s/\[/\\&/g
-s/\]/\\&/g
-s/\$/$$/g
-H
-:any
-${
- g
- s/^\n//
- s/\n/ /g
- p
-}
-'
-DEFS=`sed -n "$ac_script" confdefs.h`
-
-
-ac_libobjs=
-ac_ltlibobjs=
-U=
-for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
- # 1. Remove the extension, and $U if already installed.
- ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
- ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"`
- # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
- # will be set to the directory where LIBOBJS objects are built.
- as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
- as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
-done
-LIBOBJS=$ac_libobjs
-
-LTLIBOBJS=$ac_ltlibobjs
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
-printf %s "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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5
-printf "%s\n" "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__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
-
-: "${CONFIG_STATUS=./config.status}"
-ac_write_fail=0
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;}
-as_write_fail=0
-cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-# Run this file to recreate the current configuration.
-# Compiler output produced by configure, useful for debugging
-# configure, is in config.log if it exists.
-
-debug=false
-ac_cs_recheck=false
-ac_cs_silent=false
-
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-as_nop=:
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else $as_nop
- case `(set -o) 2>/dev/null` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac
-fi
-
-
-
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
-as_nl='
-'
-export as_nl
-IFS=" "" $as_nl"
-
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
-if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
-
-# The user is always right.
-if ${PATH_SEPARATOR+false} :; 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
-
-
-# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
- as_myself=$0
-fi
-if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
- exit 1
-fi
-
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
- fi
- printf "%s\n" "$as_me: error: $2" >&2
- as_fn_exit $as_status
-} # as_fn_error
-
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
- return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
- set +e
- as_fn_set_status $1
- exit $1
-} # as_fn_exit
-
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
- { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
-then :
- eval 'as_fn_append ()
- {
- eval $1+=\$2
- }'
-else $as_nop
- as_fn_append ()
- {
- eval $1=\$$1\$2
- }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
-then :
- eval 'as_fn_arith ()
- {
- as_val=$(( $* ))
- }'
-else $as_nop
- as_fn_arith ()
- {
- as_val=`expr "$@" || test $? -eq 1`
- }
-fi # as_fn_arith
-
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
- test "X`expr 00001 : '.*\(...\)'`" = X001; then
- as_expr=expr
-else
- as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
- as_basename=basename
-else
- as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
- as_dirname=dirname
-else
- as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
- X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{
- s//\1/
- q
- }
- /^X\/\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\/\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
- case `echo 'xy\c'` in
- *c*) ECHO_T=' ';; # ECHO_T is single tab character.
- xy) ECHO_C='\c';;
- *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
- ECHO_T=' ';;
- esac;;
-*)
- ECHO_N='-n';;
-esac
-
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
- rm -f conf$$.dir/conf$$.file
-else
- rm -f conf$$.dir
- mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
- if ln -s conf$$.file conf$$ 2>/dev/null; then
- as_ln_s='ln -s'
- # ... but there are two gotchas:
- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
- elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
- else
- as_ln_s='cp -pR'
- fi
-else
- as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
- case $as_dir in #(
- -*) as_dir=./$as_dir;;
- esac
- test -d "$as_dir" || eval $as_mkdir_p || {
- as_dirs=
- while :; do
- case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
- *) as_qdir=$as_dir;;
- esac
- as_dirs="'$as_qdir' $as_dirs"
- as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_dir" : 'X\(//\)[^/]' \| \
- X"$as_dir" : 'X\(//\)$' \| \
- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- test -d "$as_dir" && break
- done
- test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-if mkdir -p . 2>/dev/null; then
- as_mkdir_p='mkdir -p "$as_dir"'
-else
- test -d ./-p && rmdir ./-p
- as_mkdir_p=false
-fi
-
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-exec 6>&1
-## ----------------------------------- ##
-## Main body of $CONFIG_STATUS script. ##
-## ----------------------------------- ##
-_ASEOF
-test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# Save the log message, to keep $0 and so on meaningful, and to
-# report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling.
-ac_log="
-This file was extended by sqlite $as_me 3.46.1, which was
-generated by GNU Autoconf 2.71. Invocation command line was
-
- CONFIG_FILES = $CONFIG_FILES
- CONFIG_HEADERS = $CONFIG_HEADERS
- CONFIG_LINKS = $CONFIG_LINKS
- CONFIG_COMMANDS = $CONFIG_COMMANDS
- $ $0 $@
-
-on `(hostname || uname -n) 2>/dev/null | sed 1q`
-"
-
-_ACEOF
-
-case $ac_config_files in *"
-"*) set x $ac_config_files; shift; ac_config_files=$*;;
-esac
-
-
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-# Files that config.status was made for.
-config_files="$ac_config_files"
-config_commands="$ac_config_commands"
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-ac_cs_usage="\
-\`$as_me' instantiates files and other configuration actions
-from templates according to the current configuration. Unless the files
-and actions are specified as TAGs, all are instantiated by default.
-
-Usage: $0 [OPTION]... [TAG]...
-
- -h, --help print this help, then exit
- -V, --version print version number and configuration settings, then exit
- --config print configuration, then exit
- -q, --quiet, --silent
- do not print progress messages
- -d, --debug don't remove temporary files
- --recheck update $as_me by reconfiguring in the same conditions
- --file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
-
-Configuration files:
-$config_files
-
-Configuration commands:
-$config_commands
-
-Report bugs to <http://www.sqlite.org>."
-
-_ACEOF
-ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
-ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"`
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config='$ac_cs_config_escaped'
-ac_cs_version="\\
-sqlite config.status 3.46.1
-configured by $0, generated by GNU Autoconf 2.71,
- with options \\"\$ac_cs_config\\"
-
-Copyright (C) 2021 Free Software Foundation, Inc.
-This config.status script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it."
-
-ac_pwd='$ac_pwd'
-srcdir='$srcdir'
-INSTALL='$INSTALL'
-MKDIR_P='$MKDIR_P'
-AWK='$AWK'
-test -n "\$AWK" || AWK=awk
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# The default lists apply if the user does not specify any file.
-ac_need_defaults=:
-while test $# != 0
-do
- case $1 in
- --*=?*)
- ac_option=`expr "X$1" : 'X\([^=]*\)='`
- ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
- ac_shift=:
- ;;
- --*=)
- ac_option=`expr "X$1" : 'X\([^=]*\)='`
- ac_optarg=
- ac_shift=:
- ;;
- *)
- ac_option=$1
- ac_optarg=$2
- ac_shift=shift
- ;;
- esac
-
- case $ac_option in
- # Handling of the options.
- -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
- ac_cs_recheck=: ;;
- --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
- printf "%s\n" "$ac_cs_version"; exit ;;
- --config | --confi | --conf | --con | --co | --c )
- printf "%s\n" "$ac_cs_config"; exit ;;
- --debug | --debu | --deb | --de | --d | -d )
- debug=: ;;
- --file | --fil | --fi | --f )
- $ac_shift
- case $ac_optarg in
- *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
- '') as_fn_error $? "missing file argument" ;;
- esac
- as_fn_append CONFIG_FILES " '$ac_optarg'"
- ac_need_defaults=false;;
- --he | --h | --help | --hel | -h )
- printf "%s\n" "$ac_cs_usage"; exit ;;
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil | --si | --s)
- ac_cs_silent=: ;;
-
- # This is an error.
- -*) as_fn_error $? "unrecognized option: \`$1'
-Try \`$0 --help' for more information." ;;
-
- *) as_fn_append ac_config_targets " $1"
- ac_need_defaults=false ;;
-
- esac
- shift
-done
-
-ac_configure_extra_args=
-
-if $ac_cs_silent; then
- exec 6>/dev/null
- ac_configure_extra_args="$ac_configure_extra_args --silent"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-if \$ac_cs_recheck; then
- set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
- shift
- \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6
- CONFIG_SHELL='$SHELL'
- export CONFIG_SHELL
- exec "\$@"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-exec 5>>config.log
-{
- echo
- sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
- printf "%s\n" "$ac_log"
-} >&5
-
-_ACEOF
-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
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-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"`'
-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"`'
-host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
-host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
-host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
-build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
-build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
-build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
-SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
-Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
-GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
-EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
-FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
-LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
-NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
-LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
-max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
-ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
-exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
-lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
-lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
-lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
-lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
-lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
-reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
-reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
-OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
-deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
-file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
-file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
-want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
-DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
-sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
-AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
-AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
-archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
-STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
-RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
-old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
-old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
-old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
-lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
-CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
-CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
-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"`'
-lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
-lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
-need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
-MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
-DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
-NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
-LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
-OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
-OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
-libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
-shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
-extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
-archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
-enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
-export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
-whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
-compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
-old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
-old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
-archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
-archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
-module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
-module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
-with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
-allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
-no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
-hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
-hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
-hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
-hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
-hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
-hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
-hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
-inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
-link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
-always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
-export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
-exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
-include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
-prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
-postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
-file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
-variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
-need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
-need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
-version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
-runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
-shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
-shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
-libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
-library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
-soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
-install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
-postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
-postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
-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"`'
-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"`'
-enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
-old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
-striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
-
-LTCC='$LTCC'
-LTCFLAGS='$LTCFLAGS'
-compiler='$compiler_DEFAULT'
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
- eval 'cat <<_LTECHO_EOF
-\$1
-_LTECHO_EOF'
-}
-
-# Quote evaled strings.
-for var in SHELL \
-ECHO \
-PATH_SEPARATOR \
-SED \
-GREP \
-EGREP \
-FGREP \
-LD \
-NM \
-LN_S \
-lt_SP2NL \
-lt_NL2SP \
-reload_flag \
-OBJDUMP \
-deplibs_check_method \
-file_magic_cmd \
-file_magic_glob \
-want_nocaseglob \
-DLLTOOL \
-sharedlib_from_linklib_cmd \
-AR \
-AR_FLAGS \
-archiver_list_spec \
-STRIP \
-RANLIB \
-CC \
-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 \
-lt_prog_compiler_static \
-lt_cv_prog_compiler_c_o \
-need_locks \
-MANIFEST_TOOL \
-DSYMUTIL \
-NMEDIT \
-LIPO \
-OTOOL \
-OTOOL64 \
-shrext_cmds \
-export_dynamic_flag_spec \
-whole_archive_flag_spec \
-compiler_needs_object \
-with_gnu_ld \
-allow_undefined_flag \
-no_undefined_flag \
-hardcode_libdir_flag_spec \
-hardcode_libdir_separator \
-exclude_expsyms \
-include_expsyms \
-file_list_spec \
-variables_saved_for_relink \
-libname_spec \
-library_names_spec \
-soname_spec \
-install_override_mode \
-finish_eval \
-old_striplib \
-striplib; do
- case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
- *[\\\\\\\`\\"\\\$]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
- ;;
- *)
- eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
- ;;
- esac
-done
-
-# Double-quote double-evaled strings.
-for var in reload_cmds \
-old_postinstall_cmds \
-old_postuninstall_cmds \
-old_archive_cmds \
-extract_expsyms_cmds \
-old_archive_from_new_cmds \
-old_archive_from_expsyms_cmds \
-archive_cmds \
-archive_expsym_cmds \
-module_cmds \
-module_expsym_cmds \
-export_symbols_cmds \
-prelink_cmds \
-postlink_cmds \
-postinstall_cmds \
-postuninstall_cmds \
-finish_cmds \
-sys_lib_search_path_spec \
-configure_time_dlsearch_path \
-configure_time_lt_sys_library_path; do
- case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
- *[\\\\\\\`\\"\\\$]*)
- 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\\\\\\""
- ;;
- esac
-done
-
-ac_aux_dir='$ac_aux_dir'
-
-# 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
- setopt NO_GLOB_SUBST
-fi
-
-
- PACKAGE='$PACKAGE'
- VERSION='$VERSION'
- RM='$RM'
- ofile='$ofile'
-
-
-
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-
-# Handling of arguments.
-for ac_config_target in $ac_config_targets
-do
- case $ac_config_target in
- "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
- "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
- "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
- "sqlite3.pc") CONFIG_FILES="$CONFIG_FILES sqlite3.pc" ;;
-
- *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
- esac
-done
-
-
-# If the user did not use the arguments to specify the items to instantiate,
-# then the envvar interface is used. Set only those that are not.
-# We use the long form for the default assignment because of an extremely
-# bizarre bug on SunOS 4.1.3.
-if $ac_need_defaults; then
- test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files
- test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands
-fi
-
-# Have a temporary directory for convenience. Make it in the build tree
-# simply because there is no reason against having it here, and in addition,
-# creating and moving files from /tmp can sometimes cause problems.
-# Hook for its removal unless debugging.
-# Note that there is a small window in which the directory will not be cleaned:
-# after its creation but before its name has been assigned to `$tmp'.
-$debug ||
-{
- tmp= ac_tmp=
- trap 'exit_status=$?
- : "${ac_tmp:=$tmp}"
- { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
-' 0
- trap 'as_fn_exit 1' 1 2 13 15
-}
-# Create a (secure) tmp directory for tmp files.
-
-{
- tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
- test -d "$tmp"
-} ||
-{
- tmp=./conf$$-$RANDOM
- (umask 077 && mkdir "$tmp")
-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
-
-# Set up the scripts for CONFIG_FILES section.
-# No need to generate them if there are no CONFIG_FILES.
-# This happens for instance with `./config.status config.h'.
-if test -n "$CONFIG_FILES"; then
-
-
-ac_cr=`echo X | tr X '\015'`
-# On cygwin, bash can eat \r inside `` if the user requested igncr.
-# But we know of no other shell where ac_cr would be empty at this
-# point, so we can use a bashism as a fallback.
-if test "x$ac_cr" = x; then
- eval ac_cr=\$\'\\r\'
-fi
-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
- ac_cs_awk_cr='\\r'
-else
- ac_cs_awk_cr=$ac_cr
-fi
-
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
-_ACEOF
-
-
-{
- echo "cat >conf$$subs.awk <<_ACEOF" &&
- echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
- echo "_ACEOF"
-} >conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
-ac_delim='%!_!# '
-for ac_last_try in false false false false false :; do
- . ./conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-
- ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
- if test $ac_delim_n = $ac_delim_num; then
- break
- elif $ac_last_try; then
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
- else
- ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
- fi
-done
-rm -f conf$$subs.sh
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
-_ACEOF
-sed -n '
-h
-s/^/S["/; s/!.*/"]=/
-p
-g
-s/^[^!]*!//
-:repl
-t repl
-s/'"$ac_delim"'$//
-t delim
-:nl
-h
-s/\(.\{148\}\)..*/\1/
-t more1
-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
-p
-n
-b repl
-:more1
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t nl
-:delim
-h
-s/\(.\{148\}\)..*/\1/
-t more2
-s/["\\]/\\&/g; s/^/"/; s/$/"/
-p
-b
-:more2
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t delim
-' <conf$$subs.awk | sed '
-/^[^""]/{
- N
- s/\n//
-}
-' >>$CONFIG_STATUS || ac_write_fail=1
-rm -f conf$$subs.awk
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
- for (key in S) S_is_set[key] = 1
- FS = ""
-
-}
-{
- line = $ 0
- nfields = split(line, field, "@")
- substed = 0
- len = length(field[1])
- for (i = 2; i < nfields; i++) {
- key = field[i]
- keylen = length(key)
- if (S_is_set[key]) {
- value = S[key]
- line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
- len += length(value) + length(field[++i])
- substed = 1
- } else
- len += 1 + keylen
- }
-
- print line
-}
-
-_ACAWK
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
- sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
-else
- cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
- || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
-_ACEOF
-
-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
-# trailing colons and then remove the whole line if VPATH becomes empty
-# (actually we leave an empty line to preserve line numbers).
-if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
-h
-s///
-s/^/:/
-s/[ ]*$/:/
-s/:\$(srcdir):/:/g
-s/:\${srcdir}:/:/g
-s/:@srcdir@:/:/g
-s/^:*//
-s/:*$//
-x
-s/\(=[ ]*\).*/\1/
-G
-s/\n//
-s/^[^=]*=[ ]*$//
-}'
-fi
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-fi # test -n "$CONFIG_FILES"
-
-
-eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS"
-shift
-for ac_tag
-do
- case $ac_tag in
- :[FHLC]) ac_mode=$ac_tag; continue;;
- esac
- case $ac_mode$ac_tag in
- :[FHL]*:*);;
- :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
- :[FH]-) ac_tag=-:-;;
- :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
- esac
- ac_save_IFS=$IFS
- IFS=:
- set x $ac_tag
- IFS=$ac_save_IFS
- shift
- ac_file=$1
- shift
-
- case $ac_mode in
- :L) ac_source=$1;;
- :[FH])
- ac_file_inputs=
- for ac_f
- do
- case $ac_f in
- -) ac_f="$ac_tmp/stdin";;
- *) # Look for the file first in the build tree, then in the source tree
- # (if the path is not absolute). The absolute path cannot be DOS-style,
- # because $ac_f cannot contain `:'.
- test -f "$ac_f" ||
- case $ac_f in
- [\\/$]*) false;;
- *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
- esac ||
- as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
- esac
- case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
- as_fn_append ac_file_inputs " '$ac_f'"
- done
-
- # Let's still pretend it is `configure' which instantiates (i.e., don't
- # use $as_me), people would be surprised to read:
- # /* config.h. Generated by config.status. */
- configure_input='Generated from '`
- printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
- `' by configure.'
- if test x"$ac_file" != x-; then
- configure_input="$ac_file. $configure_input"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-printf "%s\n" "$as_me: creating $ac_file" >&6;}
- fi
- # Neutralize special characters interpreted by sed in replacement strings.
- case $configure_input in #(
- *\&* | *\|* | *\\* )
- ac_sed_conf_input=`printf "%s\n" "$configure_input" |
- sed 's/[\\\\&|]/\\\\&/g'`;; #(
- *) ac_sed_conf_input=$configure_input;;
- esac
-
- case $ac_tag in
- *:-:* | *:-) cat >"$ac_tmp/stdin" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
- esac
- ;;
- esac
-
- ac_dir=`$as_dirname -- "$ac_file" ||
-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$ac_file" : 'X\(//\)[^/]' \| \
- X"$ac_file" : 'X\(//\)$' \| \
- X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$ac_file" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- as_dir="$ac_dir"; as_fn_mkdir_p
- ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
- # A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
- case $ac_top_builddir_sub in
- "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
- esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
- .) # We are building in place.
- ac_srcdir=.
- ac_top_srcdir=$ac_top_builddir_sub
- ac_abs_top_srcdir=$ac_pwd ;;
- [\\/]* | ?:[\\/]* ) # Absolute name.
- ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir
- ac_abs_top_srcdir=$srcdir ;;
- *) # Relative name.
- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_build_prefix$srcdir
- ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-
- case $ac_mode in
- :F)
- #
- # CONFIG_FILE
- #
-
- case $INSTALL in
- [\\/$]* | ?:[\\/]* ) 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
-# If the template does not know about datarootdir, expand it.
-# FIXME: This hack should be removed a few years after 2.60.
-ac_datarootdir_hack=; ac_datarootdir_seen=
-ac_sed_dataroot='
-/datarootdir/ {
- p
- q
-}
-/@datadir@/p
-/@docdir@/p
-/@infodir@/p
-/@localedir@/p
-/@mandir@/p'
-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
-*datarootdir*) ac_datarootdir_seen=yes;;
-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
- ac_datarootdir_hack='
- s&@datadir@&$datadir&g
- s&@docdir@&$docdir&g
- s&@infodir@&$infodir&g
- s&@localedir@&$localedir&g
- s&@mandir@&$mandir&g
- s&\\\${datarootdir}&$datarootdir&g' ;;
-esac
-_ACEOF
-
-# Neutralize VPATH when `$srcdir' = `.'.
-# Shell code in configure.ac might set extrasub.
-# FIXME: do we really want to maintain this feature?
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_sed_extra="$ac_vpsub
-$extrasub
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-:t
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s|@configure_input@|$ac_sed_conf_input|;t t
-s&@top_builddir@&$ac_top_builddir_sub&;t t
-s&@top_build_prefix@&$ac_top_build_prefix&;t t
-s&@srcdir@&$ac_srcdir&;t t
-s&@abs_srcdir@&$ac_abs_srcdir&;t t
-s&@top_srcdir@&$ac_top_srcdir&;t t
-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
-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" \
- >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-
-test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
- { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
- "$ac_tmp/out"`; test -z "$ac_out"; } &&
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined" >&5
-printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined" >&2;}
-
- rm -f "$ac_tmp/stdin"
- case $ac_file in
- -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
- *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
- esac \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- ;;
-
-
- :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
-printf "%s\n" "$as_me: executing $ac_file commands" >&6;}
- ;;
- esac
-
-
- 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=`printf "%s\n" "$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 ||
-printf "%s\n" 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 ||
-printf "%s\n" 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
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$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 that allow our
- # commands through without removal of \ escapes.
- if test -n "${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
- fi
-
- cfgfile=${ofile}T
- trap "$RM \"$cfgfile\"; exit 1" 1 2 15
- $RM "$cfgfile"
-
- cat <<_LT_EOF >> "$cfgfile"
-#! $SHELL
-# Generated automatically by $as_me ($PACKAGE) $VERSION
-# 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.
-#
-# 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
-# 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/>.
-
-
-# The names of the tagged configurations supported by this script.
-available_tags=''
-
-# 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
-
-# Whether or not to build shared libraries.
-build_libtool_libs=$enable_shared
-
-# Whether or not to build static libraries.
-build_old_libs=$enable_static
-
-# What type of objects to build.
-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
-
-# An echo program that protects backslashes.
-ECHO=$lt_ECHO
-
-# The PATH separator for the build system.
-PATH_SEPARATOR=$lt_PATH_SEPARATOR
-
-# The host system.
-host_alias=$host_alias
-host=$host
-host_os=$host_os
-
-# The build system.
-build_alias=$build_alias
-build=$build
-build_os=$build_os
-
-# A sed program that does not truncate output.
-SED=$lt_SED
-
-# Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="\$SED -e 1s/^X//"
-
-# A grep program that handles long lines.
-GREP=$lt_GREP
-
-# An ERE matcher.
-EGREP=$lt_EGREP
-
-# A literal string matcher.
-FGREP=$lt_FGREP
-
-# A BSD- or MS-compatible name lister.
-NM=$lt_NM
-
-# Whether we need soft or hard links.
-LN_S=$lt_LN_S
-
-# What is the maximum length of a command?
-max_cmd_len=$max_cmd_len
-
-# Object file suffix (normally "o").
-objext=$ac_objext
-
-# Executable file suffix (normally "").
-exeext=$exeext
-
-# whether the shell understands "unset".
-lt_unset=$lt_unset
-
-# turn spaces into newlines.
-SP2NL=$lt_lt_SP2NL
-
-# turn newlines into spaces.
-NL2SP=$lt_lt_NL2SP
-
-# convert \$build file names to \$host format.
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-
-# convert \$build files to toolchain format.
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-
-# An object symbol dumper.
-OBJDUMP=$lt_OBJDUMP
-
-# Method to check whether dependent libraries are shared objects.
-deplibs_check_method=$lt_deplibs_check_method
-
-# Command to use when deplibs_check_method = "file_magic".
-file_magic_cmd=$lt_file_magic_cmd
-
-# How to find potential files when deplibs_check_method = "file_magic".
-file_magic_glob=$lt_file_magic_glob
-
-# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
-want_nocaseglob=$lt_want_nocaseglob
-
-# DLL creation program.
-DLLTOOL=$lt_DLLTOOL
-
-# Command to associate shared and link libraries.
-sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
-
-# The archiver.
-AR=$lt_AR
-
-# Flags to create an archive.
-AR_FLAGS=$lt_AR_FLAGS
-
-# How to feed a file listing to the archiver.
-archiver_list_spec=$lt_archiver_list_spec
-
-# A symbol stripping program.
-STRIP=$lt_STRIP
-
-# Commands used to install an old-style archive.
-RANLIB=$lt_RANLIB
-old_postinstall_cmds=$lt_old_postinstall_cmds
-old_postuninstall_cmds=$lt_old_postuninstall_cmds
-
-# Whether to use a lock for old archive extraction.
-lock_old_archive_extraction=$lock_old_archive_extraction
-
-# A C compiler.
-LTCC=$lt_CC
-
-# LTCC compiler flags.
-LTCFLAGS=$lt_CFLAGS
-
-# Take the output of nm and produce a listing of raw symbols and C names.
-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 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
-
-# Used to examine libraries when file_magic_cmd begins with "file".
-MAGIC_CMD=$MAGIC_CMD
-
-# Must we lock files when doing compilation?
-need_locks=$lt_need_locks
-
-# Manifest tool.
-MANIFEST_TOOL=$lt_MANIFEST_TOOL
-
-# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
-DSYMUTIL=$lt_DSYMUTIL
-
-# Tool to change global to local symbols on Mac OS X.
-NMEDIT=$lt_NMEDIT
-
-# Tool to manipulate fat objects and archives on Mac OS X.
-LIPO=$lt_LIPO
-
-# ldd/readelf like tool for Mach-O binaries on Mac OS X.
-OTOOL=$lt_OTOOL
-
-# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
-OTOOL64=$lt_OTOOL64
-
-# Old archive suffix (normally "a").
-libext=$libext
-
-# Shared library suffix (normally ".so").
-shrext_cmds=$lt_shrext_cmds
-
-# The commands to extract the exported symbol list from a shared archive.
-extract_expsyms_cmds=$lt_extract_expsyms_cmds
-
-# Variables whose values should be saved in libtool wrapper scripts and
-# restored at link time.
-variables_saved_for_relink=$lt_variables_saved_for_relink
-
-# Do we need the "lib" prefix for modules?
-need_lib_prefix=$need_lib_prefix
-
-# Do we need a version for libraries?
-need_version=$need_version
-
-# Library versioning type.
-version_type=$version_type
-
-# Shared library runtime path variable.
-runpath_var=$runpath_var
-
-# Shared library path variable.
-shlibpath_var=$shlibpath_var
-
-# Is shlibpath searched before the hard-coded library search path?
-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
-
-# Format of library name prefix.
-libname_spec=$lt_libname_spec
-
-# List of archive names. First name is the real one, the rest are links.
-# The last name is the one that the linker finds with -lNAME
-library_names_spec=$lt_library_names_spec
-
-# The coded name of the library, if different from the real name.
-soname_spec=$lt_soname_spec
-
-# Permission mode override for installation of shared libraries.
-install_override_mode=$lt_install_override_mode
-
-# Command to use after installation of a shared archive.
-postinstall_cmds=$lt_postinstall_cmds
-
-# Command to use after uninstallation of a shared archive.
-postuninstall_cmds=$lt_postuninstall_cmds
-
-# Commands used to finish a libtool library installation in a directory.
-finish_cmds=$lt_finish_cmds
-
-# As "finish_cmds", except a single script fragment to be evaled but
-# not shown.
-finish_eval=$lt_finish_eval
-
-# Whether we should hardcode library paths into libraries.
-hardcode_into_libs=$hardcode_into_libs
-
-# Compile-time system search path for libraries.
-sys_lib_search_path_spec=$lt_sys_lib_search_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
-
-# Whether dlopen of programs is supported.
-dlopen_self=$enable_dlopen_self
-
-# Whether dlopen of statically linked programs is supported.
-dlopen_self_static=$enable_dlopen_self_static
-
-# Commands to strip libraries.
-old_striplib=$lt_old_striplib
-striplib=$lt_striplib
-
-
-# The linker used to build libraries.
-LD=$lt_LD
-
-# How to create reloadable object files.
-reload_flag=$lt_reload_flag
-reload_cmds=$lt_reload_cmds
-
-# Commands used to build an old-style archive.
-old_archive_cmds=$lt_old_archive_cmds
-
-# A language specific compiler.
-CC=$lt_compiler
-
-# Is the compiler the GNU compiler?
-with_gcc=$GCC
-
-# Compiler flag to turn off builtin functions.
-no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
-
-# Additional compiler flags for building library objects.
-pic_flag=$lt_lt_prog_compiler_pic
-
-# How to pass a linker flag through the compiler.
-wl=$lt_lt_prog_compiler_wl
-
-# Compiler flag to prevent dynamic linking.
-link_static_flag=$lt_lt_prog_compiler_static
-
-# Does compiler simultaneously support -c and -o options?
-compiler_c_o=$lt_lt_cv_prog_compiler_c_o
-
-# Whether or not to add -lc for building shared libraries.
-build_libtool_need_lc=$archive_cmds_need_lc
-
-# Whether or not to disallow shared libs when runtime libs are static.
-allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
-
-# Compiler flag to allow reflexive dlopens.
-export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
-
-# Compiler flag to generate shared objects directly from archives.
-whole_archive_flag_spec=$lt_whole_archive_flag_spec
-
-# Whether the compiler copes with passing no objects directly.
-compiler_needs_object=$lt_compiler_needs_object
-
-# Create an old-style archive from a shared archive.
-old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
-
-# Create a temporary old-style archive to link instead of a shared archive.
-old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
-
-# Commands used to build a shared archive.
-archive_cmds=$lt_archive_cmds
-archive_expsym_cmds=$lt_archive_expsym_cmds
-
-# Commands used to build a loadable module if different from building
-# a shared archive.
-module_cmds=$lt_module_cmds
-module_expsym_cmds=$lt_module_expsym_cmds
-
-# Whether we are building with GNU ld or not.
-with_gnu_ld=$lt_with_gnu_ld
-
-# Flag that allows shared libraries with undefined symbols to be built.
-allow_undefined_flag=$lt_allow_undefined_flag
-
-# Flag that enforces no undefined symbols.
-no_undefined_flag=$lt_no_undefined_flag
-
-# Flag to hardcode \$libdir into a binary during linking.
-# This must work even if \$libdir does not exist
-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
-# DIR into the resulting binary.
-hardcode_direct=$hardcode_direct
-
-# 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
-# library is relocated.
-hardcode_direct_absolute=$hardcode_direct_absolute
-
-# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
-# into the resulting binary.
-hardcode_minus_L=$hardcode_minus_L
-
-# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
-# into the resulting binary.
-hardcode_shlibpath_var=$hardcode_shlibpath_var
-
-# Set to "yes" if building a shared library automatically hardcodes DIR
-# into the library and all subsequent libraries and executables linked
-# against it.
-hardcode_automatic=$hardcode_automatic
-
-# Set to yes if linker adds runtime paths of dependent libraries
-# to runtime path list.
-inherit_rpath=$inherit_rpath
-
-# Whether libtool must link a program against all its dependency libraries.
-link_all_deplibs=$link_all_deplibs
-
-# Set to "yes" if exported symbols are required.
-always_export_symbols=$always_export_symbols
-
-# The commands to list exported symbols.
-export_symbols_cmds=$lt_export_symbols_cmds
-
-# Symbols that should not be listed in the preloaded symbols.
-exclude_expsyms=$lt_exclude_expsyms
-
-# Symbols that must always be exported.
-include_expsyms=$lt_include_expsyms
-
-# Commands necessary for linking programs (against libraries) with templates.
-prelink_cmds=$lt_prelink_cmds
-
-# Commands necessary for finishing linking programs.
-postlink_cmds=$lt_postlink_cmds
-
-# Specify filename containing input files.
-file_list_spec=$lt_file_list_spec
-
-# How to hardcode a shared library path into an executable.
-hardcode_action=$hardcode_action
-
-# ### END LIBTOOL CONFIG
-
-_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 set != "${COLLECT_NAMES+set}"; then
- COLLECT_NAMES=
- export COLLECT_NAMES
-fi
-_LT_EOF
- ;;
- esac
-
-
-
-ltmain=$ac_aux_dir/ltmain.sh
-
-
- # We use sed instead of cat because bash on DJGPP gets confused if
- # if finds mixed CR/LF and LF-only lines. Since sed operates in
- # text mode, it properly converts lines to CR/LF. This bash problem
- # is reportedly fixed, but why not run on old versions too?
- sed '$q' "$ltmain" >> "$cfgfile" \
- || (rm -f "$cfgfile"; exit 1)
-
- mv -f "$cfgfile" "$ofile" ||
- (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
- chmod +x "$ofile"
-
- ;;
-
- esac
-done # for ac_tag
-
-
-as_fn_exit 0
-_ACEOF
-ac_clean_files=$ac_clean_files_save
-
-test $ac_write_fail = 0 ||
- as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
-
-
-# configure is writing to config.log, and then calls config.status.
-# config.status does its own redirection, appending to config.log.
-# Unfortunately, on DOS this fails, as config.log is still kept open
-# by configure, so config.status won't be able to write to it; its
-# output is simply discarded. So we exec the FD to /dev/null,
-# effectively closing config.log, so it can be properly (re)opened and
-# appended to by config.status. When coming back to configure, we
-# need to make the FD available again.
-if test "$no_create" != yes; then
- ac_cs_success=:
- ac_config_status_args=
- test "$silent" = yes &&
- ac_config_status_args="$ac_config_status_args --quiet"
- exec 5>/dev/null
- $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
- exec 5>>config.log
- # Use ||, not &&, to avoid exiting from the if with $? = 1, which
- # would make configure fail if this is the last instruction.
- $ac_cs_success || as_fn_exit 1
-fi
-if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
-fi
-
-
+#!/bin/sh
+dir="`dirname "$0"`/autosetup"
+#@@INITCHECK@@#
+WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"
diff --git a/contrib/sqlite3/configure.ac b/contrib/sqlite3/configure.ac
deleted file mode 100644
index 806255961fda..000000000000
--- a/contrib/sqlite3/configure.ac
+++ /dev/null
@@ -1,270 +0,0 @@
-
-#-----------------------------------------------------------------------
-# Supports the following non-standard switches.
-#
-# --enable-threadsafe
-# --enable-readline
-# --enable-editline
-# --enable-static-shell
-# --enable-dynamic-extensions
-#
-
-AC_PREREQ(2.61)
-AC_INIT(sqlite, 3.46.1, http://www.sqlite.org)
-AC_CONFIG_SRCDIR([sqlite3.c])
-AC_CONFIG_AUX_DIR([.])
-
-# Use automake.
-AM_INIT_AUTOMAKE([foreign])
-
-AC_SYS_LARGEFILE
-
-# Check for required programs.
-AC_PROG_CC
-AC_PROG_LIBTOOL
-AC_PROG_MKDIR_P
-
-# Check for library functions that SQLite can optionally use.
-AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
-AC_FUNC_STRERROR_R
-
-AC_CONFIG_FILES([Makefile sqlite3.pc])
-BUILD_CFLAGS=
-AC_SUBST(BUILD_CFLAGS)
-
-#-------------------------------------------------------------------------
-# Two options to enable readline compatible libraries:
-#
-# --enable-editline
-# --enable-readline
-#
-# Both are enabled by default. If, after command line processing both are
-# still enabled, the script searches for editline first and automatically
-# disables readline if it is found. So, to use readline explicitly, the
-# user must pass "--disable-editline". To disable command line editing
-# support altogether, "--disable-editline --disable-readline".
-#
-# When searching for either library, check for headers before libraries
-# as some distros supply packages that contain libraries but not header
-# files, which come as a separate development package.
-#
-AC_ARG_ENABLE(editline, [AS_HELP_STRING([--enable-editline],[use BSD libedit])])
-AC_ARG_ENABLE(readline, [AS_HELP_STRING([--enable-readline],[use readline])])
-
-AS_IF([ test x"$enable_editline" != xno ],[
- AC_CHECK_HEADERS([editline/readline.h],[
- sLIBS=$LIBS
- LIBS=""
- AC_SEARCH_LIBS([readline],[edit],[
- AC_DEFINE([HAVE_EDITLINE],1,Define to use BSD editline)
- READLINE_LIBS="$LIBS -ltinfo"
- enable_readline=no
- ],[],[-ltinfo])
- AS_UNSET(ac_cv_search_readline)
- LIBS=$sLIBS
- ])
-])
-
-AS_IF([ test x"$enable_readline" != xno ],[
- AC_CHECK_HEADERS([readline/readline.h],[
- sLIBS=$LIBS
- LIBS=""
- AC_SEARCH_LIBS(tgetent, termcap curses ncurses ncursesw, [], [])
- AC_SEARCH_LIBS(readline,[readline edit], [
- AC_DEFINE([HAVE_READLINE],1,Define to use readline or wrapper)
- READLINE_LIBS=$LIBS
- ])
- LIBS=$sLIBS
- ])
-])
-
-AC_SUBST(READLINE_LIBS)
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-threadsafe
-#
-AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING(
- [--enable-threadsafe], [build a thread-safe library [default=yes]])],
- [], [enable_threadsafe=yes])
-if test x"$enable_threadsafe" == "xno"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0"
-else
- BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
- AC_SEARCH_LIBS(pthread_create, pthread)
- AC_SEARCH_LIBS(pthread_mutexattr_init, pthread)
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-dynamic-extensions
-#
-AC_ARG_ENABLE(dynamic-extensions, [AS_HELP_STRING(
- [--enable-dynamic-extensions], [support loadable extensions [default=yes]])],
- [], [enable_dynamic_extensions=yes])
-if test x"$enable_dynamic_extensions" != "xno"; then
- AC_SEARCH_LIBS(dlopen, dl)
-else
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_OMIT_LOAD_EXTENSION=1"
-fi
-AC_MSG_CHECKING([for whether to support dynamic extensions])
-AC_MSG_RESULT($enable_dynamic_extensions)
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-math
-#
-AC_ARG_ENABLE(math, [AS_HELP_STRING(
- [--enable-math], [SQL math functions [default=yes]])],
- [], [enable_math=yes])
-AC_MSG_CHECKING([SQL math functions])
-if test x"$enable_math" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS"
- AC_MSG_RESULT([enabled])
- AC_SEARCH_LIBS(ceil, m)
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts4
-#
-AC_ARG_ENABLE(fts4, [AS_HELP_STRING(
- [--enable-fts4], [include fts4 support [default=yes]])],
- [], [enable_fts4=yes])
-AC_MSG_CHECKING([FTS4 extension])
-if test x"$enable_fts4" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS4"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts3
-#
-AC_ARG_ENABLE(fts3, [AS_HELP_STRING(
- [--enable-fts3], [include fts3 support [default=no]])],
- [], [])
-AC_MSG_CHECKING([FTS3 extension])
-if test x"$enable_fts3" = "xyes" -a x"$enable_fts4" = "xno"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS3"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts5
-#
-AC_ARG_ENABLE(fts5, [AS_HELP_STRING(
- [--enable-fts5], [include fts5 support [default=yes]])],
- [], [enable_fts5=yes])
-AC_MSG_CHECKING([FTS5 extension])
-if test x"$enable_fts5" = "xyes"; then
- AC_MSG_RESULT([enabled])
- AC_SEARCH_LIBS(log, m)
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS5"
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-rtree
-#
-AC_ARG_ENABLE(rtree, [AS_HELP_STRING(
- [--enable-rtree], [include rtree support [default=yes]])],
- [], [enable_rtree=yes])
-AC_MSG_CHECKING([RTREE extension])
-if test x"$enable_rtree" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-session
-#
-AC_ARG_ENABLE(session, [AS_HELP_STRING(
- [--enable-session], [enable the session extension [default=no]])],
- [], [])
-AC_MSG_CHECKING([Session extension])
-if test x"$enable_session" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-debug
-#
-AC_ARG_ENABLE(debug, [AS_HELP_STRING(
- [--enable-debug], [build with debugging features enabled [default=no]])],
- [], [])
-AC_MSG_CHECKING([Build type])
-if test x"$enable_debug" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_DEBUG -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
- CFLAGS="-g -O0"
- AC_MSG_RESULT([debug])
-else
- AC_MSG_RESULT([release])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-static-shell
-#
-AC_ARG_ENABLE(static-shell, [AS_HELP_STRING(
- [--enable-static-shell],
- [statically link libsqlite3 into shell tool [default=yes]])],
- [], [enable_static_shell=yes])
-if test x"$enable_static_shell" = "xyes"; then
- EXTRA_SHELL_OBJ=sqlite3-sqlite3.$OBJEXT
-else
- EXTRA_SHELL_OBJ=libsqlite3.la
-fi
-AC_SUBST(EXTRA_SHELL_OBJ)
-#-----------------------------------------------------------------------
-
-AC_CHECK_FUNCS(posix_fallocate)
-AC_CHECK_HEADERS(zlib.h,[
- AC_SEARCH_LIBS(deflate,z,[BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_HAVE_ZLIB"])
-])
-
-AC_SEARCH_LIBS(system,,,[SHELL_CFLAGS="-DSQLITE_NOHAVE_SYSTEM"])
-AC_SUBST(SHELL_CFLAGS)
-
-#-----------------------------------------------------------------------
-# UPDATE: Maybe it's better if users just set CFLAGS before invoking
-# configure. This option doesn't really add much...
-#
-# --enable-tempstore
-#
-# AC_ARG_ENABLE(tempstore, [AS_HELP_STRING(
-# [--enable-tempstore],
-# [in-memory temporary tables (never, no, yes, always) [default=no]])],
-# [], [enable_tempstore=no])
-# AC_MSG_CHECKING([for whether or not to store temp tables in-memory])
-# case "$enable_tempstore" in
-# never ) TEMP_STORE=0 ;;
-# no ) TEMP_STORE=1 ;;
-# always ) TEMP_STORE=3 ;;
-# yes ) TEMP_STORE=3 ;;
-# * )
-# TEMP_STORE=1
-# enable_tempstore=yes
-# ;;
-# esac
-# AC_MSG_RESULT($enable_tempstore)
-# AC_SUBST(TEMP_STORE)
-#-----------------------------------------------------------------------
-
-AC_OUTPUT
diff --git a/contrib/sqlite3/depcomp b/contrib/sqlite3/depcomp
deleted file mode 100755
index 715e34311ed2..000000000000
--- a/contrib/sqlite3/depcomp
+++ /dev/null
@@ -1,791 +0,0 @@
-#! /bin/sh
-# depcomp - compile a program generating dependencies as side-effects
-
-scriptversion=2018-03-07.03; # UTC
-
-# Copyright (C) 1999-2021 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/contrib/sqlite3/install-sh b/contrib/sqlite3/install-sh
deleted file mode 100755
index ec298b537402..000000000000
--- a/contrib/sqlite3/install-sh
+++ /dev/null
@@ -1,541 +0,0 @@
-#!/bin/sh
-# install - install a program, script, or datafile
-
-scriptversion=2020-11-14.01; # UTC
-
-# This originates from X11R5 (mit/util/scripts/install.sh), which was
-# later released in X11R6 (xc/config/util/install.sh) with the
-# following copyright and license.
-#
-# Copyright (C) 1994 X Consortium
-#
-# 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
-# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
-# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# Except as contained in this notice, the name of the X Consortium shall not
-# be used in advertising or otherwise to promote the sale, use or other deal-
-# ings in this Software without prior written authorization from the X Consor-
-# tium.
-#
-#
-# FSF changes to this file are in the public domain.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# 'make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch.
-
-tab=' '
-nl='
-'
-IFS=" $tab$nl"
-
-# Set DOITPROG to "echo" to test this script.
-
-doit=${DOITPROG-}
-doit_exec=${doit:-exec}
-
-# Put in absolute file names if you don't have them in your path;
-# or use environment vars.
-
-chgrpprog=${CHGRPPROG-chgrp}
-chmodprog=${CHMODPROG-chmod}
-chownprog=${CHOWNPROG-chown}
-cmpprog=${CMPPROG-cmp}
-cpprog=${CPPROG-cp}
-mkdirprog=${MKDIRPROG-mkdir}
-mvprog=${MVPROG-mv}
-rmprog=${RMPROG-rm}
-stripprog=${STRIPPROG-strip}
-
-posix_mkdir=
-
-# Desired mode of installed file.
-mode=0755
-
-# Create dirs (including intermediate dirs) using mode 755.
-# This is like GNU 'install' as of coreutils 8.32 (2020).
-mkdir_umask=22
-
-backupsuffix=
-chgrpcmd=
-chmodcmd=$chmodprog
-chowncmd=
-mvcmd=$mvprog
-rmcmd="$rmprog -f"
-stripcmd=
-
-src=
-dst=
-dir_arg=
-dst_arg=
-
-copy_on_change=false
-is_target_a_directory=possibly
-
-usage="\
-Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
- or: $0 [OPTION]... SRCFILES... DIRECTORY
- or: $0 [OPTION]... -t DIRECTORY SRCFILES...
- or: $0 [OPTION]... -d DIRECTORIES...
-
-In the 1st form, copy SRCFILE to DSTFILE.
-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-In the 4th, create DIRECTORIES.
-
-Options:
- --help display this help and exit.
- --version display version info and exit.
-
- -c (ignored)
- -C install only if different (preserve data modification time)
- -d create directories instead of installing files.
- -g GROUP $chgrpprog installed files to GROUP.
- -m MODE $chmodprog installed files to MODE.
- -o USER $chownprog installed files to USER.
- -p pass -p to $cpprog.
- -s $stripprog installed files.
- -S SUFFIX attempt to back up existing files, with suffix SUFFIX.
- -t DIRECTORY install into DIRECTORY.
- -T report an error if DSTFILE is a directory.
-
-Environment variables override the default commands:
- CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
- RMPROG STRIPPROG
-
-By default, rm is invoked with -f; when overridden with RMPROG,
-it's up to you to specify -f if you want it.
-
-If -S is not specified, no backups are attempted.
-
-Email bug reports to bug-automake@gnu.org.
-Automake home page: https://www.gnu.org/software/automake/
-"
-
-while test $# -ne 0; do
- case $1 in
- -c) ;;
-
- -C) copy_on_change=true;;
-
- -d) dir_arg=true;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift;;
-
- --help) echo "$usage"; exit $?;;
-
- -m) mode=$2
- case $mode in
- *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
- echo "$0: invalid mode: $mode" >&2
- exit 1;;
- esac
- shift;;
-
- -o) chowncmd="$chownprog $2"
- shift;;
-
- -p) cpprog="$cpprog -p";;
-
- -s) stripcmd=$stripprog;;
-
- -S) backupsuffix="$2"
- 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) is_target_a_directory=never;;
-
- --version) echo "$0 $scriptversion"; exit $?;;
-
- --) shift
- break;;
-
- -*) 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.
- # Otherwise, the last argument is the destination. Remove it from $@.
- for arg
- do
- if test -n "$dst_arg"; then
- # $@ is not empty: it contains at least $arg.
- set fnord "$@" "$dst_arg"
- shift # fnord
- fi
- shift # arg
- dst_arg=$arg
- # Protect names problematic for 'test' and other utilities.
- case $dst_arg in
- -* | [=\(\)!]) dst_arg=./$dst_arg;;
- esac
- done
-fi
-
-if test $# -eq 0; then
- if test -z "$dir_arg"; then
- echo "$0: no input file specified." >&2
- exit 1
- fi
- # It's OK to call 'install-sh -d' without argument.
- # This can happen when creating conditional directories.
- exit 0
-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
- trap "ret=141; $do_exit" 13
- trap "ret=143; $do_exit" 15
-
- # Set umask so as not to create temps with too-generous modes.
- # However, 'strip' requires both read and write access to temps.
- case $mode in
- # Optimize common cases.
- *644) cp_umask=133;;
- *755) cp_umask=22;;
-
- *[0-7])
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw='% 200'
- fi
- cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
- *)
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw=,u+rw
- fi
- cp_umask=$mode$u_plus_rw;;
- esac
-fi
-
-for src
-do
- # Protect names problematic for 'test' and other utilities.
- case $src in
- -* | [=\(\)!]) src=./$src;;
- esac
-
- if test -n "$dir_arg"; then
- dst=$src
- dstdir=$dst
- test -d "$dstdir"
- dstdir_status=$?
- # Don't chown directories that already exist.
- if test $dstdir_status = 0; then
- chowncmd=""
- fi
- else
-
- # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
- # might cause directories to be created, which would be especially bad
- # if $src (and thus $dsttmp) contains '*'.
- if test ! -f "$src" && test ! -d "$src"; then
- echo "$0: $src does not exist." >&2
- exit 1
- fi
-
- if test -z "$dst_arg"; then
- echo "$0: no destination specified." >&2
- exit 1
- fi
- dst=$dst_arg
-
- # If destination is a directory, append the input filename.
- if test -d "$dst"; then
- if test "$is_target_a_directory" = never; then
- echo "$0: $dst_arg: Is a directory" >&2
- exit 1
- fi
- dstdir=$dst
- dstbase=`basename "$src"`
- case $dst in
- */) dst=$dst$dstbase;;
- *) dst=$dst/$dstbase;;
- esac
- dstdir_status=0
- else
- 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
- '')
- # 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
- # The $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'.
- 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
-
- if
- $posix_mkdir && (
- umask $mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
- )
- then :
- else
-
- # mkdir does not conform to POSIX,
- # or it failed possibly due to a race condition. Create the
- # directory the slow way, step by step, checking for races as we go.
-
- case $dstdir in
- /*) prefix='/';;
- [-=\(\)!]*) prefix='./';;
- *) prefix='';;
- esac
-
- oIFS=$IFS
- IFS=/
- set -f
- set fnord $dstdir
- shift
- 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/
- 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
- fi
- fi
- fi
-
- if test -n "$dir_arg"; then
- { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
- { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
- test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
- else
-
- # Make a couple of temp file names in the proper directory.
- 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 &&
- { 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.
- #
- # If any of these fail, we abort the whole thing. If we want to
- # ignore errors from any of these, just make sure not to ignore
- # errors from the above "$doit $cpprog $src $dsttmp" command.
- #
- { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
- { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
- { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
-
- # 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` &&
- set -f &&
- set X $old && old=:$2:$4:$5:$6 &&
- set X $new && new=:$2:$4:$5:$6 &&
- set +f &&
- test "$old" = "$new" &&
- $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
- then
- rm -f "$dsttmp"
- else
- # If $backupsuffix is set, and the file being installed
- # already exists, attempt a backup. Don't worry if it fails,
- # e.g., if mv doesn't support -f.
- if test -n "$backupsuffix" && test -f "$dst"; then
- $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
- fi
-
- # Rename the file to the real destination.
- $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
-
- # The rename failed, perhaps because mv can't rename something else
- # 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 "$dst" 2>/dev/null ||
- { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
- { $doit $rmcmd "$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
-
- trap '' 0
- fi
-done
-
-# 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/contrib/sqlite3/ltmain.sh b/contrib/sqlite3/ltmain.sh
deleted file mode 100755
index 540a92ab5476..000000000000
--- a/contrib/sqlite3/ltmain.sh
+++ /dev/null
@@ -1,11251 +0,0 @@
-#! /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.6
-# Provide generalized library-building support services.
-# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-
-# 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.
-
-# 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.
-#
-# 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 this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-PROGRAM=libtool
-PACKAGE=libtool
-VERSION="2.4.6 Debian-2.4.6-15build2"
-package_revision=2.4.6
-
-
-## ------ ##
-## 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-01-20.17; # 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=:
- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else
- case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
-fi
-
-# 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 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
-
-# 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
-
-
-
-## ------------------------- ##
-## 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"}
-: ${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}"}
-
-
-## -------------------- ##
-## Useful sed snippets. ##
-## -------------------- ##
-
-sed_dirname='s|/[^/]*$||'
-sed_basename='s|^.*/||'
-
-# 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'
-
-# 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"
-
-
-## ----------------- ##
-## Global variables. ##
-## ----------------- ##
-
-# 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.
-
-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.
-
-# 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='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
-debug_cmd=${debug_cmd-":"}
-exit_cmd=:
-
-# 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
-
-# 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.
-progname=`$ECHO "$progpath" |$SED "$sed_basename"`
-
-# Make sure we have an absolute progpath for reexecution:
-case $progpath in
- [\\/]*|[A-Za-z]:\\*) ;;
- *[\\/]*)
- progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
- progdir=`cd "$progdir" && pwd`
- progpath=$progdir/$progname
- ;;
- *)
- _G_IFS=$IFS
- IFS=${PATH_SEPARATOR-:}
- for progdir in $PATH; do
- IFS=$_G_IFS
- test -x "$progdir/$progname" && break
- done
- IFS=$_G_IFS
- test -n "$progdir" || progdir=`pwd`
- progpath=$progdir/$progname
- ;;
-esac
-
-
-## ----------------- ##
-## Standard options. ##
-## ----------------- ##
-
-# 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.
-
-opt_dry_run=false
-opt_quiet=false
-opt_verbose=false
-
-# 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 ()
-{
- $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=:
-}
-
-
-## ----------------- ##
-## 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 ()
-{
- $debug_cmd
-
- 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_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_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 ()
-{
- $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_error ARG...
-# -----------------
-# Echo program name prefixed message to standard error.
-func_error ()
-{
- $debug_cmd
-
- $require_term_colors
-
- func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2
-}
-
-
-# func_fatal_error ARG...
-# -----------------------
-# Echo program name prefixed message to standard error, and exit.
-func_fatal_error ()
-{
- $debug_cmd
-
- func_error "$*"
- exit $EXIT_FAILURE
-}
-
-
-# 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_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 ()
-{
- $debug_cmd
-
- _G_directory_path=$1
- _G_dir_list=
-
- 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 "$_G_directory_path"; do
- # ...make a list in topmost first order. Use a colon delimited
- # list incase some portion of path contains whitespace.
- _G_dir_list=$_G_directory_path:$_G_dir_list
-
- # If the last portion added has no slash in it, the list is done
- case $_G_directory_path in */*) ;; *) break ;; esac
-
- # ...otherwise throw away the child directory and loop
- _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
- done
- _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
-
- 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 "$_G_dir" 2>/dev/null || :
- done
- IFS=$func_mkdir_p_IFS
-
- # Bail out if we (or some other process) failed to create a directory.
- test -d "$_G_directory_path" || \
- func_fatal_error "Failed to create '$1'"
- fi
-}
-
-
-# func_mktempdir [BASENAME]
-# -------------------------
-# Make a temporary directory that won't clash with other running
-# libtool processes, and avoids race conditions if possible. If
-# given, BASENAME is the basename for that directory.
-func_mktempdir ()
-{
- $debug_cmd
-
- _G_template=${TMPDIR-/tmp}/${1-$progname}
-
- if test : = "$opt_dry_run"; then
- # Return a directory name, but don't create it in dry-run mode
- _G_tmpdir=$_G_template-$$
- else
-
- # If mktemp works, use that first and foremost
- _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
-
- if test ! -d "$_G_tmpdir"; then
- # Failing that, at least try and use $RANDOM to avoid a race
- _G_tmpdir=$_G_template-${RANDOM-0}$$
-
- func_mktempdir_umask=`umask`
- umask 0077
- $MKDIR "$_G_tmpdir"
- umask $func_mktempdir_umask
- fi
-
- # If we're not in dry-run mode, bomb out on failure
- test -d "$_G_tmpdir" || \
- func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
- fi
-
- $ECHO "$_G_tmpdir"
-}
-
-
-# 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 ()
-{
- $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.
- ;;
- *)
- # 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 "$_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_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
- case $1 in
- *[\\\`\"\$]*)
- _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
- *)
- _G_unquoted_arg=$1 ;;
- esac
- 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
- *[\\\`\"]*)
- _G_arg=`$ECHO "$1" | $SED \
- -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
- *)
- _G_arg=$1 ;;
- esac
-
- 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.
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- _G_arg=\"$_G_arg\"
- ;;
- esac
-
- func_quote_for_expand_result=$_G_arg
-}
-
-
-# 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 ()
-{
- $debug_cmd
-
- _G_cmd=$1
- _G_fail_exp=${2-':'}
-
- func_quote_for_expand "$_G_cmd"
- eval "func_notquiet $func_quote_for_expand_result"
-
- $opt_dry_run || {
- eval "$_G_cmd"
- _G_status=$?
- if test 0 -ne "$_G_status"; then
- eval "(exit $_G_status); $_G_fail_exp"
- fi
- }
-}
-
-
-# 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 ()
-{
- $debug_cmd
-
- _G_cmd=$1
- _G_fail_exp=${2-':'}
-
- $opt_quiet || {
- func_quote_for_expand "$_G_cmd"
- eval "func_echo $func_quote_for_expand_result"
- }
-
- $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
- }
-}
-
-
-# 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 ()
-{
- $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_verbose ARG...
-# -------------------
-# Echo program name prefixed message in verbose mode only.
-func_verbose ()
-{
- $debug_cmd
-
- $opt_verbose && func_echo "$*"
-
- :
-}
-
-
-# func_warn_and_continue ARG...
-# -----------------------------
-# Echo program name prefixed warning message to standard error.
-func_warn_and_continue ()
-{
- $debug_cmd
-
- $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_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=2015-10-07.11; # 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
-
- _G_rc_run_hooks=false
-
- 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
- if eval $_G_hook '"$@"'; then
- # 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
- _G_rc_run_hooks=:
- fi
- done
-
- $_G_rc_run_hooks && func_run_hooks_result=$_G_hook_result
-}
-
-
-
-## --------------- ##
-## Option parsing. ##
-## --------------- ##
-
-# In order to add your own option parsing hooks, you must accept the
-# full positional parameter list in your hook function, you may remove/edit
-# any options that you action, and then pass back the remaining unprocessed
-# options in '<hooked_function_name>_result', escaped suitably for
-# 'eval'. In this case you also must return $EXIT_SUCCESS to let the
-# hook's caller know that it should pay attention to
-# '<hooked_function_name>_result'. Returning $EXIT_FAILURE signalizes that
-# arguments are left untouched by the hook and therefore caller will ignore the
-# result variable.
-#
-# Like this:
-#
-# my_options_prep ()
-# {
-# $debug_cmd
-#
-# # Extend the existing usage message.
-# usage_message=$usage_message'
-# -s, --silent don'\''t print informational messages
-# '
-# # No change in '$@' (ignored completely by this hook). There is
-# # no need to do the equivalent (but slower) action:
-# # func_quote_for_eval ${1+"$@"}
-# # my_options_prep_result=$func_quote_for_eval_result
-# false
-# }
-# func_add_hook func_options_prep my_options_prep
-#
-#
-# my_silent_option ()
-# {
-# $debug_cmd
-#
-# args_changed=false
-#
-# # 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=:
-# args_changed=:
-# ;;
-# # 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
-# args_changed=:
-# ;;
-# *) # Make sure the first unrecognised option "$_G_opt"
-# # is added back to "$@", we could need that later
-# # if $args_changed is true.
-# set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
-# esac
-# done
-#
-# if $args_changed; then
-# func_quote_for_eval ${1+"$@"}
-# my_silent_option_result=$func_quote_for_eval_result
-# fi
-#
-# $args_changed
-# }
-# 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."
-#
-# false
-# }
-# func_add_hook func_validate_options my_option_validation
-#
-# You'll also 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_finish [ARG]...
-# ----------------------------
-# Finishing the option parse loop (call 'func_options' hooks ATM).
-func_options_finish ()
-{
- $debug_cmd
-
- _G_func_options_finish_exit=false
- if func_run_hooks func_options ${1+"$@"}; then
- func_options_finish_result=$func_run_hooks_result
- _G_func_options_finish_exit=:
- fi
-
- $_G_func_options_finish_exit
-}
-
-
-# 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
-
- _G_rc_options=false
-
- for my_func in options_prep parse_options validate_options options_finish
- do
- if eval func_$my_func '${1+"$@"}'; then
- eval _G_res_var='$'"func_${my_func}_result"
- eval set dummy "$_G_res_var" ; shift
- _G_rc_options=:
- fi
- done
-
- # Save modified positional parameters for caller. As a top-level
- # options-parser function we always need to set the 'func_options_result'
- # variable (regardless the $_G_rc_options value).
- if $_G_rc_options; then
- func_options_result=$_G_res_var
- else
- func_quote_for_eval ${1+"$@"}
- func_options_result=$func_quote_for_eval_result
- fi
-
- $_G_rc_options
-}
-
-
-# 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 propagate that back to rest of this script, then the complete
-# modified list must be put in 'func_run_hooks_result' before
-# returning $EXIT_SUCCESS (otherwise $EXIT_FAILURE is returned).
-func_hookable func_options_prep
-func_options_prep ()
-{
- $debug_cmd
-
- # Option defaults:
- opt_verbose=false
- opt_warning_types=
-
- _G_rc_options_prep=false
- if func_run_hooks func_options_prep ${1+"$@"}; then
- _G_rc_options_prep=:
- # save modified positional parameters for caller
- func_options_prep_result=$func_run_hooks_result
- fi
-
- $_G_rc_options_prep
-}
-
-
-# func_parse_options [ARG]...
-# ---------------------------
-# The main option parsing loop.
-func_hookable func_parse_options
-func_parse_options ()
-{
- $debug_cmd
-
- func_parse_options_result=
-
- _G_rc_parse_options=false
- # 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.
- if func_run_hooks func_parse_options ${1+"$@"}; then
- eval set dummy "$func_run_hooks_result"; shift
- _G_rc_parse_options=:
- fi
-
- # Break out of the loop if we already parsed every option.
- test $# -gt 0 || break
-
- _G_match_parse_options=:
- _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)
- if test $# = 0 && func_missing_arg $_G_opt; then
- _G_rc_parse_options=:
- break
- fi
- 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
- ;;
-
- --) _G_rc_parse_options=: ; break ;;
- -*) func_fatal_help "unrecognised option: '$_G_opt'" ;;
- *) set dummy "$_G_opt" ${1+"$@"}; shift
- _G_match_parse_options=false
- break
- ;;
- esac
-
- $_G_match_parse_options && _G_rc_parse_options=:
- done
-
-
- if $_G_rc_parse_options; then
- # save modified positional parameters for caller
- func_quote_for_eval ${1+"$@"}
- func_parse_options_result=$func_quote_for_eval_result
- fi
-
- $_G_rc_parse_options
-}
-
-
-# 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
-
- _G_rc_validate_options=false
-
- # Display all warnings if -W was not given.
- test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
-
- if func_run_hooks func_validate_options ${1+"$@"}; then
- # save modified positional parameters for caller
- func_validate_options_result=$func_run_hooks_result
- _G_rc_validate_options=:
- fi
-
- # Bail if the options were screwed!
- $exit_cmd $EXIT_FAILURE
-
- $_G_rc_validate_options
-}
-
-
-
-## ----------------- ##
-## 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 ()
-{
- $debug_cmd
-
- func_usage_message
- $ECHO "$long_help_message"
- exit 0
-}
-
-
-# func_missing_arg ARGNAME
-# ------------------------
-# Echo program name prefixed message to standard error and set global
-# exit_cmd.
-func_missing_arg ()
-{
- $debug_cmd
-
- func_error "Missing argument for '$1'."
- exit_cmd=exit
-}
-
-
-# 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.
-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 ()
-{
- $debug_cmd
-
- func_usage_message
- $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
- exit 0
-}
-
-
-# func_usage_message
-# ------------------
-# Echo short help message to standard output.
-func_usage_message ()
-{
- $debug_cmd
-
- eval \$ECHO \""Usage: $usage"\"
- echo
- $SED -n 's|^# ||
- /^Written by/{
- x;p;x
- }
- h
- /^Written by/q' < "$progpath"
- echo
- eval \$ECHO \""$usage_message"\"
-}
-
-
-# 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 $?
-}
-
-
-# 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:
-
-# Set a version string.
-scriptversion='(GNU libtool) 2.4.6'
-
-
-# func_echo ARG...
-# ----------------
-# Libtool also displays the current mode in messages, so override
-# funclib.sh func_echo with this custom definition.
-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${opt_mode+: $opt_mode}: $_G_line"
- done
- IFS=$func_echo_IFS
-}
-
-
-# func_warning ARG...
-# -------------------
-# Libtool warnings are not categorized, so override funclib.sh
-# func_warning with this simpler definition.
-func_warning ()
-{
- $debug_cmd
-
- $warning_func ${1+"$@"}
-}
-
-
-## ---------------- ##
-## 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
-"
-
-# Additional text appended to 'usage_message' in response to '--help'.
-func_help ()
-{
- $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 $scriptversion Debian-2.4.6-15build2
- 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/s/libtool/>.
-General help using GNU software: <http://www.gnu.org/gethelp/>."
- exit 0
-}
-
-
-# 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_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__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 ()
-{
- re_begincf='^# ### BEGIN LIBTOOL'
- re_endcf='^# ### END LIBTOOL'
-
- # Default configuration.
- $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
-
- # Now print the configurations for the tags.
- for tagname in $taglist; do
- $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
- done
-
- exit $?
-}
-
-
-# func_features
-# -------------
-# Display the features supported by this script.
-func_features ()
-{
- echo "host: $host"
- if test yes = "$build_libtool_libs"; then
- echo "enable shared libraries"
- else
- echo "disable shared libraries"
- fi
- if test yes = "$build_old_libs"; then
- echo "enable static libraries"
- else
- echo "disable static libraries"
- fi
-
- exit $?
-}
-
-
-# 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
-
- 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
-
- # 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
-}
-
-
-# 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
-$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
-$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
-$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
-
- exit $EXIT_MISMATCH
- fi
-}
-
-
-# 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=
-
- _G_rc_lt_options_prep=:
-
- # 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
- ;;
- *)
- _G_rc_lt_options_prep=false
- ;;
- esac
-
- if $_G_rc_lt_options_prep; then
- # Pass back the list of options.
- func_quote_for_eval ${1+"$@"}
- libtool_options_prep_result=$func_quote_for_eval_result
- fi
-
- $_G_rc_lt_options_prep
-}
-func_add_hook func_options_prep libtool_options_prep
-
-
-# libtool_parse_options [ARG]...
-# ---------------------------------
-# Provide handling for libtool specific options.
-libtool_parse_options ()
-{
- $debug_cmd
-
- _G_rc_lt_parse_options=false
-
- # Perform our own loop to consume as many options as possible in
- # each iteration.
- while test $# -gt 0; do
- _G_match_lt_parse_options=:
- _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
- _G_match_lt_parse_options=false
- break
- ;;
- esac
- $_G_match_lt_parse_options && _G_rc_lt_parse_options=:
- done
-
- if $_G_rc_lt_parse_options; then
- # save modified positional parameters for caller
- func_quote_for_eval ${1+"$@"}
- libtool_parse_options_result=$func_quote_for_eval_result
- fi
-
- $_G_rc_lt_parse_options
-}
-func_add_hook func_parse_options libtool_parse_options
-
-
-
-# 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
-
- # preserve --debug
- test : = "$debug_cmd" || func_append preserve_args " --debug"
-
- 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
-
- $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"
-
- # 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
-
-
-
-## ----------- ##
-## 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.
-# 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 | func_generated_by_libtool_p
-}
-
-# func_lalib_unsafe_p 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.
-func_lalib_unsafe_p ()
-{
- lalib_p=no
- if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
- for lalib_p_l in 1 2 3 4
- do
- read lalib_p_line
- case $lalib_p_line in
- \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
- esac
- done
- exec 0<&5 5<&-
- fi
- test yes = "$lalib_p"
-}
-
-# func_ltwrapper_script_p file
-# True iff FILE is a libtool wrapper script
-# This function is only a basic sanity check; it will hardly flush out
-# determined imposters.
-func_ltwrapper_script_p ()
-{
- test -f "$1" &&
- $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
-}
-
-# func_ltwrapper_executable_p file
-# True iff FILE is a libtool wrapper executable
-# This function is only a basic sanity check; it will hardly flush out
-# determined imposters.
-func_ltwrapper_executable_p ()
-{
- func_ltwrapper_exec_suffix=
- case $1 in
- *.exe) ;;
- *) func_ltwrapper_exec_suffix=.exe ;;
- esac
- $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
-}
-
-# func_ltwrapper_scriptname file
-# Assumes file is an ltwrapper_executable
-# uses $file to determine the appropriate filename for a
-# temporary ltwrapper_script.
-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_p file
-# True iff FILE is a libtool wrapper script or wrapper executable
-# This function is only a basic sanity check; it will hardly flush out
-# determined imposters.
-func_ltwrapper_p ()
-{
- func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
-}
-
-
-# func_execute_cmds commands fail_cmd
-# Execute tilde-delimited COMMANDS.
-# If FAIL_CMD is given, eval that upon failure.
-# FAIL_CMD may read-access the current command in variable CMD!
-func_execute_cmds ()
-{
- $debug_cmd
-
- save_ifs=$IFS; IFS='~'
- for cmd in $1; do
- IFS=$sp$nl
- eval cmd=\"$cmd\"
- IFS=$save_ifs
- func_show_eval "$cmd" "${2-:}"
- done
- IFS=$save_ifs
-}
-
-
-# func_source file
-# Source FILE, adding directory component if necessary.
-# 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.
-func_source ()
-{
- $debug_cmd
-
- case $1 in
- */* | *\\*) . "$1" ;;
- *) . "./$1" ;;
- esac
-}
-
-
-# func_resolve_sysroot PATH
-# Replace a leading = in PATH with a sysroot. Store the result into
-# func_resolve_sysroot_result
-func_resolve_sysroot ()
-{
- func_resolve_sysroot_result=$1
- case $func_resolve_sysroot_result in
- =*)
- func_stripname '=' '' "$func_resolve_sysroot_result"
- func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
- ;;
- esac
-}
-
-# func_replace_sysroot PATH
-# If PATH begins with the sysroot, replace it with = and
-# store the result into func_replace_sysroot_result.
-func_replace_sysroot ()
-{
- case $lt_sysroot:$1 in
- ?*:"$lt_sysroot"*)
- func_stripname "$lt_sysroot" '' "$1"
- func_replace_sysroot_result='='$func_stripname_result
- ;;
- *)
- # Including no sysroot.
- func_replace_sysroot_result=$1
- ;;
- esac
-}
-
-# func_infer_tag arg
-# Infer tagged configuration to use if any are available and
-# if one wasn't chosen via the "--tag" command line option.
-# Only attempt this if the compiler in the base compile
-# command doesn't match the default compiler.
-# arg is usually of the form 'gcc ...'
-func_infer_tag ()
-{
- $debug_cmd
-
- if test -n "$available_tags" && test -z "$tagname"; then
- CC_quoted=
- for arg in $CC; do
- func_append_quoted CC_quoted "$arg"
- done
- CC_expanded=`func_echo_all $CC`
- CC_quoted_expanded=`func_echo_all $CC_quoted`
- case $@ in
- # Blanks in the command may have been stripped by the calling shell,
- # but not from the CC environment variable when configure was run.
- " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
- " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
- # Blanks at the start of $base_compile will cause this to fail
- # if we don't check for them as well.
- *)
- 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`"
- CC_quoted=
- for arg in $CC; do
- # Double-quote args containing other shell metacharacters.
- func_append_quoted CC_quoted "$arg"
- done
- CC_expanded=`func_echo_all $CC`
- CC_quoted_expanded=`func_echo_all $CC_quoted`
- case "$@ " in
- " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
- " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
- # The compiler in the base compile command matches
- # the one in the tagged configuration.
- # Assume this is the tagged configuration we want.
- tagname=$z
- break
- ;;
- esac
- fi
- done
- # If $tagname still isn't set, then no tagged configuration
- # was found and let the user know that the "--tag" command
- # 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'"
-# else
-# func_verbose "using $tagname tagged configuration"
- fi
- ;;
- esac
- fi
-}
-
-
-
-# func_write_libtool_object output_name pic_name nonpic_name
-# Create a libtool object file (analogous to a ".la" file),
-# but don't create it if we're doing a dry run.
-func_write_libtool_object ()
-{
- write_libobj=$1
- if test yes = "$build_libtool_libs"; then
- write_lobj=\'$2\'
- else
- write_lobj=none
- fi
-
- if test yes = "$build_old_libs"; then
- write_oldobj=\'$3\'
- else
- write_oldobj=none
- fi
-
- $opt_dry_run || {
- cat >${write_libobj}T <<EOF
-# $write_libobj - a libtool object file
-# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# Name of the PIC object.
-pic_object=$write_lobj
-
-# Name of the non-PIC object
-non_pic_object=$write_oldobj
-
-EOF
- $MV "${write_libobj}T" "$write_libobj"
- }
-}
-
-
-##################################################
-# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
-##################################################
-
-# func_convert_core_file_wine_to_w32 ARG
-# Helper function used by file name conversion functions when $build is *nix,
-# and $host is mingw, cygwin, or some other w32 environment. Relies on a
-# correctly configured wine environment available, with the winepath program
-# in $build's $PATH.
-#
-# ARG is the $build file name to be converted to w32 format.
-# Result is available in $func_convert_core_file_wine_to_w32_result, and will
-# be empty on error (or when ARG is empty)
-func_convert_core_file_wine_to_w32 ()
-{
- $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
- # command is not found, the shell will set an exit code of 127 and print
- # *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
- func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
- $SED -e "$sed_naive_backslashify"`
- else
- func_convert_core_file_wine_to_w32_result=
- fi
- fi
-}
-# end: func_convert_core_file_wine_to_w32
-
-
-# func_convert_core_path_wine_to_w32 ARG
-# Helper function used by path conversion functions when $build is *nix, and
-# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
-# configured wine environment available, with the winepath program in $build's
-# $PATH. Assumes ARG has no leading or trailing path separator characters.
-#
-# ARG is path to be converted from $build format to win32.
-# Result is available in $func_convert_core_path_wine_to_w32_result.
-# Unconvertible file (directory) names in ARG are skipped; if no directory names
-# are convertible, then the result may be empty.
-func_convert_core_path_wine_to_w32 ()
-{
- $debug_cmd
-
- # unfortunately, winepath doesn't convert paths, only file names
- 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 -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
- else
- func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
- fi
- fi
- done
- IFS=$oldIFS
- fi
-}
-# end: func_convert_core_path_wine_to_w32
-
-
-# func_cygpath ARGS...
-# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
-# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
-# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
-# (2), returns the Cygwin file name or path in func_cygpath_result (input
-# file name or path is assumed to be in w32 format, as previously converted
-# from $build's *nix or MSYS format). In case (3), returns the w32 file name
-# or path in func_cygpath_result (input file name or path is assumed to be in
-# Cygwin format). Returns an empty string on error.
-#
-# ARGS are passed to cygpath, with the last one being the file name or path to
-# be converted.
-#
-# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
-# environment variable; do not put it in $PATH.
-func_cygpath ()
-{
- $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
- # on failure, ensure result is empty
- func_cygpath_result=
- fi
- else
- func_cygpath_result=
- func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
- fi
-}
-#end: func_cygpath
-
-
-# func_convert_core_msys_to_w32 ARG
-# Convert file name or path ARG from MSYS format to w32 format. Return
-# result in func_convert_core_msys_to_w32_result.
-func_convert_core_msys_to_w32 ()
-{
- $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 "$sed_naive_backslashify"`
-}
-#end: func_convert_core_msys_to_w32
-
-
-# func_convert_file_check ARG1 ARG2
-# Verify that ARG1 (a file name in $build format) was converted to $host
-# format in ARG2. Otherwise, emit an error message, but continue (resetting
-# func_to_host_file_result to ARG1).
-func_convert_file_check ()
-{
- $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 "Continuing, but uninstalled executables may not work."
- # Fallback:
- func_to_host_file_result=$1
- fi
-}
-# end func_convert_file_check
-
-
-# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
-# Verify that FROM_PATH (a path in $build format) was converted to $host
-# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
-# func_to_host_file_result to a simplistic fallback value (see below).
-func_convert_path_check ()
-{
- $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 "Continuing, but uninstalled executables may not work."
- # Fallback. This is a deliberately simplistic "conversion" and
- # should not be "improved". See libtool.info.
- if test "x$1" != "x$2"; then
- lt_replace_pathsep_chars="s|$1|$2|g"
- func_to_host_path_result=`echo "$3" |
- $SED -e "$lt_replace_pathsep_chars"`
- else
- func_to_host_path_result=$3
- fi
- fi
-}
-# end func_convert_path_check
-
-
-# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
-# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
-# and appending REPL if ORIG matches BACKPAT.
-func_convert_path_front_back_pathsep ()
-{
- $debug_cmd
-
- case $4 in
- $1 ) func_to_host_path_result=$3$func_to_host_path_result
- ;;
- esac
- case $4 in
- $2 ) func_append func_to_host_path_result "$3"
- ;;
- esac
-}
-# end func_convert_path_front_back_pathsep
-
-
-##################################################
-# $build to $host FILE NAME CONVERSION FUNCTIONS #
-##################################################
-# 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.
-
-
-# func_to_host_file ARG
-# Converts the file name ARG from $build format to $host format. Return result
-# in func_to_host_file_result.
-func_to_host_file ()
-{
- $debug_cmd
-
- $to_host_file_cmd "$1"
-}
-# end func_to_host_file
-
-
-# func_to_tool_file ARG LAZY
-# converts the file name ARG from $build format to toolchain format. Return
-# result in func_to_tool_file_result. If the conversion in use is listed
-# in (the comma separated) LAZY, no conversion takes place.
-func_to_tool_file ()
-{
- $debug_cmd
-
- case ,$2, in
- *,"$to_tool_file_cmd",*)
- func_to_tool_file_result=$1
- ;;
- *)
- $to_tool_file_cmd "$1"
- func_to_tool_file_result=$func_to_host_file_result
- ;;
- esac
-}
-# end func_to_tool_file
-
-
-# func_convert_file_noop ARG
-# Copy ARG to func_to_host_file_result.
-func_convert_file_noop ()
-{
- func_to_host_file_result=$1
-}
-# end func_convert_file_noop
-
-
-# func_convert_file_msys_to_w32 ARG
-# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
-# conversion to w32 is not available inside the cwrapper. Returns result in
-# func_to_host_file_result.
-func_convert_file_msys_to_w32 ()
-{
- $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
- fi
- func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_msys_to_w32
-
-
-# func_convert_file_cygwin_to_w32 ARG
-# Convert file name ARG from Cygwin to w32 format. Returns result in
-# func_to_host_file_result.
-func_convert_file_cygwin_to_w32 ()
-{
- $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.
- func_to_host_file_result=`cygpath -m "$1"`
- fi
- func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_cygwin_to_w32
-
-
-# func_convert_file_nix_to_w32 ARG
-# Convert file name ARG from *nix to w32 format. Requires a wine environment
-# and a working winepath. Returns result in func_to_host_file_result.
-func_convert_file_nix_to_w32 ()
-{
- $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
- fi
- func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_nix_to_w32
-
-
-# func_convert_file_msys_to_cygwin ARG
-# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
-# Returns result in func_to_host_file_result.
-func_convert_file_msys_to_cygwin ()
-{
- $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
- fi
- func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_msys_to_cygwin
-
-
-# func_convert_file_nix_to_cygwin ARG
-# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed
-# in a wine environment, working winepath, and LT_CYGPATH set. Returns result
-# in func_to_host_file_result.
-func_convert_file_nix_to_cygwin ()
-{
- $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
- fi
- func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_nix_to_cygwin
-
-
-#############################################
-# $build to $host PATH CONVERSION FUNCTIONS #
-#############################################
-# 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.
-#
-# Path separators are also converted from $build format to $host format. If
-# ARG begins or ends with a path separator character, it is preserved (but
-# converted to $host format) on output.
-#
-# All path conversion functions are named using the following convention:
-# file name conversion function : func_convert_file_X_to_Y ()
-# path conversion function : func_convert_path_X_to_Y ()
-# where, for any given $build/$host combination the 'X_to_Y' value is the
-# same. If conversion functions are added for new $build/$host combinations,
-# the two new functions must follow this pattern, or func_init_to_host_path_cmd
-# will break.
-
-
-# func_init_to_host_path_cmd
-# Ensures that function "pointer" variable $to_host_path_cmd is set to the
-# appropriate value, based on the value of $to_host_file_cmd.
-to_host_path_cmd=
-func_init_to_host_path_cmd ()
-{
- $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
- fi
-}
-
-
-# func_to_host_path ARG
-# Converts the path ARG from $build format to $host format. Return result
-# in func_to_host_path_result.
-func_to_host_path ()
-{
- $debug_cmd
-
- func_init_to_host_path_cmd
- $to_host_path_cmd "$1"
-}
-# end func_to_host_path
-
-
-# func_convert_path_noop ARG
-# Copy ARG to func_to_host_path_result.
-func_convert_path_noop ()
-{
- func_to_host_path_result=$1
-}
-# end func_convert_path_noop
-
-
-# func_convert_path_msys_to_w32 ARG
-# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
-# conversion to w32 is not available inside the cwrapper. Returns result in
-# func_to_host_path_result.
-func_convert_path_msys_to_w32 ()
-{
- $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 ';.';
- # and winepath ignores them completely.
- 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_convert_path_check : ";" \
- "$func_to_host_path_tmp1" "$func_to_host_path_result"
- func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
- fi
-}
-# end func_convert_path_msys_to_w32
-
-
-# func_convert_path_cygwin_to_w32 ARG
-# Convert path ARG from Cygwin to w32 format. Returns result in
-# func_to_host_file_result.
-func_convert_path_cygwin_to_w32 ()
-{
- $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_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
- func_convert_path_check : ";" \
- "$func_to_host_path_tmp1" "$func_to_host_path_result"
- func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
- fi
-}
-# end func_convert_path_cygwin_to_w32
-
-
-# func_convert_path_nix_to_w32 ARG
-# Convert path ARG from *nix to w32 format. Requires a wine environment and
-# a working winepath. Returns result in func_to_host_file_result.
-func_convert_path_nix_to_w32 ()
-{
- $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_convert_path_check : ";" \
- "$func_to_host_path_tmp1" "$func_to_host_path_result"
- func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
- fi
-}
-# end func_convert_path_nix_to_w32
-
-
-# func_convert_path_msys_to_cygwin ARG
-# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
-# Returns result in func_to_host_file_result.
-func_convert_path_msys_to_cygwin ()
-{
- $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_convert_path_check : : \
- "$func_to_host_path_tmp1" "$func_to_host_path_result"
- func_convert_path_front_back_pathsep ":*" "*:" : "$1"
- fi
-}
-# end func_convert_path_msys_to_cygwin
-
-
-# func_convert_path_nix_to_cygwin ARG
-# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a
-# a wine environment, working winepath, and LT_CYGPATH set. Returns result in
-# func_to_host_file_result.
-func_convert_path_nix_to_cygwin ()
-{
- $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 ';.', and winepath ignores them completely.
- func_stripname : : "$1"
- 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_convert_path_check : : \
- "$func_to_host_path_tmp1" "$func_to_host_path_result"
- func_convert_path_front_back_pathsep ":*" "*:" : "$1"
- fi
-}
-# 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 ()
-{
- $debug_cmd
-
- # Get the compilation command and the source file.
- base_compile=
- srcfile=$nonopt # always keep a non-empty value in "srcfile"
- suppress_opt=yes
- suppress_output=
- arg_mode=normal
- libobj=
- later=
- pie_flag=
-
- for arg
- do
- case $arg_mode in
- arg )
- # do not "continue". Instead, add this to base_compile
- lastarg=$arg
- arg_mode=normal
- ;;
-
- target )
- libobj=$arg
- arg_mode=normal
- continue
- ;;
-
- normal )
- # Accept any command-line options.
- case $arg in
- -o)
- test -n "$libobj" && \
- func_fatal_error "you cannot specify '-o' more than once"
- arg_mode=target
- continue
- ;;
-
- -pie | -fpie | -fPIE)
- func_append pie_flag " $arg"
- continue
- ;;
-
- -shared | -static | -prefer-pic | -prefer-non-pic)
- func_append later " $arg"
- continue
- ;;
-
- -no-suppress)
- suppress_opt=no
- continue
- ;;
-
- -Xcompiler)
- arg_mode=arg # the next one goes into the "base_compile" arg list
- continue # The current "srcfile" will either be retained or
- ;; # replaced later. I would guess that would be a bug.
-
- -Wc,*)
- func_stripname '-Wc,' '' "$arg"
- args=$func_stripname_result
- lastarg=
- save_ifs=$IFS; IFS=,
- for arg in $args; do
- IFS=$save_ifs
- func_append_quoted lastarg "$arg"
- done
- IFS=$save_ifs
- func_stripname ' ' '' "$lastarg"
- lastarg=$func_stripname_result
-
- # Add the arguments to base_compile.
- func_append base_compile " $lastarg"
- continue
- ;;
-
- *)
- # Accept the current argument as the source file.
- # The previous "srcfile" becomes the current argument.
- #
- lastarg=$srcfile
- srcfile=$arg
- ;;
- esac # case $arg
- ;;
- esac # case $arg_mode
-
- # Aesthetically quote the previous argument.
- func_append_quoted base_compile "$lastarg"
- done # for arg
-
- case $arg_mode in
- arg)
- func_fatal_error "you must specify an argument for -Xcompile"
- ;;
- target)
- 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
- }
- ;;
- esac
-
- # Recognize several different file suffixes.
- # If the user specifies -o file.o, it is replaced with file.lo
- case $libobj in
- *.[cCFSifmso] | \
- *.ada | *.adb | *.ads | *.asm | \
- *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
- *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
- func_xform "$libobj"
- libobj=$func_xform_result
- ;;
- esac
-
- case $libobj in
- *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
- *)
- func_fatal_error "cannot determine name of library object from '$libobj'"
- ;;
- esac
-
- func_infer_tag $base_compile
-
- for arg in $later; do
- case $arg in
- -shared)
- test yes = "$build_libtool_libs" \
- || func_fatal_configuration "cannot build a shared library"
- build_old_libs=no
- continue
- ;;
-
- -static)
- build_libtool_libs=no
- build_old_libs=yes
- continue
- ;;
-
- -prefer-pic)
- pic_mode=yes
- continue
- ;;
-
- -prefer-non-pic)
- pic_mode=no
- continue
- ;;
- esac
- done
-
- 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_dirname_and_basename "$obj" "/" ""
- 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 yes = "$build_old_libs"; then
- removelist="$obj $lobj $libobj ${libobj}T"
- else
- removelist="$lobj $libobj ${libobj}T"
- fi
-
- # On Cygwin there's no "real" PIC flag so we must build both object types
- case $host_os in
- cygwin* | mingw* | pw32* | os2* | cegcc*)
- pic_mode=default
- ;;
- esac
- 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 no = "$compiler_c_o"; then
- output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
- lockfile=$output_obj.lock
- else
- output_obj=
- need_locks=no
- lockfile=
- fi
-
- # 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 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 warn = "$need_locks"; then
- if test -f "$lockfile"; then
- $ECHO "\
-*** ERROR, $lockfile exists and contains:
-`cat $lockfile 2>/dev/null`
-
-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
-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."
-
- $opt_dry_run || $RM $removelist
- exit $EXIT_FAILURE
- fi
- func_append removelist " $output_obj"
- $ECHO "$srcfile" > "$lockfile"
- fi
-
- $opt_dry_run || $RM $removelist
- func_append removelist " $lockfile"
- trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
-
- func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
- srcfile=$func_to_tool_file_result
- func_quote_for_eval "$srcfile"
- qsrcfile=$func_quote_for_eval_result
-
- # Only build a PIC object if we are building libtool libraries.
- if test yes = "$build_libtool_libs"; then
- # Without this assignment, base_compile gets emptied.
- fbsd_hideous_sh_bug=$base_compile
-
- if test no != "$pic_mode"; then
- command="$base_compile $qsrcfile $pic_flag"
- else
- # Don't build PIC code
- command="$base_compile $qsrcfile"
- fi
-
- func_mkdir_p "$xdir$objdir"
-
- if test -z "$output_obj"; then
- # Place PIC objects in $objdir
- func_append command " -o $lobj"
- fi
-
- func_show_eval_locale "$command" \
- 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
-
- if test warn = "$need_locks" &&
- test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
- $ECHO "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$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
-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."
-
- $opt_dry_run || $RM $removelist
- exit $EXIT_FAILURE
- fi
-
- # Just move the object if needed, then go on to compile the next one
- if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
- func_show_eval '$MV "$output_obj" "$lobj"' \
- 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
- fi
-
- # Allow error messages only from the first compilation.
- 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 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 yes = "$compiler_c_o"; then
- func_append command " -o $obj"
- fi
-
- # Suppress compiler output if we already did a PIC compilation.
- func_append command "$suppress_output"
- func_show_eval_locale "$command" \
- '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
-
- if test warn = "$need_locks" &&
- test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
- $ECHO "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$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
-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."
-
- $opt_dry_run || $RM $removelist
- exit $EXIT_FAILURE
- fi
-
- # Just move the object if needed
- if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
- func_show_eval '$MV "$output_obj" "$obj"' \
- 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
- fi
- fi
-
- $opt_dry_run || {
- func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
-
- # Unlock the critical section if it was locked
- if test no != "$need_locks"; then
- removelist=$lockfile
- $RM "$lockfile"
- fi
- }
-
- exit $EXIT_SUCCESS
-}
-
-$opt_help || {
- test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
-}
-
-func_mode_help ()
-{
- # We need to display help for each of the modes.
- case $opt_mode in
- "")
- # Generic help is extracted from the usage comments
- # at the start of this file.
- func_help
- ;;
-
- clean)
- $ECHO \
-"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
-
-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
-to RM.
-
-If FILE is a libtool library, object or program, all the files associated
-with it are deleted. Otherwise, only FILE itself is deleted using RM."
- ;;
-
- compile)
- $ECHO \
-"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
-
-Compile a source file into a libtool library object.
-
-This mode accepts the following additional options:
-
- -o OUTPUT-FILE set the output file name to OUTPUT-FILE
- -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
- -Wc,FLAG pass FLAG directly to the compiler
-
-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'."
- ;;
-
- execute)
- $ECHO \
-"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
-
-Automatically set library path, then run a program.
-
-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'
-flags.
-
-If any of the ARGS are libtool executable wrappers, then they are translated
-into their corresponding uninstalled binary, and any of their required library
-directories are added to the library path.
-
-Then, COMMAND is executed, with ARGS as arguments."
- ;;
-
- finish)
- $ECHO \
-"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
-
-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."
- ;;
-
- install)
- $ECHO \
-"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
-
-Install executables or libraries.
-
-INSTALL-COMMAND is the installation command. The first component should be
-either the 'install' or 'cp' program.
-
-The following components of INSTALL-COMMAND are treated specially:
-
- -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation
-
-The rest of the components are interpreted as arguments to that command (only
-BSD-compatible install options are recognized)."
- ;;
-
- link)
- $ECHO \
-"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
-
-Link object files or libraries together to form another library, or to
-create an executable program.
-
-LINK-COMMAND is a command using the C compiler that you would use to create
-a program from several object files.
-
-The following components of LINK-COMMAND are treated specially:
-
- -all-static do not do any dynamic linking at all
- -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
- -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
- try to export only the symbols listed in SYMFILE
- -export-symbols-regex REGEX
- try to export only the symbols matching REGEX
- -LLIBDIR search LIBDIR for required installed libraries
- -lNAME OUTPUT-FILE requires the installed library libNAME
- -module build a library that can dlopened
- -no-fast-install disable the fast-install mode
- -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
- -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
- -rpath LIBDIR the created library will eventually be installed in LIBDIR
- -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
- -shared only do dynamic linking of libtool libraries
- -shrext SUFFIX override the standard shared library file extension
- -static do not do any dynamic linking of uninstalled libtool libraries
- -static-libtool-libs
- do not do any dynamic linking of libtool libraries
- -version-info CURRENT[:REVISION[:AGE]]
- specify library version info [each variable defaults to 0]
- -weak LIBNAME declare that the target provides the LIBNAME interface
- -Wc,FLAG
- -Xcompiler FLAG pass linker-specific FLAG directly to the compiler
- -Wl,FLAG
- -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.
-
-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
-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 '.lo' or '.$objext', then a reloadable object file
-is created, otherwise an executable program is created."
- ;;
-
- uninstall)
- $ECHO \
-"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
-
-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
-to RM.
-
-If FILE is a libtool library, all the files associated with it are deleted.
-Otherwise, only FILE itself is deleted using RM."
- ;;
-
- *)
- func_fatal_help "invalid operation mode '$opt_mode'"
- ;;
- esac
-
- echo
- $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
- func_mode_help
- else
- {
- func_help noexit
- for opt_mode in compile link execute install finish uninstall clean; do
- func_mode_help
- done
- } | $SED -n '1p; 2,$s/^Usage:/ or: /p'
- {
- func_help noexit
- for opt_mode in compile link execute install finish uninstall clean; do
- echo
- func_mode_help
- done
- } |
- $SED '1d
- /^When reporting/,/^Report/{
- H
- d
- }
- $x
- /information about other modes/d
- /more detailed .*MODE/d
- s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
- fi
- exit $?
-fi
-
-
-# func_mode_execute arg...
-func_mode_execute ()
-{
- $debug_cmd
-
- # The first argument is the command name.
- 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"
-
- dir=
- case $file in
- *.la)
- func_resolve_sysroot "$file"
- file=$func_resolve_sysroot_result
-
- # 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"
-
- # Read the libtool library.
- dlname=
- library_names=
- func_source "$file"
-
- # Skip this library if it cannot be dlopened.
- 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'"
- continue
- fi
-
- func_dirname "$file" "" "."
- 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'"
- fi
- fi
- ;;
-
- *.lo)
- # Just add the directory containing the .lo file.
- func_dirname "$file" "" "."
- dir=$func_dirname_result
- ;;
-
- *)
- 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
-
- # Now add the directory to shlibpath_var.
- if eval "test -z \"\$$shlibpath_var\""; then
- eval "$shlibpath_var=\"\$dir\""
- else
- eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
- fi
- done
-
- # This variable tells wrapper scripts just to set shlibpath_var
- # rather than running their programs.
- libtool_execute_magic=$magic
-
- # Check if any of the arguments is a wrapper script.
- args=
- for file
- do
- case $file in
- -* | *.la | *.lo ) ;;
- *)
- # Do a test to see if this is really a libtool program.
- if func_ltwrapper_script_p "$file"; then
- func_source "$file"
- # Transform arg to wrapped name.
- 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
- fi
- ;;
- esac
- # Quote arguments (to preserve shell metacharacters).
- func_append_quoted args "$file"
- done
-
- 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"
- fi
-
- # Restore saved environment variables
- for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
- do
- eval "if test \"\${save_$lt_var+set}\" = set; then
- $lt_var=\$save_$lt_var; export $lt_var
- else
- $lt_unset $lt_var
- fi"
- done
-
- # Now prepare to actually exec the command.
- exec_cmd=\$cmd$args
- fi
-}
-
-test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
-
-
-# func_mode_finish arg...
-func_mode_finish ()
-{
- $debug_cmd
-
- libs=
- libdirs=
- admincmds=
-
- for opt in "$nonopt" ${1+"$@"}
- do
- if test -d "$opt"; then
- func_append libdirs " $opt"
-
- elif test -f "$opt"; then
- if func_lalib_unsafe_p "$opt"; then
- func_append libs " $opt"
- else
- func_warning "'$opt' is not a valid libtool archive"
- fi
-
- else
- func_fatal_error "invalid argument '$opt'"
- fi
- done
-
- if test -n "$libs"; then
- if test -n "$lt_sysroot"; then
- sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
- sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
- else
- sysroot_cmd=
- fi
-
- # Remove sysroot references
- if $opt_dry_run; then
- for lib in $libs; do
- 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 \
- > $tmpdir/tmp-la
- mv -f $tmpdir/tmp-la $lib
- done
- ${RM}r "$tmpdir"
- fi
- fi
-
- if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
- for libdir in $libdirs; do
- if test -n "$finish_cmds"; then
- # Do each command in the finish commands.
- func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
-'"$cmd"'"'
- fi
- if test -n "$finish_eval"; then
- # Do the single finish_eval.
- eval cmds=\"$finish_eval\"
- $opt_dry_run || eval "$cmds" || func_append admincmds "
- $cmds"
- fi
- done
- fi
-
- # Exit here if they wanted silent mode.
- $opt_quiet && exit $EXIT_SUCCESS
-
- if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
- echo "----------------------------------------------------------------------"
- echo "Libraries have been installed in:"
- for libdir in $libdirs; do
- $ECHO " $libdir"
- done
- 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 "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 " during execution"
- fi
- if test -n "$runpath_var"; then
- 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"
- 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'"
- fi
- echo
-
- echo "See any operating system documentation about shared libraries for"
- case $host in
- solaris2.[6789]|solaris2.1[0-9])
- echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
- echo "pages."
- ;;
- *)
- echo "more information, such as the ld(1) and ld.so(8) manual pages."
- ;;
- esac
- echo "----------------------------------------------------------------------"
- fi
- exit $EXIT_SUCCESS
-}
-
-test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
-
-
-# func_mode_install arg...
-func_mode_install ()
-{
- $debug_cmd
-
- # There may be an optional sh(1) argument at the beginning of
- # install_prog (especially on Windows NT).
- if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
- # Allow the use of GNU shtool's install command.
- case $nonopt in *shtool*) :;; *) false;; esac
- then
- # Aesthetically quote it.
- func_quote_for_eval "$nonopt"
- install_prog="$func_quote_for_eval_result "
- arg=$1
- shift
- else
- install_prog=
- arg=$nonopt
- fi
-
- # The real first argument should be the name of the installation program.
- # Aesthetically quote it.
- func_quote_for_eval "$arg"
- func_append install_prog "$func_quote_for_eval_result"
- install_shared_prog=$install_prog
- case " $install_prog " in
- *[\\\ /]cp\ *) install_cp=: ;;
- *) install_cp=false ;;
- esac
-
- # We need to accept at least all the BSD install flags.
- dest=
- files=
- opts=
- prev=
- install_type=
- isdir=false
- stripme=
- no_mode=:
- for arg
- do
- arg2=
- if test -n "$dest"; then
- func_append files " $dest"
- dest=$arg
- continue
- fi
-
- case $arg in
- -d) isdir=: ;;
- -f)
- if $install_cp; then :; else
- prev=$arg
- fi
- ;;
- -g | -m | -o)
- prev=$arg
- ;;
- -s)
- stripme=" -s"
- continue
- ;;
- -*)
- ;;
- *)
- # If the previous option needed an argument, then skip it.
- if test -n "$prev"; then
- if test X-m = "X$prev" && test -n "$install_override_mode"; then
- arg2=$install_override_mode
- no_mode=false
- fi
- prev=
- else
- dest=$arg
- continue
- fi
- ;;
- esac
-
- # Aesthetically quote the argument.
- func_quote_for_eval "$arg"
- func_append install_prog " $func_quote_for_eval_result"
- if test -n "$arg2"; then
- func_quote_for_eval "$arg2"
- fi
- func_append install_shared_prog " $func_quote_for_eval_result"
- done
-
- test -z "$install_prog" && \
- func_fatal_help "you must specify an install program"
-
- test -n "$prev" && \
- func_fatal_help "the '$prev' option requires an argument"
-
- if test -n "$install_override_mode" && $no_mode; then
- if $install_cp; then :; else
- func_quote_for_eval "$install_override_mode"
- func_append install_shared_prog " -m $func_quote_for_eval_result"
- fi
- fi
-
- if test -z "$files"; then
- if test -z "$dest"; then
- func_fatal_help "no file or destination specified"
- else
- func_fatal_help "you must specify a destination"
- fi
- fi
-
- # Strip any trailing slash from the destination.
- func_stripname '' '/' "$dest"
- dest=$func_stripname_result
-
- # Check to see that the destination is a directory.
- test -d "$dest" && isdir=:
- if $isdir; then
- destdir=$dest
- destname=
- else
- func_dirname_and_basename "$dest" "" "."
- 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"
- fi
- case $destdir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- for file in $files; do
- case $file in
- *.lo) ;;
- *)
- func_fatal_help "'$destdir' must be an absolute directory name"
- ;;
- esac
- done
- ;;
- esac
-
- # This variable tells wrapper scripts just to set variables rather
- # than running their programs.
- libtool_install_magic=$magic
-
- staticlibs=
- future_libdirs=
- current_libdirs=
- for file in $files; do
-
- # Do each installation.
- case $file in
- *.$libext)
- # Do the static libraries later.
- func_append staticlibs " $file"
- ;;
-
- *.la)
- func_resolve_sysroot "$file"
- file=$func_resolve_sysroot_result
-
- # 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"
-
- library_names=
- old_library=
- relink_command=
- func_source "$file"
-
- # Add the libdir to current_libdirs if it is the destination.
- if test "X$destdir" = "X$libdir"; then
- case "$current_libdirs " in
- *" $libdir "*) ;;
- *) func_append current_libdirs " $libdir" ;;
- esac
- else
- # Note the libdir as a future libdir.
- case "$future_libdirs " in
- *" $libdir "*) ;;
- *) func_append future_libdirs " $libdir" ;;
- esac
- fi
-
- func_dirname "$file" "/" ""
- dir=$func_dirname_result
- func_append dir "$objdir"
-
- if test -n "$relink_command"; then
- # Determine the prefix the user has applied to our future dir.
- inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
-
- # Don't allow the user to place us outside of our expected
- # location b/c this prevents finding dependent libraries that
- # are installed to the same prefix.
- # At present, this check doesn't affect windows .dll's that
- # 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"
-
- if test -n "$inst_prefix_dir"; then
- # Stick the inst_prefix_dir data into the link command.
- relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
- else
- relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
- fi
-
- func_warning "relinking '$file'"
- func_show_eval "$relink_command" \
- '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
- shift
-
- 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
- case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
- case $realname in
- *.dll.a)
- tstripme=
- ;;
- esac
- ;;
- os2*)
- case $realname in
- *_dll.a)
- tstripme=
- ;;
- esac
- ;;
- esac
- if test -n "$tstripme" && test -n "$striplib"; then
- func_show_eval "$striplib $destdir/$realname" 'exit $?'
- fi
-
- if test "$#" -gt 0; then
- # Delete the old symlinks, and create new ones.
- # 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
- do
- test "$linkname" != "$realname" \
- && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
- done
- fi
-
- # Do each command in the postinstall commands.
- 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
- func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
-
- # Maybe install the static library, too.
- test -n "$old_library" && func_append staticlibs " $dir/$old_library"
- ;;
-
- *.lo)
- # Install (i.e. copy) a libtool object.
-
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile=$destdir/$destname
- else
- func_basename "$file"
- destfile=$func_basename_result
- destfile=$destdir/$destfile
- fi
-
- # Deduce the name of the destination old-style object file.
- case $destfile in
- *.lo)
- func_lo2o "$destfile"
- staticdest=$func_lo2o_result
- ;;
- *.$objext)
- staticdest=$destfile
- destfile=
- ;;
- *)
- func_fatal_help "cannot copy a libtool object to '$destfile'"
- ;;
- esac
-
- # Install the libtool object if requested.
- test -n "$destfile" && \
- func_show_eval "$install_prog $file $destfile" 'exit $?'
-
- # Install the old object if enabled.
- if test yes = "$build_old_libs"; then
- # Deduce the name of the old-style object file.
- func_lo2o "$file"
- staticobj=$func_lo2o_result
- func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
- fi
- exit $EXIT_SUCCESS
- ;;
-
- *)
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile=$destdir/$destname
- else
- func_basename "$file"
- 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=
- case $file in
- *.exe)
- if test ! -f "$file"; then
- func_stripname '' '.exe' "$file"
- file=$func_stripname_result
- stripped_ext=.exe
- fi
- ;;
- esac
-
- # Do a test to see if this is really a libtool program.
- case $host in
- *cygwin* | *mingw*)
- if func_ltwrapper_executable_p "$file"; then
- func_ltwrapper_scriptname "$file"
- wrapper=$func_ltwrapper_scriptname_result
- else
- func_stripname '' '.exe' "$file"
- wrapper=$func_stripname_result
- fi
- ;;
- *)
- wrapper=$file
- ;;
- esac
- if func_ltwrapper_script_p "$wrapper"; then
- notinst_deplibs=
- relink_command=
-
- func_source "$wrapper"
-
- # Check the variables that should have been set.
- test -z "$generated_by_libtool_version" && \
- func_fatal_error "invalid libtool wrapper script '$wrapper'"
-
- 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'`
- if test -n "$libdir" && test ! -f "$libfile"; then
- func_warning "'$lib' has not been installed in '$libdir'"
- finalize=false
- fi
- done
-
- relink_command=
- func_source "$wrapper"
-
- outputname=
- if test no = "$fast_install" && test -n "$relink_command"; then
- $opt_dry_run || {
- if $finalize; then
- tmpdir=`func_mktempdir`
- func_basename "$file$stripped_ext"
- file=$func_basename_result
- outputname=$tmpdir/$file
- # Replace the output file specification.
- relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
-
- $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"
- $opt_dry_run || ${RM}r "$tmpdir"
- continue
- fi
- file=$outputname
- else
- func_warning "cannot relink '$file'"
- fi
- }
- else
- # Install the binary that we compiled earlier.
- file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
- fi
- fi
-
- # remove .exe since cygwin /usr/bin/install will append another
- # one anyway
- case $install_prog,$host in
- */usr/bin/install*,*cygwin*)
- case $file:$destfile in
- *.exe:*.exe)
- # this is ok
- ;;
- *.exe:*)
- destfile=$destfile.exe
- ;;
- *:*.exe)
- func_stripname '' '.exe' "$destfile"
- destfile=$func_stripname_result
- ;;
- esac
- ;;
- esac
- func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
- $opt_dry_run || if test -n "$outputname"; then
- ${RM}r "$tmpdir"
- fi
- ;;
- esac
- done
-
- for file in $staticlibs; do
- func_basename "$file"
- name=$func_basename_result
-
- # Set up the ranlib parameters.
- oldlib=$destdir/$name
- func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
- tool_oldlib=$func_to_tool_file_result
-
- func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
-
- if test -n "$stripme" && test -n "$old_striplib"; then
- func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
- fi
-
- # Do each command in the postinstall commands.
- func_execute_cmds "$old_postinstall_cmds" 'exit $?'
- done
-
- test -n "$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'
- else
- exit $EXIT_SUCCESS
- fi
-}
-
-test install = "$opt_mode" && func_mode_install ${1+"$@"}
-
-
-# func_generate_dlsyms outputname originator pic_p
-# Extract symbols from dlprefiles and create ${outputname}S.o with
-# a dlpreopen symbol table.
-func_generate_dlsyms ()
-{
- $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 no != "$dlself"; then
- if test -n "$NM" && test -n "$global_symbol_pipe"; then
- my_dlsyms=${my_outputname}S.c
- else
- func_error "not configured to extract global symbols from dlpreopened files"
- fi
- fi
-
- if test -n "$my_dlsyms"; then
- case $my_dlsyms in
- "") ;;
- *.c)
- # Discover the nlist of each of the dlfiles.
- nlist=$output_objdir/$my_outputname.nm
-
- func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
-
- # Parse the name list into a source file.
- 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) $VERSION */
-
-#ifdef __cplusplus
-extern \"C\" {
-#endif
-
-#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 can't be const, because runtime
- relocations are performed -- see ld's documentation on pseudo-relocs. */
-# define LT_DLSYM_CONST
-#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 yes = "$dlself"; then
- func_verbose "generating symbol list for '$output'"
-
- $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
-
- # Add our own program objects to the symbol list.
- 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'"
- $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
- done
-
- if test -n "$exclude_expsyms"; then
- $opt_dry_run || {
- eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
- eval '$MV "$nlist"T "$nlist"'
- }
- fi
-
- if test -n "$export_symbols_regex"; then
- $opt_dry_run || {
- eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
- eval '$MV "$nlist"T "$nlist"'
- }
- fi
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- 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"'
- case $host in
- *cygwin* | *mingw* | *cegcc* )
- eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
- eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
- ;;
- esac
- }
- else
- $opt_dry_run || {
- 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
- *cygwin* | *mingw* | *cegcc* )
- eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
- eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
- ;;
- esac
- }
- fi
- fi
-
- for dlprefile in $dlprefiles; do
- func_verbose "extracting global C symbols from '$dlprefile'"
- func_basename "$dlprefile"
- 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=
- 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
- func_basename "$dlprefile_dlname"
- dlprefile_dlbasename=$func_basename_result
- else
- # no lafile. user explicitly requested -dlpreopen <import library>.
- $sharedlib_from_linklib_cmd "$dlprefile"
- dlprefile_dlbasename=$sharedlib_from_linklib_result
- fi
- fi
- $opt_dry_run || {
- if test -n "$dlprefile_dlbasename"; then
- eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
- else
- func_warning "Could not compute DLL name from $name"
- eval '$ECHO ": $name " >> "$nlist"'
- fi
- func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
- eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
- $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
- }
- else # not an import lib
- $opt_dry_run || {
- eval '$ECHO ": $name " >> "$nlist"'
- func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
- eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
- }
- fi
- ;;
- *)
- $opt_dry_run || {
- eval '$ECHO ": $name " >> "$nlist"'
- func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
- eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
- }
- ;;
- esac
- done
-
- $opt_dry_run || {
- # Make sure we have at least an empty file.
- test -f "$nlist" || : > "$nlist"
-
- if test -n "$exclude_expsyms"; then
- $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
- $MV "$nlist"T "$nlist"
- fi
-
- # Try sorting and uniquifying the output.
- if $GREP -v "^: " < "$nlist" |
- if sort -k 3 </dev/null >/dev/null 2>&1; then
- sort -k 3
- else
- sort +2
- fi |
- uniq > "$nlist"S; then
- :
- else
- $GREP -v "^: " < "$nlist" > "$nlist"S
- fi
-
- if test -f "$nlist"S; then
- eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
- else
- 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. */
-typedef struct {
- const char *name;
- void *address;
-} lt_dlsymlist;
-extern LT_DLSYM_CONST lt_dlsymlist
-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},"
-
- if test -s "$nlist"I; then
- echo >> "$output_objdir/$my_dlsyms" "\
- {\"@INIT@\", (void *) &lt_syminit},"
- fi
-
- case $need_lib_prefix in
- no)
- eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
- ;;
- *)
- eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
- ;;
- esac
- echo >> "$output_objdir/$my_dlsyms" "\
- {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
- return lt_${my_prefix}_LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif\
-"
- } # !$opt_dry_run
-
- pic_flag_for_symtable=
- case "$compile_command " in
- *" -static "*) ;;
- *)
- case $host in
- # compiling the symbol table file with pic_flag works around
- # a FreeBSD bug that causes programs to crash when -lm is
- # linked before any other PIC object. But we must not use
- # pic_flag when linking with -static. The problem exists in
- # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
- *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
- pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
- *-*-hpux*)
- pic_flag_for_symtable=" $pic_flag" ;;
- *)
- $my_pic_p && pic_flag_for_symtable=" $pic_flag"
- ;;
- esac
- ;;
- esac
- symtab_cflags=
- for arg in $LTCFLAGS; do
- case $arg in
- -pie | -fpie | -fPIE) ;;
- *) func_append symtab_cflags " $arg" ;;
- esac
- done
-
- # Now compile the dynamic symbol file.
- 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" "${nlist}I"'
-
- # Transform the symbol file into the correct name.
- symfileobj=$output_objdir/${my_outputname}S.$objext
- case $host in
- *cygwin* | *mingw* | *cegcc* )
- if test -f "$output_objdir/$my_outputname.def"; then
- compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
- finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
- else
- compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
- finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
- fi
- ;;
- *)
- compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
- finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
- ;;
- esac
- ;;
- *)
- func_fatal_error "unknown suffix for '$my_dlsyms'"
- ;;
- esac
- else
- # We keep going just in case the user didn't refer to
- # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
- # really was required.
-
- # Nullify the symbol file.
- compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
- finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
- 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'
-#
-# Need a lot of goo to handle *both* DLLs and import libs
-# Has to be a shell function in order to 'eat' the argument
-# that is supplied when $file_magic_command is called.
-# Despite the name, also deal with 64 bit binaries.
-func_win32_libid ()
-{
- $debug_cmd
-
- win32_libid_type=unknown
- win32_fileres=`file -L $1 2>/dev/null`
- case $win32_fileres in
- *ar\ archive\ import\ library*) # definitely import
- win32_libid_type="x86 archive import"
- ;;
- *ar\ archive*) # could be an import, or static
- # 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
- 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|
- p
- q
- }
- }'`
- ;;
- esac
- case $win32_nmres in
- import*) win32_libid_type="x86 archive import";;
- *) win32_libid_type="x86 archive static";;
- esac
- fi
- ;;
- *DLL*)
- win32_libid_type="x86 DLL"
- ;;
- *executable*) # but shell scripts are "executable" too...
- case $win32_fileres in
- *MS\ Windows\ PE\ Intel*)
- win32_libid_type="x86 DLL"
- ;;
- esac
- ;;
- esac
- $ECHO "$win32_libid_type"
-}
-
-# func_cygming_dll_for_implib ARG
-#
-# Platform-specific function to extract the
-# name of the DLL associated with the specified
-# import library ARG.
-# Invoked by eval'ing the libtool variable
-# $sharedlib_from_linklib_cmd
-# Result is available in the variable
-# $sharedlib_from_linklib_result
-func_cygming_dll_for_implib ()
-{
- $debug_cmd
-
- sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
-}
-
-# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
-#
-# The is the core of a fallback implementation of a
-# platform-specific function to extract the name of the
-# DLL associated with the specified import library LIBNAME.
-#
-# SECTION_NAME is either .idata$6 or .idata$7, depending
-# on the platform and compiler that created the implib.
-#
-# Echos the name of the DLL associated with the
-# specified import library.
-func_cygming_dll_for_implib_fallback_core ()
-{
- $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"':/{
- # Place marker at beginning of archive member dllname section
- s/.*/====MARK====/
- p
- d
- }
- # These lines can sometimes be longer than 43 characters, but
- # are always uninteresting
- /:[ ]*file format pe[i]\{,1\}-/d
- /^In archive [^:]*:/d
- # Ensure marker is printed
- /^====MARK====/p
- # Remove all lines with less than 43 characters
- /^.\{43\}/!d
- # From remaining lines, remove first 43 characters
- s/^.\{43\}//' |
- $SED -n '
- # Join marker and all lines until next marker into a single line
- /^====MARK====/ b para
- H
- $ b para
- b
- :para
- x
- s/\n//g
- # Remove the marker
- s/^====MARK====//
- # Remove trailing dots and whitespace
- s/[\. \t]*$//
- # Print
- /./p' |
- # we now have a list, one entry per line, of the stringified
- # contents of the appropriate section of all members of the
- # 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
- # begins with a literal '.' or a single character followed by
- # a '.'.
- #
- # Of those that remain, print the first one.
- $SED -e '/^\./d;/^.\./d;q'
-}
-
-# func_cygming_dll_for_implib_fallback ARG
-# Platform-specific function to extract the
-# name of the DLL associated with the specified
-# import library ARG.
-#
-# This fallback implementation is for use when $DLLTOOL
-# does not support the --identify-strict option.
-# Invoked by eval'ing the libtool variable
-# $sharedlib_from_linklib_cmd
-# Result is available in the variable
-# $sharedlib_from_linklib_result
-func_cygming_dll_for_implib_fallback ()
-{
- $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
- # ms-generated import library
- sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
- else
- # unknown
- sharedlib_from_linklib_result=
- fi
-}
-
-
-# func_extract_an_archive dir oldlib
-func_extract_an_archive ()
-{
- $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"
- sleep 2
- done
- 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 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
- :
- else
- func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
- fi
-}
-
-
-# func_extract_archives gentop oldlib ...
-func_extract_archives ()
-{
- $debug_cmd
-
- my_gentop=$1; shift
- my_oldlibs=${1+"$@"}
- 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 ;;
- *) my_xabs=`pwd`"/$my_xlib" ;;
- esac
- func_basename "$my_xlib"
- my_xlib=$func_basename_result
- my_xlib_u=$my_xlib
- while :; do
- case " $extracted_archives " in
- *" $my_xlib_u "*)
- func_arith $extracted_serial + 1
- extracted_serial=$func_arith_result
- my_xlib_u=lt$extracted_serial-$my_xlib ;;
- *) break ;;
- esac
- done
- extracted_archives="$extracted_archives $my_xlib_u"
- my_xdir=$my_gentop/$my_xlib_u
-
- func_mkdir_p "$my_xdir"
-
- case $host in
- *-darwin*)
- func_verbose "Extracting $my_xabs"
- # Do not bother doing anything if just a dry run
- $opt_dry_run || {
- darwin_orig_dir=`pwd`
- cd $my_xdir || exit $?
- darwin_archive=$my_xabs
- darwin_curdir=`pwd`
- 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"
- cd "$darwin_curdir"
- $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 "$sed_basename" | sort -u`
- darwin_file=
- darwin_files=
- for darwin_file in $darwin_filelist; do
- darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
- $LIPO -create -output "$darwin_file" $darwin_files
- done # $darwin_filelist
- $RM -rf unfat-$$
- cd "$darwin_orig_dir"
- else
- cd $darwin_orig_dir
- func_extract_an_archive "$my_xdir" "$my_xabs"
- fi # $darwin_arches
- } # !$opt_dry_run
- ;;
- *)
- func_extract_an_archive "$my_xdir" "$my_xabs"
- ;;
- esac
- my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
- done
-
- func_extract_archives_result=$my_oldobjs
-}
-
-
-# func_emit_wrapper [arg=no]
-#
-# Emit a libtool wrapper script on stdout.
-# Don't directly open a file because we may want to
-# incorporate the script contents within a cygwin/mingw
-# wrapper executable. Must ONLY be called from within
-# func_mode_link because it depends on a number of variables
-# set therein.
-#
-# 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 where it is stored is
-# the $objdir directory. This is a cygwin/mingw-specific
-# behavior.
-func_emit_wrapper ()
-{
- func_emit_wrapper_arg1=${1-no}
-
- $ECHO "\
-#! $SHELL
-
-# $output - temporary wrapper script for $objdir/$outputname
-# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
-#
-# The $output program cannot be directly executed until all the libtool
-# libraries that it depends on are installed.
-#
-# This wrapper script should never be moved out of the build directory.
-# If it is, it will not operate correctly.
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-sed_quote_subst='$sed_quote_subst'
-
-# Be Bourne compatible
-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
- # is contrary to our usage. Disable this feature.
- alias -g '\${1+\"\$@\"}'='\"\$@\"'
- setopt NO_GLOB_SUBST
-else
- case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
-fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-relink_command=\"$relink_command\"
-
-# This environment variable determines our operation mode.
-if test \"\$libtool_install_magic\" = \"$magic\"; then
- # install mode needs the following variables:
- generated_by_libtool_version='$macro_version'
- notinst_deplibs='$notinst_deplibs'
-else
- # When we are sourced in execute mode, \$file and \$ECHO are already set.
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- file=\"\$0\""
-
- qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
- $ECHO "\
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
- eval 'cat <<_LTECHO_EOF
-\$1
-_LTECHO_EOF'
-}
- ECHO=\"$qECHO\"
- fi
-
-# Very basic option parsing. These options are (a) specific to
-# the libtool wrapper, (b) are identical between the wrapper
-# /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 that match
-# this pattern).
-#
-# There are only two supported options: --lt-debug and
-# --lt-dump-script. There is, deliberately, no --lt-help.
-#
-# The first argument to this parsing function should be the
-# script's $0 value, followed by "$@".
-lt_option_debug=
-func_parse_lt_options ()
-{
- lt_script_arg0=\$0
- shift
- for lt_opt
- do
- case \"\$lt_opt\" in
- --lt-debug) lt_option_debug=1 ;;
- --lt-dump-script)
- lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
- test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
- lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
- cat \"\$lt_dump_D/\$lt_dump_F\"
- exit 0
- ;;
- --lt-*)
- \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
- exit 1
- ;;
- esac
- done
-
- # Print the debug banner immediately:
- if test -n \"\$lt_option_debug\"; then
- echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
- fi
-}
-
-# Used when --lt-debug. Prints its arguments to stdout
-# (redirection is the responsibility of the caller)
-func_lt_dump_args ()
-{
- lt_dump_args_N=1;
- for lt_arg
- do
- \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
- lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
- done
-}
-
-# Core function for launching the target application
-func_exec_program_core ()
-{
-"
- case $host in
- # Backslashes separate directories on plain windows
- *-*-mingw | *-*-os2* | *-cegcc*)
- $ECHO "\
- if test -n \"\$lt_option_debug\"; then
- \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
- func_lt_dump_args \${1+\"\$@\"} 1>&2
- fi
- exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
-"
- ;;
-
- *)
- $ECHO "\
- if test -n \"\$lt_option_debug\"; then
- \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
- func_lt_dump_args \${1+\"\$@\"} 1>&2
- fi
- exec \"\$progdir/\$program\" \${1+\"\$@\"}
-"
- ;;
- esac
- $ECHO "\
- \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
- exit 1
-}
-
-# A function to encapsulate launching the target application
-# Strips options in the --lt-* namespace from \$@ and
-# launches target application with the remaining arguments.
-func_exec_program ()
-{
- case \" \$* \" in
- *\\ --lt-*)
- for lt_wr_arg
- do
- case \$lt_wr_arg in
- --lt-*) ;;
- *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
- esac
- shift
- done ;;
- esac
- func_exec_program_core \${1+\"\$@\"}
-}
-
- # Parse options
- func_parse_lt_options \"\$0\" \${1+\"\$@\"}
-
- # Find the directory that this script lives in.
- thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
- test \"x\$thisdir\" = \"x\$file\" && thisdir=.
-
- # Follow symbolic links until we get to the real thisdir.
- file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
- while test -n \"\$file\"; do
- destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
-
- # If there was a directory component, then change thisdir.
- if test \"x\$destdir\" != \"x\$file\"; then
- case \"\$destdir\" in
- [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
- *) thisdir=\"\$thisdir/\$destdir\" ;;
- esac
- fi
-
- file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
- file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
- done
-
- # Usually 'no', except on cygwin/mingw when embedded into
- # the cwrapper.
- WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
- if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
- # special case for '.'
- if test \"\$thisdir\" = \".\"; then
- thisdir=\`pwd\`
- fi
- # remove .libs from thisdir
- case \"\$thisdir\" in
- *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
- $objdir ) thisdir=. ;;
- esac
- fi
-
- # Try to get the absolute directory name.
- absdir=\`cd \"\$thisdir\" && pwd\`
- test -n \"\$absdir\" && thisdir=\"\$absdir\"
-"
-
- 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\`; \\
- test \"X\$file\" != \"X\$progdir/\$program\"; }; then
-
- file=\"\$\$-\$program\"
-
- if test ! -d \"\$progdir\"; then
- $MKDIR \"\$progdir\"
- else
- $RM \"\$progdir/\$file\"
- fi"
-
- $ECHO "\
-
- # relink executable if necessary
- if test -n \"\$relink_command\"; then
- if relink_command_output=\`eval \$relink_command 2>&1\`; then :
- else
- \$ECHO \"\$relink_command_output\" >&2
- $RM \"\$progdir/\$file\"
- exit 1
- fi
- fi
-
- $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
- { $RM \"\$progdir/\$program\";
- $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
- $RM \"\$progdir/\$file\"
- fi"
- else
- $ECHO "\
- program='$outputname'
- progdir=\"\$thisdir/$objdir\"
-"
- fi
-
- $ECHO "\
-
- if test -f \"\$progdir/\$program\"; then"
-
- # fixup the dll searchpath if we need to.
- #
- # Fix the DLL searchpath if we need to. Do this before prepending
- # to shlibpath, because on Windows, both are PATH and uninstalled
- # libraries must come first.
- if test -n "$dllsearchpath"; then
- $ECHO "\
- # Add the dll search path components to the executable PATH
- PATH=$dllsearchpath:\$PATH
-"
- fi
-
- # Export our shlibpath_var if we have one.
- 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\"
-
- # Some systems cannot cope with colon-terminated $shlibpath_var
- # The second colon is a workaround for a bug in BeOS R4 sed
- $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
-
- export $shlibpath_var
-"
- fi
-
- $ECHO "\
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- # Run the actual program with our arguments.
- func_exec_program \${1+\"\$@\"}
- fi
- else
- # The program doesn't exist.
- \$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
- fi
-fi\
-"
-}
-
-
-# func_emit_cwrapperexe_src
-# emit the source code for a wrapper executable on stdout
-# Must ONLY be called from within func_mode_link because
-# it depends on a number of variable set therein.
-func_emit_cwrapperexe_src ()
-{
- cat <<EOF
-
-/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
- Generated by $PROGRAM (GNU $PACKAGE) $VERSION
-
- The $output program cannot be directly executed until all the libtool
- libraries that it depends on are installed.
-
- This wrapper executable should never be moved out of the build directory.
- If it is, it will not operate correctly.
-*/
-EOF
- cat <<"EOF"
-#ifdef _MSC_VER
-# define _CRT_SECURE_NO_DEPRECATE 1
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef _MSC_VER
-# include <direct.h>
-# include <process.h>
-# include <io.h>
-#else
-# include <unistd.h>
-# include <stdint.h>
-# ifdef __CYGWIN__
-# include <io.h>
-# endif
-#endif
-#include <malloc.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
-
-/* declarations of non-ANSI functions */
-#if defined __MINGW32__
-# ifdef __STRICT_ANSI__
-int _putenv (const char *);
-# endif
-#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_platform || defined ... */
-#endif
-
-/* portability defines, excluding path handling macros */
-#if defined _MSC_VER
-# define setmode _setmode
-# define stat _stat
-# define chmod _chmod
-# define getcwd _getcwd
-# define putenv _putenv
-# define S_IXUSR _S_IEXEC
-#elif defined __MINGW32__
-# define setmode _setmode
-# define stat _stat
-# define chmod _chmod
-# define getcwd _getcwd
-# define putenv _putenv
-#elif defined __CYGWIN__
-# define HAVE_SETENV
-# define FOPEN_WB "wb"
-/* #elif defined other platforms ... */
-#endif
-
-#if defined PATH_MAX
-# define LT_PATHMAX PATH_MAX
-#elif defined MAXPATHLEN
-# define LT_PATHMAX MAXPATHLEN
-#else
-# define LT_PATHMAX 1024
-#endif
-
-#ifndef S_IXOTH
-# define S_IXOTH 0
-#endif
-#ifndef S_IXGRP
-# define S_IXGRP 0
-#endif
-
-/* path handling portability macros */
-#ifndef DIR_SEPARATOR
-# define DIR_SEPARATOR '/'
-# define PATH_SEPARATOR ':'
-#endif
-
-#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
- defined __OS2__
-# define HAVE_DOS_BASED_FILE_SYSTEM
-# define FOPEN_WB "wb"
-# ifndef DIR_SEPARATOR_2
-# define DIR_SEPARATOR_2 '\\'
-# endif
-# ifndef PATH_SEPARATOR_2
-# define PATH_SEPARATOR_2 ';'
-# endif
-#endif
-
-#ifndef DIR_SEPARATOR_2
-# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
-#else /* DIR_SEPARATOR_2 */
-# define IS_DIR_SEPARATOR(ch) \
- (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
-#endif /* DIR_SEPARATOR_2 */
-
-#ifndef PATH_SEPARATOR_2
-# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
-#else /* PATH_SEPARATOR_2 */
-# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
-#endif /* PATH_SEPARATOR_2 */
-
-#ifndef FOPEN_WB
-# define FOPEN_WB "w"
-#endif
-#ifndef _O_BINARY
-# define _O_BINARY 0
-#endif
-
-#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
-#define XFREE(stale) do { \
- if (stale) { free (stale); stale = 0; } \
-} while (0)
-
-#if defined LT_DEBUGWRAPPER
-static int lt_debug = 1;
-#else
-static int lt_debug = 0;
-#endif
-
-const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
-
-void *xmalloc (size_t num);
-char *xstrdup (const char *string);
-const char *base_name (const char *name);
-char *find_executable (const char *wrapper);
-char *chase_symlinks (const char *pathspec);
-int make_executable (const char *path);
-int check_executable (const char *path);
-char *strendzap (char *str, const char *pat);
-void lt_debugprintf (const char *file, int line, const char *fmt, ...);
-void lt_fatal (const char *file, int line, const char *message, ...);
-static const char *nonnull (const char *s);
-static const char *nonempty (const char *s);
-void lt_setenv (const char *name, const char *value);
-char *lt_extend_str (const char *orig_value, const char *add, int to_end);
-void lt_update_exe_path (const char *name, const char *value);
-void lt_update_lib_path (const char *name, const char *value);
-char **prepare_spawn (char **argv);
-void lt_dump_script (FILE *f);
-EOF
-
- cat <<EOF
-#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 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";
-EOF
- else
- cat <<"EOF"
-const char * LIB_PATH_VALUE = "";
-EOF
- fi
-
- if test -n "$dllsearchpath"; then
- func_to_host_path "$dllsearchpath:"
- cat <<EOF
-const char * EXE_PATH_VARNAME = "PATH";
-const char * EXE_PATH_VALUE = "$func_to_host_path_result";
-EOF
- else
- cat <<"EOF"
-const char * EXE_PATH_VARNAME = "";
-const char * EXE_PATH_VALUE = "";
-EOF
- fi
-
- if test yes = "$fast_install"; then
- cat <<EOF
-const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
-EOF
- else
- cat <<EOF
-const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
-EOF
- fi
-
-
- cat <<"EOF"
-
-#define LTWRAPPER_OPTION_PREFIX "--lt-"
-
-static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
-static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
-static const char *debug_opt = LTWRAPPER_OPTION_PREFIX "debug";
-
-int
-main (int argc, char *argv[])
-{
- char **newargz;
- int newargc;
- char *tmp_pathspec;
- char *actual_cwrapper_path;
- char *actual_cwrapper_name;
- char *target_name;
- char *lt_argv_zero;
- int rval = 127;
-
- int i;
-
- program_name = (char *) xstrdup (base_name (argv[0]));
- 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
- * argz[0], which is handled differently
- */
- newargc=0;
- for (i = 1; i < argc; i++)
- {
- if (STREQ (argv[i], dumpscript_opt))
- {
-EOF
- case $host in
- *mingw* | *cygwin* )
- # make stdout use "unix" line endings
- echo " setmode(1,_O_BINARY);"
- ;;
- esac
-
- cat <<"EOF"
- lt_dump_script (stdout);
- return 0;
- }
- if (STREQ (argv[i], debug_opt))
- {
- lt_debug = 1;
- continue;
- }
- 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
- have already dealt with, above (inluding dump-script), then
- report an error. Otherwise, targets might begin to believe
- they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
- namespace. The first time any user complains about this, we'll
- need to make LTWRAPPER_OPTION_PREFIX a configure-time option
- or a configure.ac-settable value.
- */
- lt_fatal (__FILE__, __LINE__,
- "unrecognized %s option: '%s'",
- ltwrapper_option_prefix, argv[i]);
- }
- /* otherwise ... */
- newargz[++newargc] = xstrdup (argv[i]);
- }
- newargz[++newargc] = NULL;
-
-EOF
- cat <<EOF
- /* The GNU banner must be the first non-error debug message */
- lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
-EOF
- cat <<"EOF"
- lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
- lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
-
- tmp_pathspec = find_executable (argv[0]);
- if (tmp_pathspec == NULL)
- lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
- lt_debugprintf (__FILE__, __LINE__,
- "(main) found exe (before symlink chase) at: %s\n",
- tmp_pathspec);
-
- actual_cwrapper_path = chase_symlinks (tmp_pathspec);
- lt_debugprintf (__FILE__, __LINE__,
- "(main) found exe (after symlink chase) at: %s\n",
- actual_cwrapper_path);
- XFREE (tmp_pathspec);
-
- actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
- strendzap (actual_cwrapper_path, actual_cwrapper_name);
-
- /* wrapper name transforms */
- strendzap (actual_cwrapper_name, ".exe");
- tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
- XFREE (actual_cwrapper_name);
- actual_cwrapper_name = tmp_pathspec;
- tmp_pathspec = 0;
-
- /* target_name transforms -- use actual target program name; might have lt- prefix */
- target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
- strendzap (target_name, ".exe");
- tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
- XFREE (target_name);
- target_name = tmp_pathspec;
- tmp_pathspec = 0;
-
- lt_debugprintf (__FILE__, __LINE__,
- "(main) libtool target name: %s\n",
- target_name);
-EOF
-
- cat <<EOF
- newargz[0] =
- XMALLOC (char, (strlen (actual_cwrapper_path) +
- strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
- strcpy (newargz[0], actual_cwrapper_path);
- strcat (newargz[0], "$objdir");
- strcat (newargz[0], "/");
-EOF
-
- cat <<"EOF"
- /* stop here, and copy so we don't have to do this twice */
- tmp_pathspec = xstrdup (newargz[0]);
-
- /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
- strcat (newargz[0], actual_cwrapper_name);
-
- /* DO want the lt- prefix here if it exists, so use target_name */
- lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
- XFREE (tmp_pathspec);
- tmp_pathspec = NULL;
-EOF
-
- case $host_os in
- mingw*)
- cat <<"EOF"
- {
- char* p;
- while ((p = strchr (newargz[0], '\\')) != NULL)
- {
- *p = '/';
- }
- while ((p = strchr (lt_argv_zero, '\\')) != NULL)
- {
- *p = '/';
- }
- }
-EOF
- ;;
- esac
-
- cat <<"EOF"
- XFREE (target_name);
- XFREE (actual_cwrapper_path);
- XFREE (actual_cwrapper_name);
-
- lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
- lt_setenv ("DUALCASE", "1"); /* for MSK sh */
- /* Update the DLL searchpath. EXE_PATH_VALUE ($dllsearchpath) must
- be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
- because on Windows, both *_VARNAMEs are PATH but uninstalled
- libraries must come first. */
- lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
- lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
-
- lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
- nonnull (lt_argv_zero));
- for (i = 0; i < newargc; i++)
- {
- lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
- i, nonnull (newargz[i]));
- }
-
-EOF
-
- case $host_os in
- mingw*)
- cat <<"EOF"
- /* execv doesn't actually work on mingw as expected on unix */
- newargz = prepare_spawn (newargz);
- rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
- if (rval == -1)
- {
- /* failed to start process */
- lt_debugprintf (__FILE__, __LINE__,
- "(main) failed to launch target \"%s\": %s\n",
- lt_argv_zero, nonnull (strerror (errno)));
- return 127;
- }
- return rval;
-EOF
- ;;
- *)
- cat <<"EOF"
- execv (lt_argv_zero, newargz);
- return rval; /* =127, but avoids unused variable warning */
-EOF
- ;;
- esac
-
- cat <<"EOF"
-}
-
-void *
-xmalloc (size_t num)
-{
- void *p = (void *) malloc (num);
- if (!p)
- lt_fatal (__FILE__, __LINE__, "memory exhausted");
-
- return p;
-}
-
-char *
-xstrdup (const char *string)
-{
- return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
- string) : NULL;
-}
-
-const char *
-base_name (const char *name)
-{
- const char *base;
-
-#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;
-#endif
-
- for (base = name; *name; name++)
- if (IS_DIR_SEPARATOR (*name))
- base = name + 1;
- return base;
-}
-
-int
-check_executable (const char *path)
-{
- struct stat st;
-
- lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
- nonempty (path));
- if ((!path) || (!*path))
- return 0;
-
- if ((stat (path, &st) >= 0)
- && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
- return 1;
- else
- return 0;
-}
-
-int
-make_executable (const char *path)
-{
- int rval = 0;
- struct stat st;
-
- lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
- nonempty (path));
- if ((!path) || (!*path))
- return 0;
-
- if (stat (path, &st) >= 0)
- {
- rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
- }
- return rval;
-}
-
-/* Searches for the full path of the wrapper. Returns
- newly allocated full path name if found, NULL otherwise
- Does not chase symlinks, even on platforms that support them.
-*/
-char *
-find_executable (const char *wrapper)
-{
- int has_slash = 0;
- const char *p;
- const char *p_next;
- /* static buffer for getcwd */
- char tmp[LT_PATHMAX + 1];
- size_t tmp_len;
- char *concat_name;
-
- lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
- nonempty (wrapper));
-
- if ((wrapper == NULL) || (*wrapper == '\0'))
- return NULL;
-
- /* Absolute path? */
-#if defined HAVE_DOS_BASED_FILE_SYSTEM
- if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
- {
- concat_name = xstrdup (wrapper);
- if (check_executable (concat_name))
- return concat_name;
- XFREE (concat_name);
- }
- else
- {
-#endif
- if (IS_DIR_SEPARATOR (wrapper[0]))
- {
- concat_name = xstrdup (wrapper);
- if (check_executable (concat_name))
- return concat_name;
- XFREE (concat_name);
- }
-#if defined HAVE_DOS_BASED_FILE_SYSTEM
- }
-#endif
-
- for (p = wrapper; *p; p++)
- if (*p == '/')
- {
- has_slash = 1;
- break;
- }
- if (!has_slash)
- {
- /* no slashes; search PATH */
- const char *path = getenv ("PATH");
- if (path != NULL)
- {
- for (p = path; *p; p = p_next)
- {
- const char *q;
- size_t p_len;
- for (q = p; *q; q++)
- if (IS_PATH_SEPARATOR (*q))
- break;
- p_len = (size_t) (q - p);
- p_next = (*q == '\0' ? q : q + 1);
- if (p_len == 0)
- {
- /* empty path: current directory */
- if (getcwd (tmp, LT_PATHMAX) == NULL)
- lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
- nonnull (strerror (errno)));
- tmp_len = strlen (tmp);
- concat_name =
- XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
- memcpy (concat_name, tmp, tmp_len);
- concat_name[tmp_len] = '/';
- strcpy (concat_name + tmp_len + 1, wrapper);
- }
- else
- {
- concat_name =
- XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
- memcpy (concat_name, p, p_len);
- concat_name[p_len] = '/';
- strcpy (concat_name + p_len + 1, wrapper);
- }
- if (check_executable (concat_name))
- return concat_name;
- XFREE (concat_name);
- }
- }
- /* not found in PATH; assume curdir */
- }
- /* Relative path | not found in path: prepend cwd */
- if (getcwd (tmp, LT_PATHMAX) == NULL)
- lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
- nonnull (strerror (errno)));
- tmp_len = strlen (tmp);
- concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
- memcpy (concat_name, tmp, tmp_len);
- concat_name[tmp_len] = '/';
- strcpy (concat_name + tmp_len + 1, wrapper);
-
- if (check_executable (concat_name))
- return concat_name;
- XFREE (concat_name);
- return NULL;
-}
-
-char *
-chase_symlinks (const char *pathspec)
-{
-#ifndef S_ISLNK
- return xstrdup (pathspec);
-#else
- char buf[LT_PATHMAX];
- struct stat s;
- char *tmp_pathspec = xstrdup (pathspec);
- char *p;
- int has_symlinks = 0;
- while (strlen (tmp_pathspec) && !has_symlinks)
- {
- lt_debugprintf (__FILE__, __LINE__,
- "checking path component for symlinks: %s\n",
- tmp_pathspec);
- if (lstat (tmp_pathspec, &s) == 0)
- {
- if (S_ISLNK (s.st_mode) != 0)
- {
- has_symlinks = 1;
- break;
- }
-
- /* search backwards for last DIR_SEPARATOR */
- p = tmp_pathspec + strlen (tmp_pathspec) - 1;
- while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
- p--;
- if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
- {
- /* no more DIR_SEPARATORS left */
- break;
- }
- *p = '\0';
- }
- else
- {
- lt_fatal (__FILE__, __LINE__,
- "error accessing file \"%s\": %s",
- tmp_pathspec, nonnull (strerror (errno)));
- }
- }
- XFREE (tmp_pathspec);
-
- if (!has_symlinks)
- {
- return xstrdup (pathspec);
- }
-
- tmp_pathspec = realpath (pathspec, buf);
- if (tmp_pathspec == 0)
- {
- lt_fatal (__FILE__, __LINE__,
- "could not follow symlinks for %s", pathspec);
- }
- return xstrdup (tmp_pathspec);
-#endif
-}
-
-char *
-strendzap (char *str, const char *pat)
-{
- size_t len, patlen;
-
- assert (str != NULL);
- assert (pat != NULL);
-
- len = strlen (str);
- patlen = strlen (pat);
-
- if (patlen <= len)
- {
- str += len - patlen;
- if (STREQ (str, pat))
- *str = '\0';
- }
- return str;
-}
-
-void
-lt_debugprintf (const char *file, int line, const char *fmt, ...)
-{
- va_list args;
- if (lt_debug)
- {
- (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
- va_start (args, fmt);
- (void) vfprintf (stderr, fmt, args);
- va_end (args);
- }
-}
-
-static void
-lt_error_core (int exit_status, const char *file,
- int line, const char *mode,
- const char *message, va_list ap)
-{
- fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
- vfprintf (stderr, message, ap);
- fprintf (stderr, ".\n");
-
- if (exit_status >= 0)
- exit (exit_status);
-}
-
-void
-lt_fatal (const char *file, int line, const char *message, ...)
-{
- va_list ap;
- va_start (ap, message);
- lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
- va_end (ap);
-}
-
-static const char *
-nonnull (const char *s)
-{
- return s ? s : "(null)";
-}
-
-static const char *
-nonempty (const char *s)
-{
- return (s && !*s) ? "(empty)" : nonnull (s);
-}
-
-void
-lt_setenv (const char *name, const char *value)
-{
- lt_debugprintf (__FILE__, __LINE__,
- "(lt_setenv) setting '%s' to '%s'\n",
- nonnull (name), nonnull (value));
- {
-#ifdef HAVE_SETENV
- /* always make a copy, for consistency with !HAVE_SETENV */
- char *str = xstrdup (value);
- setenv (name, str, 1);
-#else
- 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)
- {
- XFREE (str);
- }
-#endif
- }
-}
-
-char *
-lt_extend_str (const char *orig_value, const char *add, int to_end)
-{
- char *new_value;
- if (orig_value && *orig_value)
- {
- 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)
- {
- strcpy (new_value, orig_value);
- strcpy (new_value + orig_value_len, add);
- }
- else
- {
- strcpy (new_value, add);
- strcpy (new_value + add_len, orig_value);
- }
- }
- else
- {
- new_value = xstrdup (add);
- }
- return new_value;
-}
-
-void
-lt_update_exe_path (const char *name, const char *value)
-{
- lt_debugprintf (__FILE__, __LINE__,
- "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
- nonnull (name), nonnull (value));
-
- if (name && *name && value && *value)
- {
- char *new_value = lt_extend_str (getenv (name), value, 0);
- /* some systems can't cope with a ':'-terminated path #' */
- size_t len = strlen (new_value);
- while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
- {
- new_value[--len] = '\0';
- }
- lt_setenv (name, new_value);
- XFREE (new_value);
- }
-}
-
-void
-lt_update_lib_path (const char *name, const char *value)
-{
- lt_debugprintf (__FILE__, __LINE__,
- "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
- nonnull (name), nonnull (value));
-
- if (name && *name && value && *value)
- {
- char *new_value = lt_extend_str (getenv (name), value, 0);
- lt_setenv (name, new_value);
- XFREE (new_value);
- }
-}
-
-EOF
- case $host_os in
- mingw*)
- cat <<"EOF"
-
-/* Prepares an argument vector before calling spawn().
- Note that spawn() does not by itself call the command interpreter
- (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
- ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&v);
- v.dwPlatformId == VER_PLATFORM_WIN32_NT;
- }) ? "cmd.exe" : "command.com").
- Instead it simply concatenates the arguments, separated by ' ', and calls
- CreateProcess(). We must quote the arguments since Win32 CreateProcess()
- interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
- special way:
- - Space and tab are interpreted as delimiters. They are not treated as
- delimiters if they are surrounded by double quotes: "...".
- - Unescaped double quotes are removed from the input. Their only effect is
- that within double quotes, space and tab are treated like normal
- characters.
- - Backslashes not followed by double quotes are not special.
- - But 2*n+1 backslashes followed by a double quote become
- n backslashes followed by a double quote (n >= 0):
- \" -> "
- \\\" -> \"
- \\\\\" -> \\"
- */
-#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
-#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
-char **
-prepare_spawn (char **argv)
-{
- size_t argc;
- char **new_argv;
- size_t i;
-
- /* Count number of arguments. */
- for (argc = 0; argv[argc] != NULL; argc++)
- ;
-
- /* Allocate new argument vector. */
- new_argv = XMALLOC (char *, argc + 1);
-
- /* Put quoted arguments into the new argument vector. */
- for (i = 0; i < argc; i++)
- {
- const char *string = argv[i];
-
- if (string[0] == '\0')
- new_argv[i] = xstrdup ("\"\"");
- else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
- {
- int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
- size_t length;
- unsigned int backslashes;
- const char *s;
- char *quoted_string;
- char *p;
-
- length = 0;
- backslashes = 0;
- if (quote_around)
- length++;
- for (s = string; *s != '\0'; s++)
- {
- char c = *s;
- if (c == '"')
- length += backslashes + 1;
- length++;
- if (c == '\\')
- backslashes++;
- else
- backslashes = 0;
- }
- if (quote_around)
- length += backslashes + 1;
-
- quoted_string = XMALLOC (char, length + 1);
-
- p = quoted_string;
- backslashes = 0;
- if (quote_around)
- *p++ = '"';
- for (s = string; *s != '\0'; s++)
- {
- char c = *s;
- if (c == '"')
- {
- unsigned int j;
- for (j = backslashes + 1; j > 0; j--)
- *p++ = '\\';
- }
- *p++ = c;
- if (c == '\\')
- backslashes++;
- else
- backslashes = 0;
- }
- if (quote_around)
- {
- unsigned int j;
- for (j = backslashes; j > 0; j--)
- *p++ = '\\';
- *p++ = '"';
- }
- *p = '\0';
-
- new_argv[i] = quoted_string;
- }
- else
- new_argv[i] = (char *) string;
- }
- new_argv[argc] = NULL;
-
- return new_argv;
-}
-EOF
- ;;
- esac
-
- cat <<"EOF"
-void lt_dump_script (FILE* f)
-{
-EOF
- func_emit_wrapper yes |
- $SED -n -e '
-s/^\(.\{79\}\)\(..*\)/\1\
-\2/
-h
-s/\([\\"]\)/\\\1/g
-s/$/\\n/
-s/\([^\n]*\).*/ fputs ("\1", f);/p
-g
-D'
- cat <<"EOF"
-}
-EOF
-}
-# end: func_emit_cwrapperexe_src
-
-# func_win32_import_lib_p ARG
-# True if ARG is an import lib, as indicated by $file_magic_cmd
-func_win32_import_lib_p ()
-{
- $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 ()
-{
- $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
- # 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 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.
- allow_undefined=yes
- ;;
- *)
- allow_undefined=yes
- ;;
- esac
- libtool_args=$nonopt
- base_compile="$nonopt $@"
- compile_command=$nonopt
- finalize_command=$nonopt
-
- compile_rpath=
- finalize_rpath=
- compile_shlibpath=
- finalize_shlibpath=
- convenience=
- old_convenience=
- deplibs=
- old_deplibs=
- compiler_flags=
- linker_flags=
- dllsearchpath=
- lib_search_path=`pwd`
- inst_prefix_dir=
- new_inherited_linker_flags=
-
- avoid_version=no
- bindir=
- dlfiles=
- dlprefiles=
- dlself=no
- export_dynamic=no
- export_symbols=
- export_symbols_regex=
- generated=
- libobjs=
- ltlibs=
- module=no
- no_install=no
- objs=
- os2dllname=
- non_pic_objects=
- precious_files_regex=
- prefer_static_libs=no
- preload=false
- prev=
- prevarg=
- release=
- rpath=
- xrpath=
- perm_rpath=
- temp_rpath=
- thread_safe=no
- vinfo=
- vinfo_number=no
- weak_libs=
- single_module=$wl-single_module
- func_infer_tag $base_compile
-
- # We need to know -static, to get the right output filenames.
- for arg
- do
- case $arg in
- -shared)
- 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 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
- dlopen_self=$dlopen_self_static
- fi
- prefer_static_libs=yes
- ;;
- -static)
- if test -z "$pic_flag" && test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- prefer_static_libs=built
- ;;
- -static-libtool-libs)
- if test -z "$pic_flag" && test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- prefer_static_libs=yes
- ;;
- esac
- build_libtool_libs=no
- build_old_libs=yes
- break
- ;;
- esac
- done
-
- # See if our shared archives depend on static archives.
- test -n "$old_archive_from_new_cmds" && build_old_libs=yes
-
- # Go through the arguments, transforming them on the way.
- while test "$#" -gt 0; do
- arg=$1
- shift
- func_quote_for_eval "$arg"
- qarg=$func_quote_for_eval_unquoted_result
- func_append libtool_args " $func_quote_for_eval_result"
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- case $prev in
- output)
- func_append compile_command " @OUTPUT@"
- func_append finalize_command " @OUTPUT@"
- ;;
- esac
-
- case $prev in
- bindir)
- bindir=$arg
- prev=
- continue
- ;;
- dlfiles|dlprefiles)
- $preload || {
- # Add the symbol object into the linking commands.
- func_append compile_command " @SYMFILE@"
- func_append finalize_command " @SYMFILE@"
- preload=:
- }
- case $arg in
- *.la | *.lo) ;; # We handle these cases below.
- force)
- if test no = "$dlself"; then
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- self)
- if test dlprefiles = "$prev"; then
- dlself=yes
- elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
- dlself=yes
- else
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- *)
- if test dlfiles = "$prev"; then
- func_append dlfiles " $arg"
- else
- func_append dlprefiles " $arg"
- fi
- prev=
- continue
- ;;
- esac
- ;;
- expsyms)
- export_symbols=$arg
- test -f "$arg" \
- || func_fatal_error "symbol file '$arg' does not exist"
- prev=
- continue
- ;;
- expsyms_regex)
- export_symbols_regex=$arg
- prev=
- continue
- ;;
- framework)
- case $host in
- *-*-darwin*)
- case "$deplibs " in
- *" $qarg.ltframework "*) ;;
- *) func_append deplibs " $qarg.ltframework" # this is fixed later
- ;;
- esac
- ;;
- esac
- prev=
- continue
- ;;
- inst_prefix)
- 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
- ;;
- objectlist)
- if test -f "$arg"; then
- save_arg=$arg
- moreargs=
- for fil in `cat "$save_arg"`
- do
-# func_append moreargs " $fil"
- arg=$fil
- # A libtool-controlled object.
-
- # Check to see that this really is a libtool object.
- if func_lalib_unsafe_p "$arg"; then
- pic_object=
- non_pic_object=
-
- # Read the .lo file
- func_source "$arg"
-
- if test -z "$pic_object" ||
- test -z "$non_pic_object" ||
- 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
-
- if test none != "$pic_object"; then
- # Prepend the subdirectory the object is found in.
- pic_object=$xdir$pic_object
-
- if test dlfiles = "$prev"; then
- if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
- func_append dlfiles " $pic_object"
- prev=
- continue
- else
- # If libtool objects are unsupported, then we need to preload.
- prev=dlprefiles
- fi
- fi
-
- # CHECK ME: I think I busted this. -Ossama
- if test dlprefiles = "$prev"; then
- # Preload the old-style object.
- func_append dlprefiles " $pic_object"
- prev=
- fi
-
- # A PIC object.
- func_append libobjs " $pic_object"
- arg=$pic_object
- fi
-
- # Non-PIC object.
- if test none != "$non_pic_object"; then
- # Prepend the subdirectory the object is found in.
- 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 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
- func_append non_pic_objects " $non_pic_object"
- fi
- else
- # Only an error if not doing a dry-run.
- if $opt_dry_run; then
- # Extract subdirectory from the argument.
- func_dirname "$arg" "/" ""
- xdir=$func_dirname_result
-
- func_lo2o "$arg"
- pic_object=$xdir$objdir/$func_lo2o_result
- non_pic_object=$xdir$func_lo2o_result
- func_append libobjs " $pic_object"
- func_append non_pic_objects " $non_pic_object"
- else
- func_fatal_error "'$arg' is not a valid libtool object"
- fi
- fi
- done
- else
- 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
- prev=
- continue
- ;;
- release)
- release=-$arg
- prev=
- continue
- ;;
- rpath | xrpath)
- # We need an absolute path.
- case $arg in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- func_fatal_error "only absolute run-paths are allowed"
- ;;
- esac
- if test rpath = "$prev"; then
- case "$rpath " in
- *" $arg "*) ;;
- *) func_append rpath " $arg" ;;
- esac
- else
- case "$xrpath " in
- *" $arg "*) ;;
- *) func_append xrpath " $arg" ;;
- esac
- fi
- prev=
- continue
- ;;
- shrext)
- shrext_cmds=$arg
- prev=
- continue
- ;;
- weak)
- func_append weak_libs " $arg"
- prev=
- continue
- ;;
- xcclinker)
- func_append linker_flags " $qarg"
- func_append compiler_flags " $qarg"
- prev=
- func_append compile_command " $qarg"
- func_append finalize_command " $qarg"
- continue
- ;;
- xcompiler)
- func_append compiler_flags " $qarg"
- prev=
- func_append compile_command " $qarg"
- func_append finalize_command " $qarg"
- continue
- ;;
- xlinker)
- func_append linker_flags " $qarg"
- func_append compiler_flags " $wl$qarg"
- prev=
- func_append compile_command " $wl$qarg"
- func_append finalize_command " $wl$qarg"
- continue
- ;;
- *)
- eval "$prev=\"\$arg\""
- prev=
- continue
- ;;
- esac
- fi # test -n "$prev"
-
- prevarg=$arg
-
- case $arg in
- -all-static)
- if test -n "$link_static_flag"; then
- # See comment for -static flag below, for more details.
- func_append compile_command " $link_static_flag"
- func_append finalize_command " $link_static_flag"
- fi
- continue
- ;;
-
- -allow-undefined)
- # FIXME: remove this flag sometime in the future.
- func_fatal_error "'-allow-undefined' must not be used because it is the default"
- ;;
-
- -avoid-version)
- avoid_version=yes
- continue
- ;;
-
- -bindir)
- prev=bindir
- continue
- ;;
-
- -dlopen)
- prev=dlfiles
- continue
- ;;
-
- -dlpreopen)
- prev=dlprefiles
- continue
- ;;
-
- -export-dynamic)
- export_dynamic=yes
- continue
- ;;
-
- -export-symbols | -export-symbols-regex)
- 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-export-symbols = "X$arg"; then
- prev=expsyms
- else
- prev=expsyms_regex
- fi
- continue
- ;;
-
- -framework)
- prev=framework
- continue
- ;;
-
- -inst-prefix-dir)
- prev=inst_prefix
- continue
- ;;
-
- # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
- # so, if we see these flags be careful not to treat them like -L
- -L[A-Z][A-Z]*:*)
- case $with_gcc/$host in
- no/*-*-irix* | /*-*-irix*)
- func_append compile_command " $arg"
- func_append finalize_command " $arg"
- ;;
- esac
- continue
- ;;
-
- -L*)
- 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'"
- else
- func_fatal_error "need path for '-L' option"
- fi
- fi
- func_resolve_sysroot "$func_stripname_result"
- dir=$func_resolve_sysroot_result
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- absdir=`cd "$dir" && pwd`
- test -z "$absdir" && \
- func_fatal_error "cannot determine absolute directory name of '$dir'"
- dir=$absdir
- ;;
- esac
- case "$deplibs " in
- *" -L$dir "* | *" $arg "*)
- # Will only happen for absolute or sysroot arguments
- ;;
- *)
- # Preserve sysroot, but never include relative directories
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
- *) func_append deplibs " -L$dir" ;;
- esac
- func_append lib_search_path " $dir"
- ;;
- esac
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
- testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
- case :$dllsearchpath: in
- *":$dir:"*) ;;
- ::) dllsearchpath=$dir;;
- *) func_append dllsearchpath ":$dir";;
- esac
- case :$dllsearchpath: in
- *":$testbindir:"*) ;;
- ::) dllsearchpath=$testbindir;;
- *) func_append dllsearchpath ":$testbindir";;
- esac
- ;;
- esac
- continue
- ;;
-
- -l*)
- 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)
- continue
- ;;
- *-*-os2*)
- # These systems don't actually have a C library (as such)
- test X-lc = "X$arg" && continue
- ;;
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
- # Do not include libc due to us having libc/libc_r.
- test X-lc = "X$arg" && continue
- ;;
- *-*-rhapsody* | *-*-darwin1.[012])
- # Rhapsody C and math libraries are in the System framework
- func_append deplibs " System.ltframework"
- continue
- ;;
- *-*-sco3.2v5* | *-*-sco5v6*)
- # Causes problems with __ctype
- test X-lc = "X$arg" && continue
- ;;
- *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
- # Compiler inserts libc in the correct place for threads to work
- test X-lc = "X$arg" && continue
- ;;
- esac
- elif test X-lc_r = "X$arg"; then
- case $host in
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
- # Do not include libc_r directly, use -pthread flag.
- continue
- ;;
- esac
- fi
- func_append deplibs " $arg"
- continue
- ;;
-
- -mllvm)
- prev=mllvm
- continue
- ;;
-
- -module)
- module=yes
- continue
- ;;
-
- # Tru64 UNIX uses -model [arg] to determine the layout of C++
- # classes, name mangling, and exception handling.
- # Darwin uses the -arch flag to determine output architecture.
- -model|-arch|-isysroot|--sysroot)
- func_append compiler_flags " $arg"
- func_append compile_command " $arg"
- func_append finalize_command " $arg"
- prev=xcompiler
- continue
- ;;
-
- -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
- |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
- func_append compiler_flags " $arg"
- func_append compile_command " $arg"
- func_append finalize_command " $arg"
- case "$new_inherited_linker_flags " in
- *" $arg "*) ;;
- * ) func_append new_inherited_linker_flags " $arg" ;;
- esac
- continue
- ;;
-
- -multi_module)
- single_module=$wl-multi_module
- continue
- ;;
-
- -no-fast-install)
- fast_install=no
- continue
- ;;
-
- -no-install)
- case $host in
- *-*-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"
- fast_install=no
- ;;
- *) no_install=yes ;;
- esac
- continue
- ;;
-
- -no-undefined)
- allow_undefined=no
- continue
- ;;
-
- -objectlist)
- prev=objectlist
- continue
- ;;
-
- -os2dllname)
- prev=os2dllname
- continue
- ;;
-
- -o) prev=output ;;
-
- -precious-files-regex)
- prev=precious_regex
- continue
- ;;
-
- -release)
- prev=release
- continue
- ;;
-
- -rpath)
- prev=rpath
- continue
- ;;
-
- -R)
- prev=xrpath
- continue
- ;;
-
- -R*)
- func_stripname '-R' '' "$arg"
- dir=$func_stripname_result
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- =*)
- func_stripname '=' '' "$dir"
- dir=$lt_sysroot$func_stripname_result
- ;;
- *)
- func_fatal_error "only absolute run-paths are allowed"
- ;;
- esac
- case "$xrpath " in
- *" $dir "*) ;;
- *) func_append xrpath " $dir" ;;
- esac
- continue
- ;;
-
- -shared)
- # The effects of -shared are defined in a previous loop.
- continue
- ;;
-
- -shrext)
- prev=shrext
- continue
- ;;
-
- -static | -static-libtool-libs)
- # The effects of -static are defined in a previous loop.
- # We used to do the same as -all-static on platforms that
- # didn't have a PIC flag, but the assumption that the effects
- # would be equivalent was wrong. It would break on at least
- # Digital Unix and AIX.
- continue
- ;;
-
- -thread-safe)
- thread_safe=yes
- continue
- ;;
-
- -version-info)
- prev=vinfo
- continue
- ;;
-
- -version-number)
- prev=vinfo
- vinfo_number=yes
- continue
- ;;
-
- -weak)
- prev=weak
- continue
- ;;
-
- -Wc,*)
- func_stripname '-Wc,' '' "$arg"
- args=$func_stripname_result
- arg=
- save_ifs=$IFS; IFS=,
- for flag in $args; do
- 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
- func_stripname ' ' '' "$arg"
- arg=$func_stripname_result
- ;;
-
- -Wl,*)
- func_stripname '-Wl,' '' "$arg"
- args=$func_stripname_result
- arg=
- save_ifs=$IFS; IFS=,
- for flag in $args; do
- 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
- func_stripname ' ' '' "$arg"
- arg=$func_stripname_result
- ;;
-
- -Xcompiler)
- prev=xcompiler
- continue
- ;;
-
- -Xlinker)
- prev=xlinker
- continue
- ;;
-
- -XCClinker)
- prev=xcclinker
- continue
- ;;
-
- # -msg_* for osf cc
- -msg_*)
- func_quote_for_eval "$arg"
- arg=$func_quote_for_eval_result
- ;;
-
- # Flags to be passed through unchanged, with rationale:
- # -64, -mips[0-9] enable 64-bit mode for the SGI compiler
- # -r[0-9][0-9]* specify processor for the SGI compiler
- # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
- # +DA*, +DD* enable 64-bit mode for the HP compiler
- # -q* compiler args for the IBM compiler
- # -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*, -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
- # -static-* direct GCC to link specific libraries statically
- # -fcilkplus Cilk Plus language extension features for C/C++
- -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*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
- -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus)
- func_quote_for_eval "$arg"
- 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
- ;;
-
- *.$objext)
- # A standard object.
- func_append objs " $arg"
- ;;
-
- *.lo)
- # A libtool-controlled object.
-
- # Check to see that this really is a libtool object.
- if func_lalib_unsafe_p "$arg"; then
- pic_object=
- non_pic_object=
-
- # Read the .lo file
- func_source "$arg"
-
- if test -z "$pic_object" ||
- test -z "$non_pic_object" ||
- 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
-
- test none = "$pic_object" || {
- # Prepend the subdirectory the object is found in.
- pic_object=$xdir$pic_object
-
- if test dlfiles = "$prev"; then
- if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
- func_append dlfiles " $pic_object"
- prev=
- continue
- else
- # If libtool objects are unsupported, then we need to preload.
- prev=dlprefiles
- fi
- fi
-
- # CHECK ME: I think I busted this. -Ossama
- if test dlprefiles = "$prev"; then
- # Preload the old-style object.
- func_append dlprefiles " $pic_object"
- prev=
- fi
-
- # A PIC object.
- func_append libobjs " $pic_object"
- arg=$pic_object
- }
-
- # Non-PIC object.
- if test none != "$non_pic_object"; then
- # Prepend the subdirectory the object is found in.
- 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 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
- func_append non_pic_objects " $non_pic_object"
- fi
- else
- # Only an error if not doing a dry-run.
- if $opt_dry_run; then
- # Extract subdirectory from the argument.
- func_dirname "$arg" "/" ""
- xdir=$func_dirname_result
-
- func_lo2o "$arg"
- pic_object=$xdir$objdir/$func_lo2o_result
- non_pic_object=$xdir$func_lo2o_result
- func_append libobjs " $pic_object"
- func_append non_pic_objects " $non_pic_object"
- else
- func_fatal_error "'$arg' is not a valid libtool object"
- fi
- fi
- ;;
-
- *.$libext)
- # An archive.
- func_append deplibs " $arg"
- func_append old_deplibs " $arg"
- continue
- ;;
-
- *.la)
- # A libtool-controlled library.
-
- func_resolve_sysroot "$arg"
- if test dlfiles = "$prev"; then
- # This library was specified with -dlopen.
- func_append dlfiles " $func_resolve_sysroot_result"
- prev=
- elif test dlprefiles = "$prev"; then
- # The library was specified with -dlpreopen.
- func_append dlprefiles " $func_resolve_sysroot_result"
- prev=
- else
- func_append deplibs " $func_resolve_sysroot_result"
- fi
- continue
- ;;
-
- # Some other compiler argument.
- *)
- # 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
- ;;
- esac # arg
-
- # Now actually substitute the argument into the commands.
- if test -n "$arg"; then
- func_append compile_command " $arg"
- func_append finalize_command " $arg"
- fi
- done # argument parsing loop
-
- test -n "$prev" && \
- func_fatal_help "the '$prevarg' option requires an argument"
-
- 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"
- fi
-
- oldlibs=
- # calculate the name of the file, without its directory
- func_basename "$output"
- 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\'\`
- 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
- func_to_tool_file "$output_objdir/"
- tool_output_objdir=$func_to_tool_file_result
- # Create the object directory.
- func_mkdir_p "$output_objdir"
-
- # Determine the type of output
- case $output in
- "")
- func_fatal_help "you must specify an output file"
- ;;
- *.$libext) linkmode=oldlib ;;
- *.lo | *.$objext) linkmode=obj ;;
- *.la) linkmode=lib ;;
- *) linkmode=prog ;; # Anything else should be a program.
- esac
-
- specialdeplibs=
-
- libs=
- # 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
- case "$libs " in
- *" $deplib "*) func_append specialdeplibs " $deplib" ;;
- esac
- fi
- func_append libs " $deplib"
- done
-
- if test lib = "$linkmode"; then
- libs="$predeps $libs $compiler_lib_search_path $postdeps"
-
- # Compute libraries that are listed more than once in $predeps
- # $postdeps and mark them as special (i.e., whose duplicates are
- # not to be eliminated).
- pre_post_deps=
- if $opt_duplicate_compiler_generated_deps; then
- for pre_post_dep in $predeps $postdeps; do
- case "$pre_post_deps " in
- *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
- esac
- func_append pre_post_deps " $pre_post_dep"
- done
- fi
- pre_post_deps=
- fi
-
- deplibs=
- newdependency_libs=
- newlib_search_path=
- need_relink=no # whether we're linking any uninstalled libtool libraries
- notinst_deplibs= # not-installed libtool libraries
- notinst_path= # paths that contain not-installed libtool libraries
-
- case $linkmode in
- lib)
- passes="conv dlpreopen link"
- for file in $dlfiles $dlprefiles; do
- case $file in
- *.la) ;;
- *)
- func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
- ;;
- esac
- done
- ;;
- prog)
- compile_deplibs=
- finalize_deplibs=
- alldeplibs=false
- newdlfiles=
- newdlprefiles=
- passes="conv scan dlopen dlpreopen link"
- ;;
- *) passes="conv"
- ;;
- esac
-
- 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 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
- fi
-
- if test lib,link = "$linkmode,$pass" ||
- test prog,scan = "$linkmode,$pass"; then
- libs=$deplibs
- deplibs=
- fi
- 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"
- ;;
- esac
- fi
- if test lib,dlpreopen = "$linkmode,$pass"; then
- # Collect and forward deplibs of preopened libtool libs
- for lib in $dlprefiles; do
- # Ignore non-libtool-libs
- dependency_libs=
- func_resolve_sysroot "$lib"
- case $lib in
- *.la) func_source "$func_resolve_sysroot_result" ;;
- esac
-
- # Collect preopened libtool deplibs, except any this library
- # has declared as weak libs
- for deplib in $dependency_libs; do
- func_basename "$deplib"
- deplib_base=$func_basename_result
- case " $weak_libs " in
- *" $deplib_base "*) ;;
- *) func_append deplibs " $deplib" ;;
- esac
- done
- done
- libs=$dlprefiles
- fi
- if test dlopen = "$pass"; then
- # Collect dlpreopened libraries
- save_deplibs=$deplibs
- deplibs=
- fi
-
- for deplib in $libs; do
- lib=
- found=false
- case $deplib in
- -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
- |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
- 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 lib = "$linkmode"; then
- case "$new_inherited_linker_flags " in
- *" $deplib "*) ;;
- * ) func_append new_inherited_linker_flags " $deplib" ;;
- esac
- fi
- fi
- continue
- ;;
- -l*)
- 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 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"
- fi
- 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
- if test -f "$lib"; then
- if test .la = "$search_ext"; then
- found=:
- else
- found=false
- fi
- break 2
- fi
- done
- done
- 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 yes = "$allow_libtool_libs_with_static_runtimes"; then
- case " $predeps $postdeps " in
- *" $deplib "*)
- if func_lalib_p "$lib"; then
- library_names=
- old_library=
- func_source "$lib"
- for l in $old_library $library_names; do
- ll=$l
- done
- if test "X$ll" = "X$old_library"; then # only static version available
- found=false
- func_dirname "$lib" "" "."
- ladir=$func_dirname_result
- lib=$ladir/$old_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
- fi
- ;;
- *) ;;
- 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 prog,link = "$linkmode,$pass"; then
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- deplibs="$deplib $deplibs"
- if test lib = "$linkmode"; then
- case "$new_inherited_linker_flags " in
- *" $deplib "*) ;;
- * ) func_append new_inherited_linker_flags " $deplib" ;;
- esac
- fi
- fi
- continue
- ;;
- -L*)
- case $linkmode in
- lib)
- deplibs="$deplib $deplibs"
- 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 conv = "$pass"; then
- deplibs="$deplib $deplibs"
- continue
- fi
- if test scan = "$pass"; then
- deplibs="$deplib $deplibs"
- else
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- fi
- func_stripname '-L' '' "$deplib"
- func_resolve_sysroot "$func_stripname_result"
- func_append newlib_search_path " $func_resolve_sysroot_result"
- ;;
- *)
- func_warning "'-L' is ignored for archives/objects"
- ;;
- esac # linkmode
- continue
- ;; # -L
- -R*)
- if test link = "$pass"; then
- func_stripname '-R' '' "$deplib"
- func_resolve_sysroot "$func_stripname_result"
- dir=$func_resolve_sysroot_result
- # Make sure the xrpath contains only unique directories.
- case "$xrpath " in
- *" $dir "*) ;;
- *) func_append xrpath " $dir" ;;
- esac
- fi
- deplibs="$deplib $deplibs"
- continue
- ;;
- *.la)
- func_resolve_sysroot "$deplib"
- lib=$func_resolve_sysroot_result
- ;;
- *.$libext)
- if test conv = "$pass"; then
- deplibs="$deplib $deplibs"
- continue
- fi
- case $linkmode in
- lib)
- # Linking convenience modules into shared libraries is allowed,
- # but linking other static libraries is non-portable.
- case " $dlpreconveniencelibs " in
- *" $deplib "*) ;;
- *)
- 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=:
- fi
- ;;
- pass_all)
- valid_a_lib=:
- ;;
- esac
- 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"
- 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 the file extensions .$libext of this argument makes me believe"
- echo "*** that it is just a static archive that I should not use here."
- fi
- ;;
- esac
- continue
- ;;
- prog)
- if test link != "$pass"; then
- deplibs="$deplib $deplibs"
- else
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- fi
- continue
- ;;
- esac # linkmode
- ;; # *.$libext
- *.lo | *.$objext)
- if test conv = "$pass"; then
- deplibs="$deplib $deplibs"
- 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"
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- func_append newdlfiles " $deplib"
- fi
- fi
- continue
- ;;
- %DEPLIBS%)
- alldeplibs=:
- continue
- ;;
- esac # case $deplib
-
- $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_dirname "$lib" "" "."
- ladir=$func_dirname_result
-
- dlname=
- dlopen=
- dlpreopen=
- libdir=
- library_names=
- old_library=
- inherited_linker_flags=
- # If the library was installed with an old release of libtool,
- # it will not redefine variables installed, or shouldnotlink
- installed=yes
- shouldnotlink=no
- avoidtemprpath=
-
-
- # Read the .la file
- func_source "$lib"
-
- # Convert "-framework foo" to "foo.ltframework"
- if test -n "$inherited_linker_flags"; then
- tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
- for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
- case " $new_inherited_linker_flags " in
- *" $tmp_inherited_linker_flag "*) ;;
- *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
- esac
- done
- fi
- dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
- 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 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'"
- 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 prog != "$linkmode" && test lib != "$linkmode"; then
- func_fatal_error "'$lib' is not a convenience library"
- fi
- continue
- fi # $pass = conv
-
-
- # Get the name of the library we link against.
- linklib=
- if test -n "$old_library" &&
- { 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
- done
- fi
- if test -z "$linklib"; then
- func_fatal_error "cannot find name of link library for '$lib'"
- fi
-
- # This library was specified with -dlopen.
- if test dlopen = "$pass"; then
- test -z "$libdir" \
- && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
- if test -z "$dlname" ||
- 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
- # bomb out in the load deplibs phase.
- func_append dlprefiles " $lib $dependency_libs"
- else
- func_append newdlfiles " $lib"
- fi
- continue
- fi # $pass = dlopen
-
- # We need an absolute path.
- case $ladir in
- [\\/]* | [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 "passing it literally to the linker, although it might fail"
- abs_ladir=$ladir
- fi
- ;;
- esac
- func_basename "$lib"
- laname=$func_basename_result
-
- # Find the relevant object directory and library name.
- 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
- else
- dir=$lt_sysroot$libdir
- absdir=$lt_sysroot$libdir
- fi
- test yes = "$hardcode_automatic" && avoidtemprpath=yes
- else
- if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
- dir=$ladir
- absdir=$abs_ladir
- # Remove this search path later
- func_append notinst_path " $abs_ladir"
- else
- dir=$ladir/$objdir
- absdir=$abs_ladir/$objdir
- # Remove this search path later
- func_append notinst_path " $abs_ladir"
- fi
- fi # $installed = yes
- func_stripname 'lib' '.la' "$laname"
- name=$func_stripname_result
-
- # This library was specified with -dlpreopen.
- 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
- # special handling for platforms with PE-DLLs.
- *cygwin* | *mingw* | *cegcc* )
- # Linker will automatically link against shared library if both
- # static and shared are present. Therefore, ensure we extract
- # symbols from the import library if a shared library is present
- # (otherwise, the dlopen module name will be incorrect). We do
- # this by putting the import library name into $newdlprefiles.
- # We recover the dlopen module name by 'saving' the la file
- # name in a special purpose variable, and (later) extracting the
- # dlname from the la file.
- if test -n "$dlname"; then
- func_tr_sh "$dir/$linklib"
- eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
- func_append newdlprefiles " $dir/$linklib"
- else
- func_append newdlprefiles " $dir/$old_library"
- # Keep a list of preopened convenience libraries to check
- # that they are being used correctly in the link pass.
- test -z "$libdir" && \
- func_append dlpreconveniencelibs " $dir/$old_library"
- fi
- ;;
- * )
- # Prefer using a static library (so that no silly _DYNAMIC symbols
- # are required to link).
- if test -n "$old_library"; then
- func_append newdlprefiles " $dir/$old_library"
- # Keep a list of preopened convenience libraries to check
- # that they are being used correctly in the link pass.
- test -z "$libdir" && \
- func_append dlpreconveniencelibs " $dir/$old_library"
- # Otherwise, use the dlname, so that lt_dlopen finds it.
- elif test -n "$dlname"; then
- func_append newdlprefiles " $dir/$dlname"
- else
- func_append newdlprefiles " $dir/$linklib"
- fi
- ;;
- esac
- fi # $pass = dlpreopen
-
- if test -z "$libdir"; then
- # Link the convenience library
- if test lib = "$linkmode"; then
- deplibs="$dir/$old_library $deplibs"
- elif test prog,link = "$linkmode,$pass"; then
- compile_deplibs="$dir/$old_library $compile_deplibs"
- finalize_deplibs="$dir/$old_library $finalize_deplibs"
- else
- deplibs="$lib $deplibs" # used for prog,scan pass
- fi
- continue
- fi
-
-
- if test prog = "$linkmode" && test link != "$pass"; then
- func_append newlib_search_path " $ladir"
- deplibs="$lib $deplibs"
-
- linkalldeplibs=false
- if test no != "$link_all_deplibs" || test -z "$library_names" ||
- test no = "$build_libtool_libs"; then
- linkalldeplibs=:
- fi
-
- tmp_libs=
- for deplib in $dependency_libs; do
- case $deplib in
- -L*) func_stripname '-L' '' "$deplib"
- func_resolve_sysroot "$func_stripname_result"
- func_append newlib_search_path " $func_resolve_sysroot_result"
- ;;
- esac
- # Need to link against all dependency_libs?
- 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
- case "$tmp_libs " in
- *" $deplib "*) func_append specialdeplibs " $deplib" ;;
- esac
- fi
- func_append tmp_libs " $deplib"
- done # for deplib
- continue
- fi # $linkmode = prog...
-
- if test prog,link = "$linkmode,$pass"; then
- if test -n "$library_names" &&
- { { 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
- # Make sure the rpath contains only unique directories.
- case $temp_rpath: in
- *"$absdir:"*) ;;
- *) func_append temp_rpath "$absdir:" ;;
- esac
- fi
-
- # Hardcode the library path.
- # Skip directories that are in the system default run-time
- # search path.
- case " $sys_lib_dlsearch_path " in
- *" $absdir "*) ;;
- *)
- case "$compile_rpath " in
- *" $absdir "*) ;;
- *) func_append compile_rpath " $absdir" ;;
- esac
- ;;
- esac
- case " $sys_lib_dlsearch_path " in
- *" $libdir "*) ;;
- *)
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) func_append finalize_rpath " $libdir" ;;
- esac
- ;;
- esac
- fi # $linkmode,$pass = prog,link...
-
- 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
- fi
- fi
-
- link_static=no # Whether the deplib will be linked statically
- use_static_libs=$prefer_static_libs
- if test built = "$use_static_libs" && test yes = "$installed"; then
- use_static_libs=no
- fi
- if test -n "$library_names" &&
- { test no = "$use_static_libs" || test -z "$old_library"; }; then
- case $host in
- *cygwin* | *mingw* | *cegcc* | *os2*)
- # No point in relinking DLLs because paths are not encoded
- func_append notinst_deplibs " $lib"
- need_relink=no
- ;;
- *)
- if test no = "$installed"; then
- func_append notinst_deplibs " $lib"
- need_relink=yes
- fi
- ;;
- esac
- # This is a shared library
-
- # Warn about portability, can't link against -module's on some
- # systems (darwin). Don't bleat about dlopened modules though!
- dlopenmodule=
- for dlpremoduletest in $dlprefiles; do
- if test "X$dlpremoduletest" = "X$lib"; then
- dlopenmodule=$dlpremoduletest
- break
- fi
- done
- if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
- echo
- 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 lib = "$linkmode" &&
- test yes = "$hardcode_into_libs"; then
- # Hardcode the library path.
- # Skip directories that are in the system default run-time
- # search path.
- case " $sys_lib_dlsearch_path " in
- *" $absdir "*) ;;
- *)
- case "$compile_rpath " in
- *" $absdir "*) ;;
- *) func_append compile_rpath " $absdir" ;;
- esac
- ;;
- esac
- case " $sys_lib_dlsearch_path " in
- *" $libdir "*) ;;
- *)
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) func_append finalize_rpath " $libdir" ;;
- esac
- ;;
- esac
- fi
-
- if test -n "$old_archive_from_expsyms_cmds"; then
- # figure out the soname
- set dummy $library_names
- shift
- 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
- elif test -n "$soname_spec"; then
- # bleh windows
- case $host in
- *cygwin* | mingw* | *cegcc* | *os2*)
- func_arith $current - $age
- major=$func_arith_result
- versuffix=-$major
- ;;
- esac
- eval soname=\"$soname_spec\"
- else
- soname=$realname
- fi
-
- # Make a new name for the extract_expsyms_cmds to use
- soroot=$soname
- func_basename "$soroot"
- 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_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_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
- fi
- # make sure the library variables are pointing to the new library
- dir=$output_objdir
- linklib=$newlib
- fi # test -n "$old_archive_from_expsyms_cmds"
-
- 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 no = "$hardcode_direct"; then
- add=$dir/$linklib
- case $host in
- *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
- *-*-sysv4*uw2*) add_dir=-L$dir ;;
- *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
- *-*-unixware7*) add_dir=-L$dir ;;
- *-*-darwin* )
- # 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
- if test "X$dlopenmodule" != "X$lib"; then
- $ECHO "*** Warning: lib $linklib is a module, not a shared library"
- 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
- fi
- elif test -n "$old_library"; then
- add=$dir/$old_library
- fi
- fi
- esac
- elif test no = "$hardcode_minus_L"; then
- case $host in
- *-*-sunos*) add_shlibpath=$dir ;;
- esac
- 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 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
- [\\/]*)
- func_append add_dir " -L$inst_prefix_dir$libdir"
- ;;
- esac
- fi
- add=-l$name
- elif test yes = "$hardcode_shlibpath_var"; then
- add_shlibpath=$dir
- add=-l$name
- else
- lib_linked=no
- fi
- ;;
- *) lib_linked=no ;;
- esac
-
- if test yes != "$lib_linked"; then
- func_fatal_configuration "unsupported hardcode properties"
- fi
-
- if test -n "$add_shlibpath"; then
- case :$compile_shlibpath: in
- *":$add_shlibpath:"*) ;;
- *) func_append compile_shlibpath "$add_shlibpath:" ;;
- esac
- fi
- 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 yes != "$hardcode_direct" &&
- test yes != "$hardcode_minus_L" &&
- test yes = "$hardcode_shlibpath_var"; then
- case :$finalize_shlibpath: in
- *":$libdir:"*) ;;
- *) func_append finalize_shlibpath "$libdir:" ;;
- esac
- fi
- fi
- fi
-
- 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 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 yes = "$hardcode_automatic"; then
- if test -n "$inst_prefix_dir" &&
- test -f "$inst_prefix_dir$libdir/$linklib"; then
- add=$inst_prefix_dir$libdir/$linklib
- else
- add=$libdir/$linklib
- fi
- else
- # We cannot seem to hardcode it, guess we'll fake it.
- 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
- [\\/]*)
- func_append add_dir " -L$inst_prefix_dir$libdir"
- ;;
- esac
- fi
- add=-l$name
- fi
-
- if test prog = "$linkmode"; then
- test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
- test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
- else
- test -n "$add_dir" && deplibs="$add_dir $deplibs"
- test -n "$add" && deplibs="$add $deplibs"
- fi
- fi
- 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 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 yes = "$build_libtool_libs"; then
- # Not a shared library
- 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 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 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 "*** not find such a program. So, this module is probably useless."
- echo "*** 'nm' from GNU binutils and a full rebuild may help."
- fi
- if test no = "$build_old_libs"; then
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- fi
- else
- deplibs="$dir/$old_library $deplibs"
- link_static=yes
- fi
- fi # link shared/static library?
-
- if test lib = "$linkmode"; then
- if test -n "$dependency_libs" &&
- { 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
- case $libdir in
- -R*) func_stripname '-R' '' "$libdir"
- temp_xrpath=$func_stripname_result
- case " $xrpath " in
- *" $temp_xrpath "*) ;;
- *) func_append xrpath " $temp_xrpath";;
- esac;;
- *) func_append temp_deplibs " $libdir";;
- esac
- done
- dependency_libs=$temp_deplibs
- fi
-
- func_append newlib_search_path " $absdir"
- # Link against this library
- test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
- # ... and its dependency_libs
- tmp_libs=
- for deplib in $dependency_libs; do
- newdependency_libs="$deplib $newdependency_libs"
- case $deplib in
- -L*) func_stripname '-L' '' "$deplib"
- func_resolve_sysroot "$func_stripname_result";;
- *) func_resolve_sysroot "$deplib" ;;
- esac
- if $opt_preserve_dup_deps; then
- case "$tmp_libs " in
- *" $func_resolve_sysroot_result "*)
- func_append specialdeplibs " $func_resolve_sysroot_result" ;;
- esac
- fi
- func_append tmp_libs " $func_resolve_sysroot_result"
- done
-
- 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 ;;
- *.la)
- func_resolve_sysroot "$deplib"
- deplib=$func_resolve_sysroot_result
- func_dirname "$deplib" "" "."
- dir=$func_dirname_result
- # We need an absolute path.
- case $dir in
- [\\/]* | [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
- fi
- ;;
- esac
- if $GREP "^installed=no" $deplib > /dev/null; then
- 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
- 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 -z "$darwin_install_name"; then
- 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"
- path=
- fi
- fi
- ;;
- *)
- path=-L$absdir/$objdir
- ;;
- esac
- else
- eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
- test -z "$libdir" && \
- func_fatal_error "'$deplib' is not a valid libtool archive"
- test "$absdir" != "$libdir" && \
- func_warning "'$deplib' seems to be moved"
-
- path=-L$absdir
- fi
- ;;
- esac
- case " $deplibs " in
- *" $path "*) ;;
- *) deplibs="$path $deplibs" ;;
- esac
- done
- fi # link_all_deplibs != no
- fi # linkmode = lib
- done # for deplib in $libs
- 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 dlpreopen = "$pass"; then
- # Link the dlpreopened libraries before other libraries
- for deplib in $save_deplibs; do
- deplibs="$deplib $deplibs"
- done
- fi
- 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
- case "$lib_search_path " in
- *" $dir "*) ;;
- *) func_append lib_search_path " $dir" ;;
- esac
- done
- newlib_search_path=
- }
-
- 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
- eval tmp_libs=\"\$$var\"
- new_libs=
- for deplib in $tmp_libs; do
- # FIXME: Pedantically, this is the right thing to do, so
- # that some nasty dependency loop isn't accidentally
- # broken:
- #new_libs="$deplib $new_libs"
- # Pragmatically, this seems to cause very few problems in
- # practice:
- case $deplib in
- -L*) new_libs="$deplib $new_libs" ;;
- -R*) ;;
- *)
- # And here is the reason: when a library appears more
- # than once as an explicit dependence of a library, or
- # is implicitly linked in more than once by the
- # compiler, it is considered special, and multiple
- # occurrences thereof are not removed. Compare this
- # with having the same library being listed as a
- # dependency of multiple other libraries: in this case,
- # we know (pedantically, we assume) the library does not
- # need to be listed more than once, so we keep only the
- # last copy. This is not always right, but it is rare
- # enough that we require users that really mean to play
- # such unportable linking tricks to link the library
- # using -Wl,-lname, so that libtool does not consider it
- # for duplicate removal.
- case " $specialdeplibs " in
- *" $deplib "*) new_libs="$deplib $new_libs" ;;
- *)
- case " $new_libs " in
- *" $deplib "*) ;;
- *) new_libs="$deplib $new_libs" ;;
- esac
- ;;
- esac
- ;;
- esac
- done
- tmp_libs=
- for deplib in $new_libs; do
- case $deplib in
- -L*)
- case " $tmp_libs " in
- *" $deplib "*) ;;
- *) func_append tmp_libs " $deplib" ;;
- esac
- ;;
- *) func_append tmp_libs " $deplib" ;;
- esac
- done
- 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
- case " $predeps $postdeps $compiler_lib_search_path " in
- *" $i "*)
- i=
- ;;
- esac
- if test -n "$i"; then
- func_append tmp_libs " $i"
- fi
- done
- dependency_libs=$tmp_libs
- done # for pass
- if test prog = "$linkmode"; then
- dlfiles=$newdlfiles
- fi
- if test prog = "$linkmode" || test lib = "$linkmode"; then
- dlprefiles=$newdlprefiles
- fi
-
- case $linkmode in
- oldlib)
- 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" ;;
- esac
-
- test -n "$rpath" && \
- func_warning "'-rpath' is ignored for archives"
-
- test -n "$xrpath" && \
- func_warning "'-R' is ignored for archives"
-
- test -n "$vinfo" && \
- func_warning "'-version-info/-version-number' is ignored for archives"
-
- test -n "$release" && \
- func_warning "'-release' is ignored for archives"
-
- test -n "$export_symbols$export_symbols_regex" && \
- func_warning "'-export-symbols' is ignored for archives"
-
- # Now set the variables for building old libraries.
- build_libtool_libs=no
- oldlibs=$output
- func_append objs "$old_deplibs"
- ;;
-
- lib)
- # Make sure we only generate libraries of the form 'libNAME.la'.
- case $outputname in
- lib*)
- func_stripname 'lib' '.la' "$outputname"
- name=$func_stripname_result
- eval shared_ext=\"$shrext_cmds\"
- eval libname=\"$libname_spec\"
- ;;
- *)
- test no = "$module" \
- && func_fatal_help "libtool library '$output' must begin with 'lib'"
-
- if test no != "$need_lib_prefix"; then
- # Add the "lib" prefix for modules if required
- func_stripname '' '.la' "$outputname"
- name=$func_stripname_result
- eval shared_ext=\"$shrext_cmds\"
- eval libname=\"$libname_spec\"
- else
- func_stripname '' '.la' "$outputname"
- libname=$func_stripname_result
- fi
- ;;
- esac
-
- if test -n "$objs"; then
- 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"
- $ECHO "*** objects $objs is not portable!"
- func_append libobjs " $objs"
- fi
- fi
-
- test no = "$dlself" \
- || func_warning "'-dlopen self' is ignored for libtool libraries"
-
- set dummy $rpath
- shift
- test 1 -lt "$#" \
- && func_warning "ignoring multiple '-rpath's for a libtool library"
-
- install_libdir=$1
-
- oldlibs=
- if test -z "$rpath"; then
- if test yes = "$build_libtool_libs"; then
- # Building a libtool convenience library.
- # 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"
- build_libtool_libs=convenience
- build_old_libs=yes
- fi
-
- test -n "$vinfo" && \
- func_warning "'-version-info/-version-number' is ignored for convenience libraries"
-
- test -n "$release" && \
- func_warning "'-release' is ignored for convenience libraries"
- else
-
- # Parse the version information argument.
- save_ifs=$IFS; IFS=:
- set dummy $vinfo 0 0 0
- shift
- IFS=$save_ifs
-
- test -n "$7" && \
- func_fatal_help "too many parameters to '-version-info'"
-
- # convert absolute version numbers to libtool ages
- # this retains compatibility with .la files and attempts
- # to make the code below a bit more comprehensible
-
- case $vinfo_number in
- yes)
- 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
- # that has an extra 1 added just for fun
- #
- case $version_type in
- # correct linux to gnu/linux during the next big refactor
- darwin|freebsd-elf|linux|osf|windows|none)
- func_arith $number_major + $number_minor
- current=$func_arith_result
- age=$number_minor
- revision=$number_revision
- ;;
- 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
- lt_irix_increment=no
- ;;
- *)
- func_fatal_configuration "$modename: unknown library version type '$version_type'"
- ;;
- esac
- ;;
- no)
- current=$1
- revision=$2
- age=$3
- ;;
- esac
-
- # Check that each of the things are valid numbers.
- 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"
- ;;
- 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"
- ;;
- 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"
- ;;
- 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"
- fi
-
- # Calculate the version variables.
- major=
- versuffix=
- verstring=
- case $version_type in
- none) ;;
-
- darwin)
- # Like Linux, but with the current version available in
- # verstring for coding it into the library header
- func_arith $current - $age
- major=.$func_arith_result
- 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"
- 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
- ;;
-
- freebsd-elf)
- func_arith $current - $age
- major=.$func_arith_result
- versuffix=$major.$age.$revision
- ;;
-
- irix | nonstopux)
- if test no = "$lt_irix_increment"; then
- func_arith $current - $age
- else
- func_arith $current - $age + 1
- fi
- major=$func_arith_result
-
- case $version_type in
- nonstopux) verstring_prefix=nonstopux ;;
- *) verstring_prefix=sgi ;;
- esac
- verstring=$verstring_prefix$major.$revision
-
- # Add in all the interfaces that we are compatible with.
- loop=$revision
- 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
- done
-
- # Before this point, $major must not contain '.'.
- major=.$major
- 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
- ;;
-
- osf)
- func_arith $current - $age
- major=.$func_arith_result
- versuffix=.$current.$age.$revision
- verstring=$current.$age.$revision
-
- # Add in all the interfaces that we are compatible with.
- loop=$age
- 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
- done
-
- # Make executables depend on our current version.
- func_append verstring ":$current.0"
- ;;
-
- qnx)
- major=.$current
- versuffix=.$current
- ;;
-
- sco)
- major=.$current
- versuffix=.$current
- ;;
-
- sunos)
- major=.$current
- versuffix=.$current.$revision
- ;;
-
- windows)
- # Use '-' rather than '.', since we only want one
- # extension on DOS 8.3 file systems.
- func_arith $current - $age
- major=$func_arith_result
- versuffix=-$major
- ;;
-
- *)
- func_fatal_configuration "unknown library version type '$version_type'"
- ;;
- esac
-
- # Clear the version info if we defaulted, and they specified a release.
- if test -z "$vinfo" && test -n "$release"; then
- major=
- case $version_type in
- darwin)
- # we can't check for "0.0" in archive_cmds due to quoting
- # problems, so we reset it completely
- verstring=
- ;;
- *)
- verstring=0.0
- ;;
- esac
- if test no = "$need_version"; then
- versuffix=
- else
- versuffix=.0.0
- fi
- fi
-
- # Remove version info from name if versioning should be avoided
- if test yes,no = "$avoid_version,$need_version"; then
- major=
- versuffix=
- verstring=
- fi
-
- # Check to see if the archive will have undefined symbols.
- 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
- fi
-
- fi
-
- func_generate_dlsyms "$libname" "$libname" :
- func_append libobjs " $symfileobj"
- test " " = "$libobjs" && libobjs=
-
- 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=
- tempremovelist=`$ECHO "$output_objdir/*"`
- for p in $tempremovelist; do
- case $p in
- *.$objext | *.gcno)
- ;;
- $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
- fi
- fi
- func_append removelist " $p"
- ;;
- *) ;;
- esac
- done
- test -n "$removelist" && \
- func_show_eval "${RM}r \$removelist"
- fi
-
- # Now set the variables for building old libraries.
- 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`
- fi
-
- # Eliminate all temporary directories.
- #for path in $notinst_path; do
- # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
- # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
- # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
- #done
-
- if test -n "$xrpath"; then
- # If the user specified any rpath flags, then add them.
- temp_xrpath=
- for libdir in $xrpath; do
- func_replace_sysroot "$libdir"
- func_append temp_xrpath " -R$func_replace_sysroot_result"
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) func_append finalize_rpath " $libdir" ;;
- esac
- done
- 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
- dlfiles=
- for lib in $old_dlfiles; do
- case " $dlprefiles $dlfiles " in
- *" $lib "*) ;;
- *) func_append dlfiles " $lib" ;;
- esac
- done
-
- # Make sure dlprefiles contains only unique files
- old_dlprefiles=$dlprefiles
- dlprefiles=
- for lib in $old_dlprefiles; do
- case "$dlprefiles " in
- *" $lib "*) ;;
- *) func_append dlprefiles " $lib" ;;
- esac
- done
-
- if test yes = "$build_libtool_libs"; then
- if test -n "$rpath"; then
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
- # these systems don't actually have a c library (as such)!
- ;;
- *-*-rhapsody* | *-*-darwin1.[012])
- # Rhapsody C library is in the System framework
- func_append deplibs " System.ltframework"
- ;;
- *-*-netbsd*)
- # Don't link with libc until the a.out ld.so is fixed.
- ;;
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
- # Do not include libc due to us having libc/libc_r.
- ;;
- *-*-sco3.2v5* | *-*-sco5v6*)
- # Causes problems with __ctype
- ;;
- *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
- # Compiler inserts libc in the correct place for threads to work
- ;;
- *)
- # Add libc to deplibs on all other systems if necessary.
- if test yes = "$build_libtool_need_lc"; then
- func_append deplibs " -lc"
- fi
- ;;
- esac
- fi
-
- # Transform deplibs into only deplibs that can be linked in shared.
- name_save=$name
- libname_save=$libname
- release_save=$release
- versuffix_save=$versuffix
- major_save=$major
- # 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=
- newdeplibs=
- droppeddeps=no
- case $deplibs_check_method in
- pass_all)
- # Don't check for shared/static. Everything works.
- # This might be a little naive. We might want to check
- # whether the library exists or not. But this is on
- # osf3 & osf4 and I'm not really sure... Just
- # implementing what was already the behavior.
- newdeplibs=$deplibs
- ;;
- test_compile)
- # This code stresses the "libraries are programs" paradigm to its
- # limits. Maybe even breaks it. We compile a program, linking it
- # against the deplibs as a proxy for the library. Then we can check
- # whether they linked in statically or dynamically with ldd.
- $opt_dry_run || $RM conftest.c
- cat > conftest.c <<EOF
- int main() { return 0; }
-EOF
- $opt_dry_run || $RM conftest
- if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
- ldd_output=`ldd conftest`
- for i in $deplibs; do
- case $i in
- -l*)
- func_stripname -l '' "$i"
- name=$func_stripname_result
- if test yes = "$allow_libtool_libs_with_static_runtimes"; then
- case " $predeps $postdeps " in
- *" $i "*)
- func_append newdeplibs " $i"
- i=
- ;;
- esac
- fi
- 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
- func_append newdeplibs " $i"
- else
- droppeddeps=yes
- echo
- $ECHO "*** Warning: dynamic linker does not accept needed library $i."
- 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 I believe you do not have"
- echo "*** because a test_compile did reveal that the linker did not use it for"
- echo "*** its dynamic dependency list that programs get resolved with at runtime."
- fi
- fi
- ;;
- *)
- func_append newdeplibs " $i"
- ;;
- esac
- done
- else
- # Error occurred in the first compile. Let's try to salvage
- # the situation: Compile a separate program for each library.
- for i in $deplibs; do
- case $i in
- -l*)
- func_stripname -l '' "$i"
- name=$func_stripname_result
- $opt_dry_run || $RM conftest
- if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
- ldd_output=`ldd conftest`
- if test yes = "$allow_libtool_libs_with_static_runtimes"; then
- case " $predeps $postdeps " in
- *" $i "*)
- func_append newdeplibs " $i"
- i=
- ;;
- esac
- fi
- 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
- func_append newdeplibs " $i"
- else
- droppeddeps=yes
- echo
- $ECHO "*** Warning: dynamic linker does not accept needed library $i."
- 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"
- echo "*** because a test_compile did reveal that the linker did not use this one"
- echo "*** as a dynamic dependency that programs can get resolved with at runtime."
- fi
- fi
- else
- droppeddeps=yes
- echo
- $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
- echo "*** make it link in! You will probably need to install it or some"
- echo "*** library that it depends on before this library will be fully"
- echo "*** functional. Installing it before continuing would be even better."
- fi
- ;;
- *)
- func_append newdeplibs " $i"
- ;;
- esac
- done
- fi
- ;;
- file_magic*)
- set dummy $deplibs_check_method; shift
- file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
- for a_deplib in $deplibs; do
- case $a_deplib in
- -l*)
- func_stripname -l '' "$a_deplib"
- name=$func_stripname_result
- if test yes = "$allow_libtool_libs_with_static_runtimes"; then
- case " $predeps $postdeps " in
- *" $a_deplib "*)
- func_append newdeplibs " $a_deplib"
- a_deplib=
- ;;
- esac
- fi
- 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 yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
- for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
- if test yes = "$want_nocaseglob"; then
- shopt -s nocaseglob
- potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
- $nocaseglob
- else
- potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
- fi
- for potent_lib in $potential_libs; do
- # Follow soft links.
- if ls -lLd "$potent_lib" 2>/dev/null |
- $GREP " -> " >/dev/null; then
- continue
- fi
- # The statement above tries to avoid entering an
- # endless loop below, in case of cyclic links.
- # We might still enter an endless loop, since a link
- # loop can be closed while we follow links,
- # but so what?
- potlib=$potent_lib
- while test -h "$potlib" 2>/dev/null; do
- potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
- case $potliblink in
- [\\/]* | [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=
- break 2
- fi
- done
- done
- fi
- if test -n "$a_deplib"; then
- droppeddeps=yes
- echo
- $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
- 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"
- echo "*** because I did check the linker path looking for a file starting"
- 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"
- $ECHO "*** using a file magic. Last file checked: $potlib"
- fi
- fi
- ;;
- *)
- # Add a -L argument.
- func_append newdeplibs " $a_deplib"
- ;;
- esac
- done # Gone through all deplibs.
- ;;
- match_pattern*)
- set dummy $deplibs_check_method; shift
- match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
- for a_deplib in $deplibs; do
- case $a_deplib in
- -l*)
- func_stripname -l '' "$a_deplib"
- name=$func_stripname_result
- if test yes = "$allow_libtool_libs_with_static_runtimes"; then
- case " $predeps $postdeps " in
- *" $a_deplib "*)
- func_append newdeplibs " $a_deplib"
- a_deplib=
- ;;
- esac
- fi
- 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
- if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
- $EGREP "$match_pattern_regex" > /dev/null; then
- func_append newdeplibs " $a_deplib"
- a_deplib=
- break 2
- fi
- done
- done
- fi
- if test -n "$a_deplib"; then
- droppeddeps=yes
- echo
- $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
- 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"
- echo "*** because I did check the linker path looking for a file starting"
- 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"
- $ECHO "*** using a regex pattern. Last file checked: $potlib"
- fi
- fi
- ;;
- *)
- # Add a -L argument.
- func_append newdeplibs " $a_deplib"
- ;;
- esac
- done # Gone through all deplibs.
- ;;
- none | unknown | *)
- newdeplibs=
- tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
- 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||"`
- done
- fi
- case $tmp_deplibs in
- *[!\ \ ]*)
- echo
- 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."
- fi
- echo "*** All declared inter-library dependencies are being dropped."
- droppeddeps=yes
- ;;
- esac
- ;;
- esac
- versuffix=$versuffix_save
- major=$major_save
- release=$release_save
- libname=$libname_save
- name=$name_save
-
- case $host in
- *-*-rhapsody* | *-*-darwin1.[012])
- # On Rhapsody replace the C library with the System framework
- newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
- ;;
- esac
-
- 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"
- echo "*** a static module, that should work as long as the dlopening"
- echo "*** application is linked with the -dlopen flag."
- 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 "*** not find such a program. So, this module is probably useless."
- echo "*** 'nm' from GNU binutils and a full rebuild may help."
- fi
- if test no = "$build_old_libs"; then
- oldlibs=$output_objdir/$libname.$libext
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- else
- echo "*** The inter-library dependencies that have been dropped here will be"
- echo "*** automatically added whenever a program is linked with this library"
- echo "*** or is declared to -dlopen it."
-
- 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 no = "$build_old_libs"; then
- oldlibs=$output_objdir/$libname.$libext
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- fi
- fi
- fi
- # Done checking deplibs!
- deplibs=$newdeplibs
- fi
- # Time to change all our "foo.ltframework" stuff back to "-framework foo"
- case $host in
- *-*-darwin*)
- newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
- new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
- deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
- ;;
- esac
-
- # move library search paths that coincide with paths to not yet
- # installed libraries to the beginning of the library search list
- new_libs=
- for path in $notinst_path; do
- case " $new_libs " in
- *" -L$path/$objdir "*) ;;
- *)
- case " $deplibs " in
- *" -L$path/$objdir "*)
- func_append new_libs " -L$path/$objdir" ;;
- esac
- ;;
- esac
- done
- for deplib in $deplibs; do
- case $deplib in
- -L*)
- case " $new_libs " in
- *" $deplib "*) ;;
- *) func_append new_libs " $deplib" ;;
- esac
- ;;
- *) func_append new_libs " $deplib" ;;
- esac
- done
- deplibs=$new_libs
-
- # All the library-specific variables (install_libdir is set above).
- library_names=
- old_library=
- dlname=
-
- # Test again, we may have decided not to build it any more
- 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 yes = "$hardcode_into_libs"; then
- # Hardcode the library paths
- hardcode_libdirs=
- dep_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
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- func_append dep_rpath " $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$perm_rpath " in
- *" $libdir "*) ;;
- *) func_append perm_rpath " $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir=$hardcode_libdirs
- eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
- fi
- if test -n "$runpath_var" && test -n "$perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $perm_rpath; do
- func_append rpath "$dir:"
- done
- eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
- fi
- test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
- fi
-
- 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
-
- # Get the real and link names of the library.
- eval shared_ext=\"$shrext_cmds\"
- eval library_names=\"$library_names_spec\"
- set dummy $library_names
- shift
- realname=$1
- shift
-
- if test -n "$soname_spec"; then
- eval soname=\"$soname_spec\"
- else
- soname=$realname
- fi
- if test -z "$dlname"; then
- dlname=$soname
- fi
-
- lib=$output_objdir/$realname
- linknames=
- for link
- do
- func_append linknames " $link"
- done
-
- # Use standard objects if they are pic
- test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
- test "X$libobjs" = "X " && libobjs=
-
- 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
- func_append delfiles " $export_symbols"
- fi
-
- orig_export_symbols=
- case $host_os in
- cygwin* | mingw* | cegcc*)
- if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
- # exporting using user supplied symfile
- 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
- export_symbols=
- always_export_symbols=yes
- }
- fi
- ;;
- esac
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- 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='~'
- for cmd1 in $cmds; do
- 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
- *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
- try_normal_branch=yes
- eval cmd=\"$cmd1\"
- func_len " $cmd"
- len=$func_len_result
- ;;
- *)
- try_normal_branch=no
- ;;
- esac
- if test yes = "$try_normal_branch" \
- && { test "$len" -lt "$max_cmd_len" \
- || test "$max_cmd_len" -le -1; }
- then
- func_show_eval "$cmd" 'exit $?'
- skipped_export=false
- elif test -n "$nm_file_list_spec"; then
- func_basename "$output"
- output_la=$func_basename_result
- save_libobjs=$libobjs
- save_output=$output
- 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"
- func_verbose "creating $NM input file list: $output"
- for obj in $save_libobjs; do
- func_to_tool_file "$obj"
- $ECHO "$func_to_tool_file_result"
- done > "$output"
- eval cmd=\"$cmd1\"
- func_show_eval "$cmd" 'exit $?'
- output=$save_output
- libobjs=$save_libobjs
- skipped_export=false
- else
- # The command line is too long to execute in one step.
- func_verbose "using reloadable object file for export list..."
- skipped_export=:
- # Break out early, otherwise skipped_export may be
- # set to false by a later but shorter cmd.
- break
- fi
- done
- 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
- fi
- 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
- $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
- fi
-
- 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"
- # FIXME: $output_objdir/$libname.filter potentially contains lots of
- # '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.
- $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
- func_append delfiles " $export_symbols $output_objdir/$libname.filter"
- export_symbols=$output_objdir/$libname.def
- $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
- fi
-
- tmp_deplibs=
- for test_deplib in $deplibs; do
- case " $convenience " in
- *" $test_deplib "*) ;;
- *)
- func_append tmp_deplibs " $test_deplib"
- ;;
- esac
- done
- deplibs=$tmp_deplibs
-
- if test -n "$convenience"; then
- if test -n "$whole_archive_flag_spec" &&
- 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.
- whole_archive_flag_spec=
- fi
- if test -n "$whole_archive_flag_spec"; then
- save_libobjs=$libobjs
- eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
- test "X$libobjs" = "X " && libobjs=
- else
- gentop=$output_objdir/${outputname}x
- func_append generated " $gentop"
-
- func_extract_archives $gentop $convenience
- func_append libobjs " $func_extract_archives_result"
- test "X$libobjs" = "X " && libobjs=
- fi
- fi
-
- 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 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 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
- else
- eval test_cmds=\"$module_cmds\"
- cmds=$module_cmds
- fi
- else
- if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
- eval test_cmds=\"$archive_expsym_cmds\"
- cmds=$archive_expsym_cmds
- else
- eval test_cmds=\"$archive_cmds\"
- cmds=$archive_cmds
- fi
- fi
-
- 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
- :
- else
- # The command line is too long to link in one step, link piecewise
- # or, if using GNU ld and skipped_export is not :, use a linker
- # script.
-
- # Save the value of $output and $libobjs because we want to
- # use them later. If we have whole_archive_flag_spec, we
- # want to use save_libobjs as it was before
- # whole_archive_flag_spec was expanded, because we can't
- # assume the linker understands whole_archive_flag_spec.
- # This may have to be revisited, in case too many
- # convenience libraries get linked in and end up exceeding
- # the spec.
- if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
- save_libobjs=$libobjs
- fi
- save_output=$output
- func_basename "$output"
- output_la=$func_basename_result
-
- # Clear the reloadable object creation command queue and
- # initialize k to one.
- test_cmds=
- concat_cmds=
- objlist=
- last_robj=
- k=1
-
- 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
- do
- func_to_tool_file "$obj"
- $ECHO "$func_to_tool_file_result" >> $output
- done
- echo ')' >> $output
- func_append delfiles " $output"
- func_to_tool_file "$output"
- output=$func_to_tool_file_result
- 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 yes = "$compiler_needs_object"; then
- firstobj="$1 "
- shift
- fi
- for obj
- do
- func_to_tool_file "$obj"
- $ECHO "$func_to_tool_file_result" >> $output
- done
- func_append delfiles " $output"
- func_to_tool_file "$output"
- output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
- else
- if test -n "$save_libobjs"; then
- func_verbose "creating reloadable object files..."
- output=$output_objdir/$output_la-$k.$objext
- eval test_cmds=\"$reload_cmds\"
- func_len " $test_cmds"
- len0=$func_len_result
- len=$len0
-
- # Loop over the list of objects to be linked.
- for obj in $save_libobjs
- do
- func_len " $obj"
- func_arith $len + $func_len_result
- len=$func_arith_result
- 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 1 -eq "$k"; then
- # The first file doesn't have a previous command to add.
- reload_objs=$objlist
- eval concat_cmds=\"$reload_cmds\"
- else
- # All subsequent reloadable object files will link in
- # the last one created.
- reload_objs="$objlist $last_robj"
- eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
- fi
- last_robj=$output_objdir/$output_la-$k.$objext
- func_arith $k + 1
- k=$func_arith_result
- output=$output_objdir/$output_la-$k.$objext
- objlist=" $obj"
- func_len " $last_robj"
- func_arith $len0 + $func_len_result
- len=$func_arith_result
- fi
- done
- # Handle the remaining objects by creating one last
- # reloadable object file. All subsequent reloadable object
- # 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\"
- if test -n "$last_robj"; then
- eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
- fi
- func_append delfiles " $output"
-
- else
- output=
- fi
-
- ${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.
- test -z "$concat_cmds" || concat_cmds=$concat_cmds~
- eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
- if test -n "$last_robj"; then
- eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
- 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='~'
- for cmd in $concat_cmds; do
- IFS=$save_ifs
- $opt_quiet || {
- func_quote_for_expand "$cmd"
- eval "func_echo $func_quote_for_expand_result"
- }
- $opt_dry_run || eval "$cmd" || {
- lt_exit=$?
-
- # Restore the uninstalled library and exit
- if test relink = "$opt_mode"; then
- ( cd "$output_objdir" && \
- $RM "${realname}T" && \
- $MV "${realname}U" "$realname" )
- fi
-
- exit $lt_exit
- }
- done
- 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"'
- func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
- fi
- fi
-
- ${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
- $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"
- # FIXME: $output_objdir/$libname.filter potentially contains lots of
- # '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.
- $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
- func_append delfiles " $export_symbols $output_objdir/$libname.filter"
- export_symbols=$output_objdir/$libname.def
- $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
- fi
- }
-
- libobjs=$output
- # Restore the value of output.
- output=$save_output
-
- if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
- eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
- test "X$libobjs" = "X " && libobjs=
- fi
- # Expand the library linking commands again to reset the
- # value of $libobjs for piecewise linking.
-
- # Do each of the archive commands.
- 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
- cmds=$module_cmds
- fi
- else
- if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
- cmds=$archive_expsym_cmds
- else
- cmds=$archive_cmds
- fi
- fi
- fi
-
- if test -n "$delfiles"; then
- # Append the command to remove temporary files to $cmds.
- eval cmds=\"\$cmds~\$RM $delfiles\"
- fi
-
- # Add any objects from preloaded convenience libraries
- if test -n "$dlprefiles"; then
- gentop=$output_objdir/${outputname}x
- func_append generated " $gentop"
-
- func_extract_archives $gentop $dlprefiles
- func_append libobjs " $func_extract_archives_result"
- test "X$libobjs" = "X " && libobjs=
- fi
-
- save_ifs=$IFS; IFS='~'
- for cmd in $cmds; do
- IFS=$sp$nl
- eval cmd=\"$cmd\"
- IFS=$save_ifs
- $opt_quiet || {
- func_quote_for_expand "$cmd"
- eval "func_echo $func_quote_for_expand_result"
- }
- $opt_dry_run || eval "$cmd" || {
- lt_exit=$?
-
- # Restore the uninstalled library and exit
- if test relink = "$opt_mode"; then
- ( cd "$output_objdir" && \
- $RM "${realname}T" && \
- $MV "${realname}U" "$realname" )
- fi
-
- exit $lt_exit
- }
- done
- IFS=$save_ifs
-
- # Restore the uninstalled library and exit
- 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
- if test -z "$whole_archive_flag_spec"; then
- func_show_eval '${RM}r "$gentop"'
- fi
- fi
-
- exit $EXIT_SUCCESS
- fi
-
- # Create links to the real library.
- for linkname in $linknames; do
- if test "$realname" != "$linkname"; then
- func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
- fi
- done
-
- # If -module or -export-dynamic was specified, set the dlname.
- if test yes = "$module" || test yes = "$export_dynamic"; then
- # On all known operating systems, these are identical.
- dlname=$soname
- fi
- fi
- ;;
-
- obj)
- 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" ;;
- esac
-
- test -n "$rpath" && \
- func_warning "'-rpath' is ignored for objects"
-
- test -n "$xrpath" && \
- func_warning "'-R' is ignored for objects"
-
- test -n "$vinfo" && \
- func_warning "'-version-info' is ignored for objects"
-
- test -n "$release" && \
- 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"
-
- libobj=$output
- func_lo2o "$libobj"
- obj=$func_lo2o_result
- ;;
- *)
- libobj=
- obj=$output
- ;;
- esac
-
- # Delete the old objects.
- $opt_dry_run || $RM $obj $libobj
-
- # Objects from convenience libraries. This assumes
- # single-version convenience libraries. Whenever we create
- # different ones for PIC/non-PIC, this we'll have to duplicate
- # the extraction.
- reload_conv_objs=
- gentop=
- # 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\"
- 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
- func_append generated " $gentop"
-
- func_extract_archives $gentop $convenience
- reload_conv_objs="$reload_objs $func_extract_archives_result"
- fi
- fi
-
- # If we're not building shared, we need to use non_pic_objs
- 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
-
- output=$obj
- func_execute_cmds "$reload_cmds" 'exit $?'
-
- # Exit if we aren't doing a library object file.
- if test -z "$libobj"; then
- if test -n "$gentop"; then
- func_show_eval '${RM}r "$gentop"'
- fi
-
- exit $EXIT_SUCCESS
- fi
-
- test yes = "$build_libtool_libs" || {
- if test -n "$gentop"; then
- func_show_eval '${RM}r "$gentop"'
- fi
-
- # Create an invalid libtool object if no PIC, so that we don't
- # accidentally link it into a program.
- # $show "echo timestamp > $libobj"
- # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
- exit $EXIT_SUCCESS
- }
-
- 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
- func_execute_cmds "$reload_cmds" 'exit $?'
- fi
-
- if test -n "$gentop"; then
- func_show_eval '${RM}r "$gentop"'
- fi
-
- exit $EXIT_SUCCESS
- ;;
-
- prog)
- case $host in
- *cygwin*) func_stripname '' '.exe' "$output"
- output=$func_stripname_result.exe;;
- esac
- test -n "$vinfo" && \
- func_warning "'-version-info' is ignored for programs"
-
- test -n "$release" && \
- func_warning "'-release' is ignored for programs"
-
- $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])
- # On Rhapsody replace the C library is the System framework
- compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
- finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
- ;;
- esac
-
- case $host in
- *-*-darwin*)
- # Don't allow lazy linking, it breaks C++ global constructors
- # But is supposedly fixed on 10.4 or later (yay!).
- 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"
- ;;
- esac
- fi
- # Time to change all our "foo.ltframework" stuff back to "-framework foo"
- compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
- finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
- ;;
- esac
-
-
- # move library search paths that coincide with paths to not yet
- # installed libraries to the beginning of the library search list
- new_libs=
- for path in $notinst_path; do
- case " $new_libs " in
- *" -L$path/$objdir "*) ;;
- *)
- case " $compile_deplibs " in
- *" -L$path/$objdir "*)
- func_append new_libs " -L$path/$objdir" ;;
- esac
- ;;
- esac
- done
- for deplib in $compile_deplibs; do
- case $deplib in
- -L*)
- case " $new_libs " in
- *" $deplib "*) ;;
- *) func_append new_libs " $deplib" ;;
- esac
- ;;
- *) func_append new_libs " $deplib" ;;
- esac
- done
- compile_deplibs=$new_libs
-
-
- func_append compile_command " $compile_deplibs"
- func_append finalize_command " $finalize_deplibs"
-
- if test -n "$rpath$xrpath"; then
- # If the user specified any rpath flags, then add them.
- for libdir in $rpath $xrpath; do
- # This is the magic to use -rpath.
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) func_append finalize_rpath " $libdir" ;;
- esac
- done
- fi
-
- # Now hardcode the library paths
- rpath=
- hardcode_libdirs=
- for libdir in $compile_rpath $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs=$libdir
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- func_append rpath " $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$perm_rpath " in
- *" $libdir "*) ;;
- *) func_append perm_rpath " $libdir" ;;
- esac
- fi
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
- testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
- case :$dllsearchpath: in
- *":$libdir:"*) ;;
- ::) dllsearchpath=$libdir;;
- *) func_append dllsearchpath ":$libdir";;
- esac
- case :$dllsearchpath: in
- *":$testbindir:"*) ;;
- ::) dllsearchpath=$testbindir;;
- *) func_append dllsearchpath ":$testbindir";;
- esac
- ;;
- esac
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir=$hardcode_libdirs
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- compile_rpath=$rpath
-
- rpath=
- hardcode_libdirs=
- for libdir in $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs=$libdir
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- func_append rpath " $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$finalize_perm_rpath " in
- *" $libdir "*) ;;
- *) func_append finalize_perm_rpath " $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir=$hardcode_libdirs
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- finalize_rpath=$rpath
-
- 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@" false
-
- # template prelinking step
- if test -n "$prelink_cmds"; then
- func_execute_cmds "$prelink_cmds" 'exit $?'
- fi
-
- wrappers_required=:
- case $host in
- *cegcc* | *mingw32ce*)
- # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
- wrappers_required=false
- ;;
- *cygwin* | *mingw* )
- test yes = "$build_libtool_libs" || wrappers_required=false
- ;;
- *)
- if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
- wrappers_required=false
- fi
- ;;
- esac
- $wrappers_required || {
- # Replace the output file specification.
- compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
- link_command=$compile_command$compile_rpath
-
- # We have no uninstalled library dependencies, so finalize right now.
- exit_status=0
- func_show_eval "$link_command" 'exit_status=$?'
-
- if test -n "$postlink_cmds"; then
- func_to_tool_file "$output"
- postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
- func_execute_cmds "$postlink_cmds" 'exit $?'
- fi
-
- # Delete the generated files.
- if test -f "$output_objdir/${outputname}S.$objext"; then
- func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
- fi
-
- exit $exit_status
- }
-
- if test -n "$compile_shlibpath$finalize_shlibpath"; then
- compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
- fi
- if test -n "$finalize_shlibpath"; then
- finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
- fi
-
- compile_var=
- finalize_var=
- if test -n "$runpath_var"; then
- if test -n "$perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $perm_rpath; do
- func_append rpath "$dir:"
- done
- compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- if test -n "$finalize_perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $finalize_perm_rpath; do
- func_append rpath "$dir:"
- done
- finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- fi
-
- if test yes = "$no_install"; then
- # We don't need to create a wrapper script.
- 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.
- $opt_dry_run || $RM $output
- # Link the executable and exit
- func_show_eval "$link_command" 'exit $?'
-
- if test -n "$postlink_cmds"; then
- func_to_tool_file "$output"
- postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
- func_execute_cmds "$postlink_cmds" 'exit $?'
- fi
-
- exit $EXIT_SUCCESS
- fi
-
- 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"
- ;;
- *,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'`
-
- # Delete the old output files.
- $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
-
- func_show_eval "$link_command" 'exit $?'
-
- if test -n "$postlink_cmds"; then
- func_to_tool_file "$output_objdir/$outputname"
- postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
- func_execute_cmds "$postlink_cmds" 'exit $?'
- fi
-
- # Now create the wrapper script.
- func_verbose "creating $output"
-
- # Quote the relink command for shipping.
- if test -n "$relink_command"; then
- # Preserve any variables that may affect compiler behavior
- for var in $variables_saved_for_relink; do
- if eval test -z \"\${$var+set}\"; then
- relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
- elif eval var_value=\$$var; test -z "$var_value"; then
- relink_command="$var=; export $var; $relink_command"
- else
- func_quote_for_eval "$var_value"
- 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"`
- fi
-
- # Only actually do things if not in dry run mode.
- $opt_dry_run || {
- # win32 will think the script is a binary if it has
- # a .exe suffix, so we strip it off here.
- case $output in
- *.exe) func_stripname '' '.exe' "$output"
- output=$func_stripname_result ;;
- esac
- # test for cygwin because mv fails w/o .exe extensions
- case $host in
- *cygwin*)
- exeext=.exe
- func_stripname '' '.exe' "$outputname"
- outputname=$func_stripname_result ;;
- *) exeext= ;;
- esac
- case $host in
- *cygwin* | *mingw* )
- 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
- $RM $cwrappersource $cwrapper
- trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
-
- func_emit_cwrapperexe_src > $cwrappersource
-
- # The wrapper executable is built using the $host compiler,
- # because it contains $host paths and files. If cross-
- # compiling, it, like the target executable, must be
- # executed on the $host or under an emulation environment.
- $opt_dry_run || {
- $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
- $STRIP $cwrapper
- }
-
- # Now, create the wrapper script for func_source use:
- func_ltwrapper_scriptname $cwrapper
- $RM $func_ltwrapper_scriptname_result
- 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
- $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
- else
- func_emit_wrapper no > $func_ltwrapper_scriptname_result
- fi
- }
- ;;
- * )
- $RM $output
- trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
-
- func_emit_wrapper no > $output
- chmod +x $output
- ;;
- esac
- }
- exit $EXIT_SUCCESS
- ;;
- esac
-
- # See if we need to build an old-fashioned archive.
- for oldlib in $oldlibs; do
-
- case $build_libtool_libs in
- convenience)
- oldobjs="$libobjs_save $symfileobj"
- addlibs=$convenience
- build_libtool_libs=no
- ;;
- module)
- oldobjs=$libobjs_save
- addlibs=$old_convenience
- build_libtool_libs=no
- ;;
- *)
- oldobjs="$old_deplibs $non_pic_objects"
- $preload && test -f "$symfileobj" \
- && func_append oldobjs " $symfileobj"
- addlibs=$old_convenience
- ;;
- esac
-
- if test -n "$addlibs"; then
- gentop=$output_objdir/${outputname}x
- func_append generated " $gentop"
-
- func_extract_archives $gentop $addlibs
- func_append oldobjs " $func_extract_archives_result"
- fi
-
- # Do each command in the archive commands.
- 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
- func_append generated " $gentop"
-
- func_extract_archives $gentop $dlprefiles
- func_append oldobjs " $func_extract_archives_result"
- fi
-
- # POSIX demands no paths to be encoded in archives. We have
- # to avoid creating archives with duplicate basenames if we
- # might have to extract them afterwards, e.g., when creating a
- # static archive out of a convenience library, or when linking
- # the entirety of a libtool archive into another (currently
- # not supported by libtool).
- if (for obj in $oldobjs
- do
- func_basename "$obj"
- $ECHO "$func_basename_result"
- done | sort | sort -uc >/dev/null 2>&1); then
- :
- else
- echo "copying selected object files to avoid basename conflicts..."
- gentop=$output_objdir/${outputname}x
- func_append generated " $gentop"
- func_mkdir_p "$gentop"
- save_oldobjs=$oldobjs
- oldobjs=
- counter=1
- for obj in $save_oldobjs
- do
- func_basename "$obj"
- objbase=$func_basename_result
- case " $oldobjs " in
- " ") oldobjs=$obj ;;
- *[\ /]"$objbase "*)
- while :; do
- # Make sure we don't pick an alternate name that also
- # overlaps.
- newobj=lt$counter-$objbase
- func_arith $counter + 1
- counter=$func_arith_result
- case " $oldobjs " in
- *[\ /]"$newobj "*) ;;
- *) if test ! -f "$gentop/$newobj"; then break; fi ;;
- esac
- done
- func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
- func_append oldobjs " $gentop/$newobj"
- ;;
- *) func_append oldobjs " $obj" ;;
- esac
- done
- fi
- func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
- tool_oldlib=$func_to_tool_file_result
- eval cmds=\"$old_archive_cmds\"
-
- func_len " $cmds"
- len=$func_len_result
- if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
- cmds=$old_archive_cmds
- elif test -n "$archiver_list_spec"; then
- func_verbose "using command file archive linking..."
- for obj in $oldobjs
- do
- func_to_tool_file "$obj"
- $ECHO "$func_to_tool_file_result"
- done > $output_objdir/$libname.libcmd
- func_to_tool_file "$output_objdir/$libname.libcmd"
- oldobjs=" $archiver_list_spec$func_to_tool_file_result"
- cmds=$old_archive_cmds
- else
- # the command line is too long to link in one step, link in parts
- func_verbose "using piecewise archive linking..."
- save_RANLIB=$RANLIB
- RANLIB=:
- objlist=
- concat_cmds=
- save_oldobjs=$oldobjs
- oldobjs=
- # Is there a better way of finding the last object in the list?
- for obj in $save_oldobjs
- do
- last_oldobj=$obj
- done
- eval test_cmds=\"$old_archive_cmds\"
- func_len " $test_cmds"
- len0=$func_len_result
- len=$len0
- for obj in $save_oldobjs
- do
- func_len " $obj"
- func_arith $len + $func_len_result
- len=$func_arith_result
- func_append objlist " $obj"
- if test "$len" -lt "$max_cmd_len"; then
- :
- else
- # the above command should be used before it gets too long
- oldobjs=$objlist
- 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\"
- objlist=
- len=$len0
- fi
- done
- RANLIB=$save_RANLIB
- oldobjs=$objlist
- if test -z "$oldobjs"; then
- eval cmds=\"\$concat_cmds\"
- else
- eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
- fi
- fi
- fi
- func_execute_cmds "$cmds" 'exit $?'
- done
-
- test -n "$generated" && \
- func_show_eval "${RM}r$generated"
-
- # Now create the libtool archive.
- case $output in
- *.la)
- old_library=
- test yes = "$build_old_libs" && old_library=$libname.$libext
- func_verbose "creating $output"
-
- # Preserve any variables that may affect compiler behavior
- for var in $variables_saved_for_relink; do
- if eval test -z \"\${$var+set}\"; then
- relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
- elif eval var_value=\$$var; test -z "$var_value"; then
- relink_command="$var=; export $var; $relink_command"
- else
- func_quote_for_eval "$var_value"
- relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
- 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 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 yes = "$installed"; then
- if test -z "$install_libdir"; then
- break
- fi
- 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
- func_resolve_sysroot "$deplib"
- 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_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
- ;;
- -L*)
- func_stripname -L '' "$deplib"
- func_replace_sysroot "$func_stripname_result"
- func_append newdependency_libs " -L$func_replace_sysroot_result"
- ;;
- -R*)
- func_stripname -R '' "$deplib"
- func_replace_sysroot "$func_stripname_result"
- func_append newdependency_libs " -R$func_replace_sysroot_result"
- ;;
- *) func_append newdependency_libs " $deplib" ;;
- esac
- done
- 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`
- test -z "$libdir" && \
- 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
- newdlprefiles=
- for lib in $dlprefiles; do
- case $lib in
- *.la)
- # Only pass preopened files to the pseudo-archive (for
- # eventual linking with the app. that links it) if we
- # 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`
- test -z "$libdir" && \
- func_fatal_error "'$lib' is not a valid libtool archive"
- func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
- ;;
- esac
- done
- dlprefiles=$newdlprefiles
- else
- newdlfiles=
- for lib in $dlfiles; do
- case $lib in
- [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
- *) abs=`pwd`"/$lib" ;;
- esac
- func_append newdlfiles " $abs"
- done
- dlfiles=$newdlfiles
- newdlprefiles=
- for lib in $dlprefiles; do
- case $lib in
- [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
- *) abs=`pwd`"/$lib" ;;
- esac
- func_append newdlprefiles " $abs"
- done
- dlprefiles=$newdlprefiles
- fi
- $RM $output
- # place dlname in correct position for cygwin
- # In fact, it would be nice if we could use this code for all target
- # systems that can't hard-code library paths into their executables
- # and that have no shared library path variable independent of PATH,
- # but it turns out we can't easily determine that from inspecting
- # libtool variables, so we have to hard-code the OSs to which it
- # applies here; at the moment, that means platforms that use the PE
- # object format with DLL files. See the long comment at the top of
- # tests/bindir.at for full details.
- tdlname=$dlname
- 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 -n "$bindir"; then
- func_relative_path "$install_libdir" "$bindir"
- tdlname=$func_relative_path_result/$dlname
- else
- # Otherwise fall back on heuristic.
- tdlname=../bin/$dlname
- fi
- ;;
- esac
- $ECHO > $output "\
-# $outputname - a libtool library file
-# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# The name that we can dlopen(3).
-dlname='$tdlname'
-
-# Names of this library.
-library_names='$library_names'
-
-# The name of the static archive.
-old_library='$old_library'
-
-# Linker flags that cannot go in dependency_libs.
-inherited_linker_flags='$new_inherited_linker_flags'
-
-# Libraries that this one depends upon.
-dependency_libs='$dependency_libs'
-
-# Names of additional weak libraries provided by this library
-weak_library_names='$weak_libs'
-
-# Version information for $libname.
-current=$current
-age=$age
-revision=$revision
-
-# Is this an already installed library?
-installed=$installed
-
-# Should we warn about portability when linking against -modules?
-shouldnotlink=$module
-
-# Files to dlopen/dlpreopen
-dlopen='$dlfiles'
-dlpreopen='$dlprefiles'
-
-# Directory that this library needs to be installed in:
-libdir='$install_libdir'"
- if test no,yes = "$installed,$need_relink"; then
- $ECHO >> $output "\
-relink_command=\"$relink_command\""
- fi
- done
- }
-
- # Do a symbolic link so that the libtool archive can be found in
- # LD_LIBRARY_PATH before the program is installed.
- func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
- ;;
- esac
- exit $EXIT_SUCCESS
-}
-
-if test link = "$opt_mode" || test relink = "$opt_mode"; then
- func_mode_link ${1+"$@"}
-fi
-
-
-# func_mode_uninstall arg...
-func_mode_uninstall ()
-{
- $debug_cmd
-
- RM=$nonopt
- files=
- rmforce=false
- exit_status=0
-
- # This variable tells wrapper scripts just to set variables rather
- # than running their programs.
- libtool_install_magic=$magic
-
- for arg
- do
- case $arg in
- -f) func_append RM " $arg"; rmforce=: ;;
- -*) func_append RM " $arg" ;;
- *) func_append files " $arg" ;;
- esac
- done
-
- test -z "$RM" && \
- func_fatal_help "you must specify an RM program"
-
- rmdirs=
-
- for file in $files; do
- func_dirname "$file" "" "."
- dir=$func_dirname_result
- if test . = "$dir"; then
- odir=$objdir
- else
- odir=$dir/$objdir
- fi
- func_basename "$file"
- name=$func_basename_result
- test uninstall = "$opt_mode" && odir=$dir
-
- # Remember odir for removal later, being careful to avoid duplicates
- if test clean = "$opt_mode"; then
- case " $rmdirs " in
- *" $odir "*) ;;
- *) func_append rmdirs " $odir" ;;
- esac
- fi
-
- # Don't error if the file doesn't exist and rm -f was used.
- if { test -L "$file"; } >/dev/null 2>&1 ||
- { test -h "$file"; } >/dev/null 2>&1 ||
- test -f "$file"; then
- :
- elif test -d "$file"; then
- exit_status=1
- continue
- elif $rmforce; then
- continue
- fi
-
- rmfiles=$file
-
- case $name in
- *.la)
- # Possibly a libtool archive, so verify it.
- if func_lalib_p "$file"; then
- func_source $dir/$name
-
- # Delete the libtool libraries and symlinks.
- for n in $library_names; do
- func_append rmfiles " $odir/$n"
- done
- test -n "$old_library" && func_append rmfiles " $odir/$old_library"
-
- case $opt_mode in
- clean)
- case " $library_names " in
- *" $dlname "*) ;;
- *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
- esac
- test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
- ;;
- uninstall)
- if test -n "$library_names"; then
- # Do each command in the postuninstall commands.
- 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" '$rmforce || exit_status=1'
- fi
- # FIXME: should reinstall the best remaining shared library.
- ;;
- esac
- fi
- ;;
-
- *.lo)
- # Possibly a libtool object, so verify it.
- if func_lalib_p "$file"; then
-
- # Read the .lo file
- func_source $dir/$name
-
- # Add PIC object to the list of files to remove.
- 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 none != "$non_pic_object"; then
- func_append rmfiles " $dir/$non_pic_object"
- fi
- fi
- ;;
-
- *)
- if test clean = "$opt_mode"; then
- noexename=$name
- case $file in
- *.exe)
- func_stripname '' '.exe' "$file"
- file=$func_stripname_result
- func_stripname '' '.exe' "$name"
- noexename=$func_stripname_result
- # $file with .exe has already been added to rmfiles,
- # add $file without .exe
- func_append rmfiles " $file"
- ;;
- esac
- # Do a test to see if this is a libtool program.
- if func_ltwrapper_p "$file"; then
- if func_ltwrapper_executable_p "$file"; then
- func_ltwrapper_scriptname "$file"
- relink_command=
- func_source $func_ltwrapper_scriptname_result
- func_append rmfiles " $func_ltwrapper_scriptname_result"
- else
- relink_command=
- func_source $dir/$noexename
- fi
-
- # 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 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"
- fi
- fi
- fi
- ;;
- esac
- func_show_eval "$RM $rmfiles" 'exit_status=1'
- done
-
- # 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"
- fi
- done
-
- exit $exit_status
-}
-
-if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
- func_mode_uninstall ${1+"$@"}
-fi
-
-test -z "$opt_mode" && {
- help=$generic_help
- func_fatal_help "you must specify a MODE"
-}
-
-test -z "$exec_cmd" && \
- func_fatal_help "invalid operation mode '$opt_mode'"
-
-if test -n "$exec_cmd"; then
- eval exec "$exec_cmd"
- exit $EXIT_FAILURE
-fi
-
-exit $exit_status
-
-
-# The TAGs below are defined such that we never get into a situation
-# 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
-# them. This is particularly important on AIX, because we don't
-# support having both static and shared libraries enabled at the same
-# time on that platform, so we default to a shared-only configuration.
-# If a disable-shared tag is given, we'll fallback to a static-only
-# configuration. But we'll never go from static-only to shared-only.
-
-# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
-build_libtool_libs=no
-build_old_libs=yes
-# ### END LIBTOOL TAG CONFIG: disable-shared
-
-# ### BEGIN LIBTOOL TAG CONFIG: disable-static
-build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
-# ### END LIBTOOL TAG CONFIG: disable-static
-
-# Local Variables:
-# mode:shell-script
-# sh-indentation:2
-# End:
diff --git a/contrib/sqlite3/missing b/contrib/sqlite3/missing
deleted file mode 100755
index 1fe1611f1851..000000000000
--- a/contrib/sqlite3/missing
+++ /dev/null
@@ -1,215 +0,0 @@
-#! /bin/sh
-# Common wrapper for a few potentially missing GNU programs.
-
-scriptversion=2018-03-07.03; # UTC
-
-# Copyright (C) 1996-2021 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/contrib/sqlite3/shell.c b/contrib/sqlite3/shell.c
index b08671e14de3..0d5bf19e74d5 100644
--- a/contrib/sqlite3/shell.c
+++ b/contrib/sqlite3/shell.c
@@ -122,9 +122,6 @@ typedef unsigned short int u16;
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
typedef unsigned char u8;
-#if SQLITE_USER_AUTHENTICATION
-# include "sqlite3userauth.h"
-#endif
#include <ctype.h>
#include <stdarg.h>
@@ -210,8 +207,6 @@ typedef unsigned char u8;
# ifndef strdup
# define strdup _strdup
# endif
-# undef popen
-# define popen _popen
# undef pclose
# define pclose _pclose
# endif
@@ -241,6 +236,8 @@ typedef unsigned char u8;
#define IsSpace(X) isspace((unsigned char)X)
#define IsDigit(X) isdigit((unsigned char)X)
#define ToLower(X) (char)tolower((unsigned char)X)
+#define IsAlnum(X) isalnum((unsigned char)X)
+#define IsAlpha(X) isalpha((unsigned char)X)
#if defined(_WIN32) || defined(WIN32)
#if SQLITE_OS_WINRT
@@ -255,19 +252,9 @@ extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
#endif
-/* Use console I/O package as a direct INCLUDE. */
-#define SQLITE_INTERNAL_LINKAGE static
-
-#ifdef SQLITE_SHELL_FIDDLE
-/* Deselect most features from the console I/O package for Fiddle. */
-# define SQLITE_CIO_NO_REDIRECT
-# define SQLITE_CIO_NO_CLASSIFY
-# define SQLITE_CIO_NO_TRANSLATE
-# define SQLITE_CIO_NO_SETMODE
-#endif
-/************************* Begin ../ext/consio/console_io.h ******************/
+/************************* Begin ../ext/misc/sqlite3_stdio.h ******************/
/*
-** 2023 November 1
+** 2024-09-24
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -276,281 +263,56 @@ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
-********************************************************************************
-** This file exposes various interfaces used for console and other I/O
-** by the SQLite project command-line tools. These interfaces are used
-** at either source conglomeration time, compilation time, or run time.
-** This source provides for either inclusion into conglomerated,
-** "single-source" forms or separate compilation then linking.
-**
-** Platform dependencies are "hidden" here by various stratagems so
-** that, provided certain conditions are met, the programs using this
-** source or object code compiled from it need no explicit conditional
-** compilation in their source for their console and stream I/O.
-**
-** The symbols and functionality exposed here are not a public API.
-** This code may change in tandem with other project code as needed.
-**
-** When this .h file and its companion .c are directly incorporated into
-** a source conglomeration (such as shell.c), the preprocessor symbol
-** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O
-** translation for Windows is effected for the build.
-*/
-#define HAVE_CONSOLE_IO_H 1
-#ifndef SQLITE_INTERNAL_LINKAGE
-# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */
-# include <stdio.h>
-#else
-# define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */
-#endif
-
-#ifndef SQLITE3_H
-/* # include "sqlite3.h" */
-#endif
-
-#ifndef SQLITE_CIO_NO_CLASSIFY
-
-/* Define enum for use with following function. */
-typedef enum StreamsAreConsole {
- SAC_NoConsole = 0,
- SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4,
- SAC_AnyConsole = 0x7
-} StreamsAreConsole;
-
-/*
-** Classify the three standard I/O streams according to whether
-** they are connected to a console attached to the process.
+*************************************************************************
**
-** Returns the bit-wise OR of SAC_{In,Out,Err}Console values,
-** or SAC_NoConsole if none of the streams reaches a console.
+** This header file contains definitions of interfaces that provide
+** cross-platform I/O for UTF-8 content.
**
-** This function should be called before any I/O is done with
-** the given streams. As a side-effect, the given inputs are
-** recorded so that later I/O operations on them may be done
-** differently than the C library FILE* I/O would be done,
-** iff the stream is used for the I/O functions that follow,
-** and to support the ones that use an implicit stream.
+** On most platforms, the interfaces definitions in this file are
+** just #defines. For example sqlite3_fopen() is a macro that resolves
+** to the standard fopen() in the C-library.
**
-** On some platforms, stream or console mode alteration (aka
-** "Setup") may be made which is undone by consoleRestore().
-*/
-SQLITE_INTERNAL_LINKAGE StreamsAreConsole
-consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr );
-/* A usual call for convenience: */
-#define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr)
-
-/*
-** After an initial call to consoleClassifySetup(...), renew
-** the same setup it effected. (A call not after is an error.)
-** This will restore state altered by consoleRestore();
+** But Windows does not have a standard C-library, at least not one that
+** can handle UTF-8. So for windows build, the interfaces resolve to new
+** C-language routines contained in the separate sqlite3_stdio.c source file.
**
-** Applications which run an inferior (child) process which
-** inherits the same I/O streams may call this function after
-** such a process exits to guard against console mode changes.
+** So on all non-Windows platforms, simply #include this header file and
+** use the interfaces defined herein. Then to run your application on Windows,
+** also link in the accompanying sqlite3_stdio.c source file when compiling
+** to get compatible interfaces.
*/
-SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void);
+#ifndef _SQLITE3_STDIO_H_
+#define _SQLITE3_STDIO_H_ 1
+#ifdef _WIN32
+/**** Definitions For Windows ****/
+#include <stdio.h>
+#include <windows.h>
-/*
-** Undo any side-effects left by consoleClassifySetup(...).
-**
-** This should be called after consoleClassifySetup() and
-** before the process terminates normally. It is suitable
-** for use with the atexit() C library procedure. After
-** this call, no console I/O should be done until one of
-** console{Classify or Renew}Setup(...) is called again.
-**
-** Applications which run an inferior (child) process that
-** inherits the same I/O streams might call this procedure
-** before so that said process will have a console setup
-** however users have configured it or come to expect.
-*/
-SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void );
+FILE *sqlite3_fopen(const char *zFilename, const char *zMode);
+FILE *sqlite3_popen(const char *zCommand, const char *type);
+char *sqlite3_fgets(char *s, int size, FILE *stream);
+int sqlite3_fputs(const char *s, FILE *stream);
+int sqlite3_fprintf(FILE *stream, const char *format, ...);
+void sqlite3_fsetmode(FILE *stream, int mode);
-#else /* defined(SQLITE_CIO_NO_CLASSIFY) */
-# define consoleClassifySetup(i,o,e)
-# define consoleRenewSetup()
-# define consoleRestore()
-#endif /* defined(SQLITE_CIO_NO_CLASSIFY) */
-#ifndef SQLITE_CIO_NO_REDIRECT
-/*
-** Set stream to be used for the functions below which write
-** to "the designated X stream", where X is Output or Error.
-** Returns the previous value.
-**
-** Alternatively, pass the special value, invalidFileStream,
-** to get the designated stream value without setting it.
-**
-** Before the designated streams are set, they default to
-** those passed to consoleClassifySetup(...), and before
-** that is called they default to stdout and stderr.
-**
-** It is error to close a stream so designated, then, without
-** designating another, use the corresponding {o,e}Emit(...).
-*/
-SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream;
-SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf);
-# ifdef CONSIO_SET_ERROR_STREAM
-SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf);
-# endif
#else
-# define setOutputStream(pf)
-# define setErrorStream(pf)
-#endif /* !defined(SQLITE_CIO_NO_REDIRECT) */
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-/*
-** Emit output like fprintf(). If the output is going to the
-** console and translation from UTF-8 is necessary, perform
-** the needed translation. Otherwise, write formatted output
-** to the provided stream almost as-is, possibly with newline
-** translation as specified by set{Binary,Text}Mode().
-*/
-SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...);
-/* Like fPrintfUtf8 except stream is always the designated output. */
-SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...);
-/* Like fPrintfUtf8 except stream is always the designated error. */
-SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...);
-
-/*
-** Emit output like fputs(). If the output is going to the
-** console and translation from UTF-8 is necessary, perform
-** the needed translation. Otherwise, write given text to the
-** provided stream almost as-is, possibly with newline
-** translation as specified by set{Binary,Text}Mode().
-*/
-SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO);
-/* Like fPutsUtf8 except stream is always the designated output. */
-SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z);
-/* Like fPutsUtf8 except stream is always the designated error. */
-SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z);
-
-/*
-** Emit output like fPutsUtf8(), except that the length of the
-** accepted char or character sequence is limited by nAccept.
-**
-** Returns the number of accepted char values.
-*/
-#ifdef CONSIO_SPUTB
-SQLITE_INTERNAL_LINKAGE int
-fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept);
-/* Like fPutbUtf8 except stream is always the designated output. */
-#endif
-SQLITE_INTERNAL_LINKAGE int
-oPutbUtf8(const char *cBuf, int nAccept);
-/* Like fPutbUtf8 except stream is always the designated error. */
-#ifdef CONSIO_EPUTB
-SQLITE_INTERNAL_LINKAGE int
-ePutbUtf8(const char *cBuf, int nAccept);
-#endif
-
-/*
-** Collect input like fgets(...) with special provisions for input
-** from the console on platforms that require same. Defers to the
-** C library fgets() when input is not from the console. Newline
-** translation may be done as set by set{Binary,Text}Mode(). As a
-** convenience, pfIn==NULL is treated as stdin.
-*/
-SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
-/* Like fGetsUtf8 except stream is always the designated input. */
-/* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
-
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
-
-#ifndef SQLITE_CIO_NO_SETMODE
-/*
-** Set given stream for binary mode, where newline translation is
-** not done, or for text mode where, for some platforms, newlines
-** are translated to the platform's conventional char sequence.
-** If bFlush true, flush the stream.
-**
-** An additional side-effect is that if the stream is one passed
-** to consoleClassifySetup() as an output, it is flushed first.
-**
-** Note that binary/text mode has no effect on console I/O
-** translation. On all platforms, newline to the console starts
-** a new line and CR,LF chars from the console become a newline.
-*/
-SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush);
-SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush);
-#endif
-
-#ifdef SQLITE_CIO_PROMPTED_IN
-typedef struct Prompts {
- int numPrompts;
- const char **azPrompts;
-} Prompts;
-
-/*
-** Macros for use of a line editor.
-**
-** The following macros define operations involving use of a
-** line-editing library or simple console interaction.
-** A "T" argument is a text (char *) buffer or filename.
-** A "N" argument is an integer.
-**
-** SHELL_ADD_HISTORY(T) // Record text as line(s) of history.
-** SHELL_READ_HISTORY(T) // Read history from file named by T.
-** SHELL_WRITE_HISTORY(T) // Write history to file named by T.
-** SHELL_STIFLE_HISTORY(N) // Limit history to N entries.
-**
-** A console program which does interactive console input is
-** expected to call:
-** SHELL_READ_HISTORY(T) before collecting such input;
-** SHELL_ADD_HISTORY(T) as record-worthy input is taken;
-** SHELL_STIFLE_HISTORY(N) after console input ceases; then
-** SHELL_WRITE_HISTORY(T) before the program exits.
-*/
-
-/*
-** Retrieve a single line of input text from an input stream.
-**
-** If pfIn is the input stream passed to consoleClassifySetup(),
-** and azPrompt is not NULL, then a prompt is issued before the
-** line is collected, as selected by the isContinuation flag.
-** Array azPrompt[{0,1}] holds the {main,continuation} prompt.
-**
-** If zBufPrior is not NULL then it is a buffer from a prior
-** call to this routine that can be reused, or will be freed.
-**
-** The result is stored in space obtained from malloc() and
-** must either be freed by the caller or else passed back to
-** this function as zBufPrior for reuse.
-**
-** This function may call upon services of a line-editing
-** library to interactively collect line edited input.
-*/
-SQLITE_INTERNAL_LINKAGE char *
-shellGetLine(FILE *pfIn, char *zBufPrior, int nLen,
- short isContinuation, Prompts azPrompt);
-#endif /* defined(SQLITE_CIO_PROMPTED_IN) */
-/*
-** TBD: Define an interface for application(s) to generate
-** completion candidates for use by the line-editor.
-**
-** This may be premature; the CLI is the only application
-** that does this. Yet, getting line-editing melded into
-** console I/O is desirable because a line-editing library
-** may have to establish console operating mode, possibly
-** in a way that interferes with the above functionality.
-*/
-
-#if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))
-/* Skip over as much z[] input char sequence as is valid UTF-8,
-** limited per nAccept char's or whole characters and containing
-** no char cn such that ((1<<cn) & ccm)!=0. On return, the
-** sequence z:return (inclusive:exclusive) is validated UTF-8.
-** Limit: nAccept>=0 => char count, nAccept<0 => character
- */
-SQLITE_INTERNAL_LINKAGE const char*
-zSkipValidUtf8(const char *z, int nAccept, long ccm);
+/**** Definitions For All Other Platforms ****/
+#include <stdio.h>
+#define sqlite3_fopen fopen
+#define sqlite3_popen popen
+#define sqlite3_fgets fgets
+#define sqlite3_fputs fputs
+#define sqlite3_fprintf fprintf
+#define sqlite3_fsetmode(F,X) /*no-op*/
#endif
+#endif /* _SQLITE3_STDIO_H_ */
-/************************* End ../ext/consio/console_io.h ********************/
-/************************* Begin ../ext/consio/console_io.c ******************/
+/************************* End ../ext/misc/sqlite3_stdio.h ********************/
+/************************* Begin ../ext/misc/sqlite3_stdio.c ******************/
/*
-** 2023 November 4
+** 2024-09-24
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -559,731 +321,317 @@ zSkipValidUtf8(const char *z, int nAccept, long ccm);
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
-********************************************************************************
-** This file implements various interfaces used for console and stream I/O
-** by the SQLite project command-line tools, as explained in console_io.h .
-** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there.
+*************************************************************************
+**
+** Implementation of standard I/O interfaces for UTF-8 that are missing
+** on Windows.
*/
-
-#ifndef SQLITE_CDECL
-# define SQLITE_CDECL
-#endif
-
-#ifndef SHELL_NO_SYSINC
-# include <stdarg.h>
-# include <string.h>
-# include <stdlib.h>
-# include <limits.h>
-# include <assert.h>
-/* # include "sqlite3.h" */
-#endif
-#ifndef HAVE_CONSOLE_IO_H
-# include "console_io.h"
-#endif
-#if defined(_MSC_VER)
-# pragma warning(disable : 4204)
+#ifdef _WIN32 /* This file is a no-op on all platforms except Windows */
+#ifndef _SQLITE3_STDIO_H_
+/* #include "sqlite3_stdio.h" */
#endif
+#undef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+/* #include "sqlite3.h" */
+#include <ctype.h>
+#include <stdarg.h>
+#include <io.h>
+#include <fcntl.h>
-#ifndef SQLITE_CIO_NO_TRANSLATE
-# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
-# ifndef SHELL_NO_SYSINC
-# include <io.h>
-# include <fcntl.h>
-# undef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-# endif
-# define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */
-# else
-# ifndef SHELL_NO_SYSINC
-# include <unistd.h>
-# endif
-# define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
-# endif
+/*
+** If the SQLITE_U8TEXT_ONLY option is defined, then use O_U8TEXT
+** when appropriate on all output. (Sometimes use O_BINARY when
+** rendering ASCII text in cases where NL-to-CRLF expansion would
+** not be correct.)
+**
+** If the SQLITE_U8TEXT_STDIO option is defined, then use O_U8TEXT
+** when appropriate when writing to stdout or stderr. Use O_BINARY
+** or O_TEXT (depending on things like the .mode and the .crlf setting
+** in the CLI, or other context clues in other applications) for all
+** other output channels.
+**
+** The default behavior, if neither of the above is defined is to
+** use O_U8TEXT when writing to the Windows console (or anything
+** else for which _isatty() returns true) and to use O_BINARY or O_TEXT
+** for all other output channels.
+**
+** The SQLITE_USE_W32_FOR_CONSOLE_IO macro is also available. If
+** defined, it forces the use of Win32 APIs for all console I/O, both
+** input and output. This is necessary for some non-Microsoft run-times
+** that implement stdio differently from Microsoft/Visual-Studio.
+*/
+#if defined(SQLITE_U8TEXT_ONLY)
+# define UseWtextForOutput(fd) 1
+# define UseWtextForInput(fd) 1
+# define IsConsole(fd) _isatty(_fileno(fd))
+#elif defined(SQLITE_U8TEXT_STDIO)
+# define UseWtextForOutput(fd) ((fd)==stdout || (fd)==stderr)
+# define UseWtextForInput(fd) ((fd)==stdin)
+# define IsConsole(fd) _isatty(_fileno(fd))
#else
-# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
-#endif
-
-#if CIO_WIN_WC_XLATE
-static HANDLE handleOfFile(FILE *pf){
- int fileDesc = _fileno(pf);
- union { intptr_t osfh; HANDLE fh; } fid = {
- (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
- };
- return fid.fh;
-}
+# define UseWtextForOutput(fd) _isatty(_fileno(fd))
+# define UseWtextForInput(fd) _isatty(_fileno(fd))
+# define IsConsole(fd) 1
#endif
-#ifndef SQLITE_CIO_NO_TRANSLATE
-typedef struct PerStreamTags {
-# if CIO_WIN_WC_XLATE
- HANDLE hx;
- DWORD consMode;
- char acIncomplete[4];
-# else
- short reachesConsole;
-# endif
- FILE *pf;
-} PerStreamTags;
-
-/* Define NULL-like value for things which can validly be 0. */
-# define SHELL_INVALID_FILE_PTR ((FILE *)~0)
-# if CIO_WIN_WC_XLATE
-# define SHELL_INVALID_CONS_MODE 0xFFFF0000
-# endif
-
-# if CIO_WIN_WC_XLATE
-# define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \
- {0,0,0,0}, SHELL_INVALID_FILE_PTR }
-# else
-# define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR }
-# endif
-
-/* Quickly say whether a known output is going to the console. */
-# if CIO_WIN_WC_XLATE
-static short pstReachesConsole(PerStreamTags *ppst){
- return (ppst->hx != INVALID_HANDLE_VALUE);
-}
-# else
-# define pstReachesConsole(ppst) 0
-# endif
+/*
+** Global variables determine if simulated O_BINARY mode is to be
+** used for stdout or other, respectively. Simulated O_BINARY mode
+** means the mode is usually O_BINARY, but switches to O_U8TEXT for
+** unicode characters U+0080 or greater (any character that has a
+** multi-byte representation in UTF-8). This is the only way we
+** have found to render Unicode characters on a Windows console while
+** at the same time avoiding undesirable \n to \r\n translation.
+*/
+static int simBinaryStdout = 0;
+static int simBinaryOther = 0;
-# if CIO_WIN_WC_XLATE
-static void restoreConsoleArb(PerStreamTags *ppst){
- if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode);
-}
-# else
-# define restoreConsoleArb(ppst)
-# endif
-/* Say whether FILE* appears to be a console, collect associated info. */
-static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){
-# if CIO_WIN_WC_XLATE
- short rv = 0;
- DWORD dwCM = SHELL_INVALID_CONS_MODE;
- HANDLE fh = handleOfFile(pf);
- ppst->pf = pf;
- if( INVALID_HANDLE_VALUE != fh ){
- rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM));
- }
- ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE;
- ppst->consMode = dwCM;
- return rv;
-# else
- ppst->pf = pf;
- ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
- return ppst->reachesConsole;
-# endif
+/*
+** Determine if simulated binary mode should be used for output to fd
+*/
+static int UseBinaryWText(FILE *fd){
+ if( fd==stdout || fd==stderr ){
+ return simBinaryStdout;
+ }else{
+ return simBinaryOther;
+ }
}
-# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
-# define ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4)
-# endif
-
-# if CIO_WIN_WC_XLATE
-/* Define console modes for use with the Windows Console API. */
-# define SHELL_CONI_MODE \
- (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \
- | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT)
-# define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \
- | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
-# endif
-typedef struct ConsoleInfo {
- PerStreamTags pstSetup[3];
- PerStreamTags pstDesignated[3];
- StreamsAreConsole sacSetup;
-} ConsoleInfo;
+/*
+** Work-alike for the fopen() routine from the standard C library.
+*/
+FILE *sqlite3_fopen(const char *zFilename, const char *zMode){
+ FILE *fp = 0;
+ wchar_t *b1, *b2;
+ int sz1, sz2;
-static short isValidStreamInfo(PerStreamTags *ppst){
- return (ppst->pf != SHELL_INVALID_FILE_PTR);
+ sz1 = (int)strlen(zFilename);
+ sz2 = (int)strlen(zMode);
+ b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
+ b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
+ if( b1 && b2 ){
+ sz1 = MultiByteToWideChar(CP_UTF8, 0, zFilename, sz1, b1, sz1);
+ b1[sz1] = 0;
+ sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2);
+ b2[sz2] = 0;
+ fp = _wfopen(b1, b2);
+ }
+ sqlite3_free(b1);
+ sqlite3_free(b2);
+ simBinaryOther = 0;
+ return fp;
}
-static ConsoleInfo consoleInfo = {
- { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
- { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
- SAC_NoConsole /* sacSetup */
-};
-SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0;
-
-# if CIO_WIN_WC_XLATE
-static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){
- if( pstReachesConsole(ppst) ){
- DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE;
- SetConsoleMode(ppst->hx, cm);
- }
-}
-# else
-# define maybeSetupAsConsole(ppst,odir)
-# endif
+/*
+** Work-alike for the popen() routine from the standard C library.
+*/
+FILE *sqlite3_popen(const char *zCommand, const char *zMode){
+ FILE *fp = 0;
+ wchar_t *b1, *b2;
+ int sz1, sz2;
-SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){
-# if CIO_WIN_WC_XLATE
- int ix = 0;
- while( ix < 6 ){
- PerStreamTags *ppst = (ix<3)?
- &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3];
- maybeSetupAsConsole(ppst, (ix % 3)>0);
- ++ix;
+ sz1 = (int)strlen(zCommand);
+ sz2 = (int)strlen(zMode);
+ b1 = sqlite3_malloc( (sz1+1)*sizeof(b1[0]) );
+ b2 = sqlite3_malloc( (sz2+1)*sizeof(b1[0]) );
+ if( b1 && b2 ){
+ sz1 = MultiByteToWideChar(CP_UTF8, 0, zCommand, sz1, b1, sz1);
+ b1[sz1] = 0;
+ sz2 = MultiByteToWideChar(CP_UTF8, 0, zMode, sz2, b2, sz2);
+ b2[sz2] = 0;
+ fp = _wpopen(b1, b2);
}
-# endif
+ sqlite3_free(b1);
+ sqlite3_free(b2);
+ return fp;
}
-SQLITE_INTERNAL_LINKAGE StreamsAreConsole
-consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
- StreamsAreConsole rv = SAC_NoConsole;
- FILE* apf[3] = { pfIn, pfOut, pfErr };
- int ix;
- for( ix = 2; ix >= 0; --ix ){
- PerStreamTags *ppst = &consoleInfo.pstSetup[ix];
- if( streamOfConsole(apf[ix], ppst) ){
- rv |= (SAC_InConsole<<ix);
+/*
+** Work-alike for fgets() from the standard C library.
+*/
+char *sqlite3_fgets(char *buf, int sz, FILE *in){
+ if( UseWtextForInput(in) ){
+ /* When reading from the command-prompt in Windows, it is necessary
+ ** to use _O_WTEXT input mode to read UTF-16 characters, then translate
+ ** that into UTF-8. Otherwise, non-ASCII characters all get translated
+ ** into '?'.
+ */
+ wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
+ if( b1==0 ) return 0;
+#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
+ DWORD nRead = 0;
+ if( IsConsole(in)
+ && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz-1, &nRead, 0)
+ ){
+ b1[nRead] = 0;
+ }else
+#endif
+ {
+ _setmode(_fileno(in), IsConsole(in) ? _O_WTEXT : _O_U8TEXT);
+ if( fgetws(b1, sz/4, in)==0 ){
+ sqlite3_free(b1);
+ return 0;
+ }
}
- consoleInfo.pstDesignated[ix] = *ppst;
- if( ix > 0 ) fflush(apf[ix]);
+ WideCharToMultiByte(CP_UTF8, 0, b1, -1, buf, sz, 0, 0);
+ sqlite3_free(b1);
+ return buf;
+ }else{
+ /* Reading from a file or other input source, just read bytes without
+ ** any translation. */
+ return fgets(buf, sz, in);
}
- consoleInfo.sacSetup = rv;
- consoleRenewSetup();
- return rv;
}
-SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){
-# if CIO_WIN_WC_XLATE
- static ConsoleInfo *pci = &consoleInfo;
- if( pci->sacSetup ){
- int ix;
- for( ix=0; ix<3; ++ix ){
- if( pci->sacSetup & (SAC_InConsole<<ix) ){
- PerStreamTags *ppst = &pci->pstSetup[ix];
- SetConsoleMode(ppst->hx, ppst->consMode);
+/*
+** Send ASCII text as O_BINARY. But for Unicode characters U+0080 and
+** greater, switch to O_U8TEXT.
+*/
+static void piecemealOutput(wchar_t *b1, int sz, FILE *out){
+ int i;
+ wchar_t c;
+ while( sz>0 ){
+ for(i=0; i<sz && b1[i]>=0x80; i++){}
+ if( i>0 ){
+ c = b1[i];
+ b1[i] = 0;
+ fflush(out);
+ _setmode(_fileno(out), _O_U8TEXT);
+ fputws(b1, out);
+ fflush(out);
+ b1 += i;
+ b1[0] = c;
+ sz -= i;
+ }else{
+ fflush(out);
+ _setmode(_fileno(out), _O_TEXT);
+ _setmode(_fileno(out), _O_BINARY);
+ fwrite(&b1[0], 1, 1, out);
+ for(i=1; i<sz && b1[i]<0x80; i++){
+ fwrite(&b1[i], 1, 1, out);
}
+ fflush(out);
+ _setmode(_fileno(out), _O_U8TEXT);
+ b1 += i;
+ sz -= i;
}
}
-# endif
}
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
-#ifdef SQLITE_CIO_INPUT_REDIR
-/* Say whether given FILE* is among those known, via either
-** consoleClassifySetup() or set{Output,Error}Stream, as
-** readable, and return an associated PerStreamTags pointer
-** if so. Otherwise, return 0.
+/*
+** Work-alike for fputs() from the standard C library.
*/
-static PerStreamTags * isKnownReadable(FILE *pf){
- static PerStreamTags *apst[] = {
- &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0
- };
- int ix = 0;
- do {
- if( apst[ix]->pf == pf ) break;
- } while( apst[++ix] != 0 );
- return apst[ix];
-}
+int sqlite3_fputs(const char *z, FILE *out){
+ if( !UseWtextForOutput(out) ){
+ /* Writing to a file or other destination, just write bytes without
+ ** any translation. */
+ return fputs(z, out);
+ }else{
+ /* One must use UTF16 in order to get unicode support when writing
+ ** to the console on Windows.
+ */
+ int sz = (int)strlen(z);
+ wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
+ if( b1==0 ) return 0;
+ sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
+ b1[sz] = 0;
+
+#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
+ DWORD nWr = 0;
+ if( IsConsole(out)
+ && WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),b1,sz,&nWr,0)
+ ){
+ /* If writing to the console, then the WriteConsoleW() is all we
+ ** need to do. */
+ }else
#endif
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-/* Say whether given FILE* is among those known, via either
-** consoleClassifySetup() or set{Output,Error}Stream, as
-** writable, and return an associated PerStreamTags pointer
-** if so. Otherwise, return 0.
-*/
-static PerStreamTags * isKnownWritable(FILE *pf){
- static PerStreamTags *apst[] = {
- &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2],
- &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0
- };
- int ix = 0;
- do {
- if( apst[ix]->pf == pf ) break;
- } while( apst[++ix] != 0 );
- return apst[ix];
-}
-
-static FILE *designateEmitStream(FILE *pf, unsigned chix){
- FILE *rv = consoleInfo.pstDesignated[chix].pf;
- if( pf == invalidFileStream ) return rv;
- else{
- /* Setting a possibly new output stream. */
- PerStreamTags *ppst = isKnownWritable(pf);
- if( ppst != 0 ){
- PerStreamTags pst = *ppst;
- consoleInfo.pstDesignated[chix] = pst;
- }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]);
- }
- return rv;
-}
-
-SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){
- return designateEmitStream(pf, 1);
-}
-# ifdef CONSIO_SET_ERROR_STREAM
-SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){
- return designateEmitStream(pf, 2);
-}
-# endif
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
-
-#ifndef SQLITE_CIO_NO_SETMODE
-# if CIO_WIN_WC_XLATE
-static void setModeFlushQ(FILE *pf, short bFlush, int mode){
- if( bFlush ) fflush(pf);
- _setmode(_fileno(pf), mode);
-}
-# else
-# define setModeFlushQ(f, b, m) if(b) fflush(f)
-# endif
-
-SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){
- setModeFlushQ(pf, bFlush, _O_BINARY);
-}
-SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){
- setModeFlushQ(pf, bFlush, _O_TEXT);
-}
-# undef setModeFlushQ
-
-#else /* defined(SQLITE_CIO_NO_SETMODE) */
-# define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
-# define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
-#endif /* defined(SQLITE_CIO_NO_SETMODE) */
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-# if CIO_WIN_WC_XLATE
-/* Write buffer cBuf as output to stream known to reach console,
-** limited to ncTake char's. Return ncTake on success, else 0. */
-static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){
- int rv = 0;
- if( z!=NULL ){
- int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0);
- if( nwc > 0 ){
- WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR));
- if( zw!=NULL ){
- nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc);
- if( nwc > 0 ){
- /* Translation from UTF-8 to UTF-16, then WCHARs out. */
- if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){
- rv = ncTake;
- }
- }
- sqlite3_free(zw);
+ {
+ /* As long as SQLITE_USE_W32_FOR_CONSOLE_IO is not defined, or for
+ ** non-console I/O even if that macro is defined, write using the
+ ** standard library. */
+ _setmode(_fileno(out), _O_U8TEXT);
+ if( UseBinaryWText(out) ){
+ piecemealOutput(b1, sz, out);
+ }else{
+ fputws(b1, out);
}
}
+ sqlite3_free(b1);
+ return 0;
}
- return rv;
}
-/* For {f,o,e}PrintfUtf8() when stream is known to reach console. */
-static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){
- char *z = sqlite3_vmprintf(zFormat, ap);
- if( z ){
- int rv = conZstrEmit(ppst, z, (int)strlen(z));
- sqlite3_free(z);
- return rv;
- }else return 0;
-}
-# endif /* CIO_WIN_WC_XLATE */
-# ifdef CONSIO_GET_EMIT_STREAM
-static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix,
- PerStreamTags *ppst){
- PerStreamTags *rv = isKnownWritable(pf);
- short isValid = (rv!=0)? isValidStreamInfo(rv) : 0;
- if( rv != 0 && isValid ) return rv;
- streamOfConsole(pf, ppst);
- return ppst;
-}
-# endif
-
-/* Get stream info, either for designated output or error stream when
-** chix equals 1 or 2, or for an arbitrary stream when chix == 0.
-** In either case, ppst references a caller-owned PerStreamTags
-** struct which may be filled in if none of the known writable
-** streams is being held by consoleInfo. The ppf parameter is a
-** byref output when chix!=0 and a byref input when chix==0.
- */
-static PerStreamTags *
-getEmitStreamInfo(unsigned chix, PerStreamTags *ppst,
- /* in/out */ FILE **ppf){
- PerStreamTags *ppstTry;
- FILE *pfEmit;
- if( chix > 0 ){
- ppstTry = &consoleInfo.pstDesignated[chix];
- if( !isValidStreamInfo(ppstTry) ){
- ppstTry = &consoleInfo.pstSetup[chix];
- pfEmit = ppst->pf;
- }else pfEmit = ppstTry->pf;
- if( !isValidStreamInfo(ppstTry) ){
- pfEmit = (chix > 1)? stderr : stdout;
- ppstTry = ppst;
- streamOfConsole(pfEmit, ppstTry);
- }
- *ppf = pfEmit;
- }else{
- ppstTry = isKnownWritable(*ppf);
- if( ppstTry != 0 ) return ppstTry;
- streamOfConsole(*ppf, ppst);
- return ppst;
- }
- return ppstTry;
-}
-
-SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){
- va_list ap;
- int rv;
- FILE *pfOut;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
-# else
- getEmitStreamInfo(1, &pst, &pfOut);
-# endif
- assert(zFormat!=0);
- va_start(ap, zFormat);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- rv = conioVmPrintf(ppst, zFormat, ap);
- }else{
-# endif
- rv = vfprintf(pfOut, zFormat, ap);
-# if CIO_WIN_WC_XLATE
- }
-# endif
- va_end(ap);
- return rv;
-}
+/*
+** Work-alike for fprintf() from the standard C library.
+*/
+int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
+ int rc;
+ if( UseWtextForOutput(out) ){
+ /* When writing to the command-prompt in Windows, it is necessary
+ ** to use _O_WTEXT input mode and write UTF-16 characters.
+ */
+ char *z;
+ va_list ap;
-SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){
- va_list ap;
- int rv;
- FILE *pfErr;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
-# else
- getEmitStreamInfo(2, &pst, &pfErr);
-# endif
- assert(zFormat!=0);
- va_start(ap, zFormat);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- rv = conioVmPrintf(ppst, zFormat, ap);
+ va_start(ap, zFormat);
+ z = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ sqlite3_fputs(z, out);
+ rc = (int)strlen(z);
+ sqlite3_free(z);
}else{
-# endif
- rv = vfprintf(pfErr, zFormat, ap);
-# if CIO_WIN_WC_XLATE
+ /* Writing to a file or other destination, just write bytes without
+ ** any translation. */
+ va_list ap;
+ va_start(ap, zFormat);
+ rc = vfprintf(out, zFormat, ap);
+ va_end(ap);
}
-# endif
- va_end(ap);
- return rv;
+ return rc;
}
-SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){
- va_list ap;
- int rv;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
-# else
- getEmitStreamInfo(0, &pst, &pfO);
-# endif
- assert(zFormat!=0);
- va_start(ap, zFormat);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- maybeSetupAsConsole(ppst, 1);
- rv = conioVmPrintf(ppst, zFormat, ap);
- if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
+/*
+** Set the mode for an output stream. mode argument is typically _O_BINARY or
+** _O_TEXT.
+*/
+void sqlite3_fsetmode(FILE *fp, int mode){
+ if( !UseWtextForOutput(fp) ){
+ fflush(fp);
+ _setmode(_fileno(fp), mode);
+ }else if( fp==stdout || fp==stderr ){
+ simBinaryStdout = (mode==_O_BINARY);
}else{
-# endif
- rv = vfprintf(pfO, zFormat, ap);
-# if CIO_WIN_WC_XLATE
- }
-# endif
- va_end(ap);
- return rv;
-}
-
-SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
-# else
- getEmitStreamInfo(0, &pst, &pfO);
-# endif
- assert(z!=0);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- int rv;
- maybeSetupAsConsole(ppst, 1);
- rv = conZstrEmit(ppst, z, (int)strlen(z));
- if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
- return rv;
- }else {
-# endif
- return (fputs(z, pfO)<0)? 0 : (int)strlen(z);
-# if CIO_WIN_WC_XLATE
+ simBinaryOther = (mode==_O_BINARY);
}
-# endif
}
-SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){
- FILE *pfErr;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
-# else
- getEmitStreamInfo(2, &pst, &pfErr);
-# endif
- assert(z!=0);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
- else {
-# endif
- return (fputs(z, pfErr)<0)? 0 : (int)strlen(z);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-
-SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){
- FILE *pfOut;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
-# else
- getEmitStreamInfo(1, &pst, &pfOut);
-# endif
- assert(z!=0);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
- else {
-# endif
- return (fputs(z, pfOut)<0)? 0 : (int)strlen(z);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
+#endif /* defined(_WIN32) */
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+/************************* End ../ext/misc/sqlite3_stdio.c ********************/
-#if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE))
-/* Skip over as much z[] input char sequence as is valid UTF-8,
-** limited per nAccept char's or whole characters and containing
-** no char cn such that ((1<<cn) & ccm)!=0. On return, the
-** sequence z:return (inclusive:exclusive) is validated UTF-8.
-** Limit: nAccept>=0 => char count, nAccept<0 => character
- */
-SQLITE_INTERNAL_LINKAGE const char*
-zSkipValidUtf8(const char *z, int nAccept, long ccm){
- int ng = (nAccept<0)? -nAccept : 0;
- const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
- assert(z!=0);
- while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
- char c = *z;
- if( (c & 0x80) == 0 ){
- if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
- ++z; /* ASCII */
- }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
- else{
- const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
- do{
- if( pcLimit && zt >= pcLimit ) return z;
- else{
- char ct = *zt++;
- if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
- /* Trailing bytes are too few, too many, or invalid. */
- return z;
- }
- }
- } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
- z = zt;
- }
- }
- return z;
-}
-#endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-# ifdef CONSIO_SPUTB
-SQLITE_INTERNAL_LINKAGE int
-fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
- assert(pfO!=0);
-# if CIO_WIN_WC_XLATE
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
- PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
- if( pstReachesConsole(ppst) ){
- int rv;
- maybeSetupAsConsole(ppst, 1);
- rv = conZstrEmit(ppst, cBuf, nAccept);
- if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
- return rv;
- }else {
-# endif
- return (int)fwrite(cBuf, 1, nAccept, pfO);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-# endif
-
-SQLITE_INTERNAL_LINKAGE int
-oPutbUtf8(const char *cBuf, int nAccept){
- FILE *pfOut;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
-# else
- getEmitStreamInfo(1, &pst, &pfOut);
-# endif
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- return conZstrEmit(ppst, cBuf, nAccept);
- }else {
-# endif
- return (int)fwrite(cBuf, 1, nAccept, pfOut);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-
-# ifdef CONSIO_EPUTB
-SQLITE_INTERNAL_LINKAGE int
-ePutbUtf8(const char *cBuf, int nAccept){
- FILE *pfErr;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
- PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- return conZstrEmit(ppst, cBuf, nAccept);
- }else {
-# endif
- return (int)fwrite(cBuf, 1, nAccept, pfErr);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-# endif /* defined(CONSIO_EPUTB) */
-
-SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
- if( pfIn==0 ) pfIn = stdin;
-# if CIO_WIN_WC_XLATE
- if( pfIn == consoleInfo.pstSetup[0].pf
- && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){
-# if CIO_WIN_WC_XLATE==1
-# define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */
- WCHAR wcBuf[SHELL_GULP+1];
- int lend = 0, noc = 0;
- if( ncMax > 0 ) cBuf[0] = 0;
- while( noc < ncMax-8-1 && !lend ){
- /* There is room for at least 2 more characters and a 0-terminator. */
- int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4;
-# undef SHELL_GULP
- DWORD nbr = 0;
- BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0);
- if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){
- /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */
- DWORD nbrx;
- bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0);
- if( bRC ) nbr += nbrx;
- }
- if( !bRC || (noc==0 && nbr==0) ) return 0;
- if( nbr > 0 ){
- int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0);
- if( nmb != 0 && noc+nmb <= ncMax ){
- int iseg = noc;
- nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0);
- noc += nmb;
- /* Fixup line-ends as coded by Windows for CR (or "Enter".)
- ** This is done without regard for any setMode{Text,Binary}()
- ** call that might have been done on the interactive input.
- */
- if( noc > 0 ){
- if( cBuf[noc-1]=='\n' ){
- lend = 1;
- if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n';
- }
- }
- /* Check for ^Z (anywhere in line) too, to act as EOF. */
- while( iseg < noc ){
- if( cBuf[iseg]=='\x1a' ){
- noc = iseg; /* Chop ^Z and anything following. */
- lend = 1; /* Counts as end of line too. */
- break;
- }
- ++iseg;
- }
- }else break; /* Drop apparent garbage in. (Could assert.) */
- }else break;
- }
- /* If got nothing, (after ^Z chop), must be at end-of-file. */
- if( noc > 0 ){
- cBuf[noc] = 0;
- return cBuf;
- }else return 0;
-# endif
- }else{
-# endif
- return fgets(cBuf, ncMax, pfIn);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+/* Use console I/O package as a direct INCLUDE. */
+#define SQLITE_INTERNAL_LINKAGE static
-#if defined(_MSC_VER)
-# pragma warning(default : 4204)
+#ifdef SQLITE_SHELL_FIDDLE
+/* Deselect most features from the console I/O package for Fiddle. */
+# define SQLITE_CIO_NO_REDIRECT
+# define SQLITE_CIO_NO_CLASSIFY
+# define SQLITE_CIO_NO_TRANSLATE
+# define SQLITE_CIO_NO_SETMODE
+# define SQLITE_CIO_NO_FLUSH
#endif
-#undef SHELL_INVALID_FILE_PTR
-
-/************************* End ../ext/consio/console_io.c ********************/
-
-#ifndef SQLITE_SHELL_FIDDLE
-
-/* From here onward, fgets() is redirected to the console_io library. */
-# define fgets(b,n,f) fGetsUtf8(b,n,f)
-/*
- * Define macros for emitting output text in various ways:
- * sputz(s, z) => emit 0-terminated string z to given stream s
- * sputf(s, f, ...) => emit varargs per format f to given stream s
- * oputz(z) => emit 0-terminated string z to default stream
- * oputf(f, ...) => emit varargs per format f to default stream
- * eputz(z) => emit 0-terminated string z to error stream
- * eputf(f, ...) => emit varargs per format f to error stream
- * oputb(b, n) => emit char buffer b[0..n-1] to default stream
- *
- * Note that the default stream is whatever has been last set via:
- * setOutputStream(FILE *pf)
- * This is normally the stream that CLI normal output goes to.
- * For the stand-alone CLI, it is stdout with no .output redirect.
- *
- * The ?putz(z) forms are required for the Fiddle builds for string literal
- * output, in aid of enforcing format string to argument correspondence.
- */
-# define sputz(s,z) fPutsUtf8(z,s)
-# define sputf fPrintfUtf8
-# define oputz(z) oPutsUtf8(z)
-# define oputf oPrintfUtf8
-# define eputz(z) ePutsUtf8(z)
-# define eputf ePrintfUtf8
-# define oputb(buf,na) oPutbUtf8(buf,na)
-
-#else
-/* For Fiddle, all console handling and emit redirection is omitted. */
-/* These next 3 macros are for emitting formatted output. When complaints
- * from the WASM build are issued for non-formatted output, (when a mere
- * string literal is to be emitted, the ?putz(z) forms should be used.
- * (This permits compile-time checking of format string / argument mismatch.)
- */
-# define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
-# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
-# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__)
-/* These next 3 macros are for emitting simple string literals. */
-# define oputz(z) fputs(z,stdout)
-# define eputz(z) fputs(z,stderr)
-# define sputz(fp,z) fputs(z,fp)
-# define oputb(buf,na) fwrite(buf,1,na,stdout)
-#endif
+#define eputz(z) sqlite3_fputs(z,stderr)
+#define sputz(fp,z) sqlite3_fputs(z,fp)
/* True if the timer is enabled */
static int enableTimer = 0;
@@ -1329,6 +677,7 @@ struct rusage {
#define getrusage(A,B) memset(B,0,sizeof(*B))
#endif
+
/* Saved resource information for the beginning of an operation */
static struct rusage sBegin; /* CPU time at start */
static sqlite3_int64 iBegin; /* Wall-clock time at start */
@@ -1352,12 +701,12 @@ static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
/*
** Print the timing results.
*/
-static void endTimer(void){
+static void endTimer(FILE *out){
if( enableTimer ){
sqlite3_int64 iEnd = timeOfDay();
struct rusage sEnd;
getrusage(RUSAGE_SELF, &sEnd);
- sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
+ sqlite3_fprintf(out, "Run Time: real %.3f user %f sys %f\n",
(iEnd - iBegin)*0.001,
timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
@@ -1365,7 +714,7 @@ static void endTimer(void){
}
#define BEGIN_TIMER beginTimer()
-#define END_TIMER endTimer()
+#define END_TIMER(X) endTimer(X)
#define HAS_TIMER 1
#elif (defined(_WIN32) || defined(WIN32))
@@ -1431,12 +780,12 @@ static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
/*
** Print the timing results.
*/
-static void endTimer(void){
+static void endTimer(FILE *out){
if( enableTimer && getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
sqlite3_int64 ftWallEnd = timeOfDay();
getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
- sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
+ sqlite3_fprintf(out, "Run Time: real %.3f user %f sys %f\n",
(ftWallEnd - ftWallBegin)*0.001,
timeDiff(&ftUserBegin, &ftUserEnd),
timeDiff(&ftKernelBegin, &ftKernelEnd));
@@ -1444,12 +793,12 @@ static void endTimer(void){
}
#define BEGIN_TIMER beginTimer()
-#define END_TIMER endTimer()
+#define END_TIMER(X) endTimer(X)
#define HAS_TIMER hasTimer()
#else
#define BEGIN_TIMER
-#define END_TIMER
+#define END_TIMER(X) /*no-op*/
#define HAS_TIMER 0
#endif
@@ -1504,7 +853,7 @@ static char *Argv0;
** Prompt strings. Initialized in main. Settable with
** .prompt main continue
*/
-#define PROMPT_LEN_MAX 20
+#define PROMPT_LEN_MAX 128
/* First line prompt. default: "sqlite> " */
static char mainPrompt[PROMPT_LEN_MAX];
/* Continuation prompt. default: " ...> " */
@@ -1523,6 +872,14 @@ static char *shell_strncpy(char *dest, const char *src, size_t n){
}
/*
+** strcpy() workalike to squelch an unwarranted link-time warning
+** from OpenBSD.
+*/
+static void shell_strcpy(char *dest, const char *src){
+ while( (*(dest++) = *(src++))!=0 ){}
+}
+
+/*
** Optionally disable dynamic continuation prompt.
** Unless disabled, the continuation prompt shows open SQL lexemes if any,
** or open parentheses level if non-zero, or continuation prompt as set.
@@ -1587,7 +944,7 @@ static char *dynamicContinuePrompt(void){
size_t ncp = strlen(continuePrompt);
size_t ndp = strlen(dynPrompt.zScannerAwaits);
if( ndp > ncp-3 ) return continuePrompt;
- strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
+ shell_strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' ';
shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
PROMPT_LEN_MAX-4);
@@ -1642,37 +999,232 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
va_start(ap, zFormat);
z = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
- sputf(iotrace, "%s", z);
+ sqlite3_fprintf(iotrace, "%s", z);
sqlite3_free(z);
}
#endif
+/* Lookup table to estimate the number of columns consumed by a Unicode
+** character.
+*/
+static const struct {
+ unsigned char w; /* Width of the character in columns */
+ int iFirst; /* First character in a span having this width */
+} aUWidth[] = {
+ /* {1, 0x00000}, */
+ {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488},
+ {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0},
+ {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7},
+ {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616},
+ {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6},
+ {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee},
+ {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730},
+ {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4},
+ {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941},
+ {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955},
+ {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc},
+ {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce},
+ {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c},
+ {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49},
+ {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81},
+ {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6},
+ {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2},
+ {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d},
+ {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d},
+ {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83},
+ {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e},
+ {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e},
+ {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf},
+ {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce},
+ {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d},
+ {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5},
+ {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34},
+ {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2},
+ {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8},
+ {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36},
+ {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71},
+ {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88},
+ {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6},
+ {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033},
+ {0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058},
+ {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f},
+ {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735},
+ {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4},
+ {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7},
+ {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b},
+ {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923},
+ {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939},
+ {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04},
+ {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c},
+ {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74},
+ {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b},
+ {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064},
+ {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329},
+ {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f},
+ {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806},
+ {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827},
+ {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e},
+ {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20},
+ {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00},
+ {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc},
+ {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c},
+ {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40},
+ {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185},
+ {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245},
+ {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001},
+ {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0}
+};
+
+/*
+** Return an estimate of the width, in columns, for the single Unicode
+** character c. For normal characters, the answer is always 1. But the
+** estimate might be 0 or 2 for zero-width and double-width characters.
+**
+** Different display devices display unicode using different widths. So
+** it is impossible to know that true display width with 100% accuracy.
+** Inaccuracies in the width estimates might cause columns to be misaligned.
+** Unfortunately, there is nothing we can do about that.
+*/
+int cli_wcwidth(int c){
+ int iFirst, iLast;
+
+ /* Fast path for common characters */
+ if( c<=0x300 ) return 1;
+
+ /* The general case */
+ iFirst = 0;
+ iLast = sizeof(aUWidth)/sizeof(aUWidth[0]) - 1;
+ while( iFirst<iLast-1 ){
+ int iMid = (iFirst+iLast)/2;
+ int cMid = aUWidth[iMid].iFirst;
+ if( cMid < c ){
+ iFirst = iMid;
+ }else if( cMid > c ){
+ iLast = iMid - 1;
+ }else{
+ return aUWidth[iMid].w;
+ }
+ }
+ if( aUWidth[iLast].iFirst > c ) return aUWidth[iFirst].w;
+ return aUWidth[iLast].w;
+}
+
+/*
+** Compute the value and length of a multi-byte UTF-8 character that
+** begins at z[0]. Return the length. Write the Unicode value into *pU.
+**
+** This routine only works for *multi-byte* UTF-8 characters.
+*/
+static int decodeUtf8(const unsigned char *z, int *pU){
+ if( (z[0] & 0xe0)==0xc0 && (z[1] & 0xc0)==0x80 ){
+ *pU = ((z[0] & 0x1f)<<6) | (z[1] & 0x3f);
+ return 2;
+ }
+ if( (z[0] & 0xf0)==0xe0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 ){
+ *pU = ((z[0] & 0x0f)<<12) | ((z[1] & 0x3f)<<6) | (z[2] & 0x3f);
+ return 3;
+ }
+ if( (z[0] & 0xf8)==0xf0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80
+ && (z[3] & 0xc0)==0x80
+ ){
+ *pU = ((z[0] & 0x0f)<<18) | ((z[1] & 0x3f)<<12) | ((z[2] & 0x3f))<<6
+ | (z[4] & 0x3f);
+ return 4;
+ }
+ *pU = 0;
+ return 1;
+}
+
+
+#if 0 /* NOT USED */
/*
-** Output string zUtf to Out stream as w characters. If w is negative,
+** Return the width, in display columns, of a UTF-8 string.
+**
+** Each normal character counts as 1. Zero-width characters count
+** as zero, and double-width characters count as 2.
+*/
+int cli_wcswidth(const char *z){
+ const unsigned char *a = (const unsigned char*)z;
+ int n = 0;
+ int i = 0;
+ unsigned char c;
+ while( (c = a[i])!=0 ){
+ if( c>=0xc0 ){
+ int u;
+ int len = decodeUtf8(&a[i], &u);
+ i += len;
+ n += cli_wcwidth(u);
+ }else if( c>=' ' ){
+ n++;
+ i++;
+ }else{
+ i++;
+ }
+ }
+ return n;
+}
+#endif
+
+/*
+** Check to see if z[] is a valid VT100 escape. If it is, then
+** return the number of bytes in the escape sequence. Return 0 if
+** z[] is not a VT100 escape.
+**
+** This routine assumes that z[0] is \033 (ESC).
+*/
+static int isVt100(const unsigned char *z){
+ int i;
+ if( z[1]!='[' ) return 0;
+ i = 2;
+ while( z[i]>=0x30 && z[i]<=0x3f ){ i++; }
+ while( z[i]>=0x20 && z[i]<=0x2f ){ i++; }
+ if( z[i]<0x40 || z[i]>0x7e ) return 0;
+ return i+1;
+}
+
+/*
+** Output string zUtf to stdout 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.
+**
+** Take into account zero-width and double-width Unicode characters.
+** In other words, a zero-width character does not count toward the
+** the w limit. A double-width character counts as two.
*/
-static void utf8_width_print(int w, const char *zUtf){
- int i;
- int n;
+static void utf8_width_print(FILE *out, int w, const char *zUtf){
+ const unsigned char *a = (const unsigned char*)zUtf;
+ unsigned char c;
+ int i = 0;
+ int n = 0;
+ int k;
int aw = w<0 ? -w : w;
if( zUtf==0 ) zUtf = "";
- for(i=n=0; zUtf[i]; i++){
- if( (zUtf[i]&0xc0)!=0x80 ){
- n++;
- if( n==aw ){
- do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
+ while( (c = a[i])!=0 ){
+ if( (c&0xc0)==0xc0 ){
+ int u;
+ int len = decodeUtf8(a+i, &u);
+ int x = cli_wcwidth(u);
+ if( x+n>aw ){
break;
}
+ i += len;
+ n += x;
+ }else if( c==0x1b && (k = isVt100(&a[i]))>0 ){
+ i += k;
+ }else if( n>=aw ){
+ break;
+ }else{
+ n++;
+ i++;
}
}
if( n>=aw ){
- oputf("%.*s", i, zUtf);
+ sqlite3_fprintf(out, "%.*s", i, zUtf);
}else if( w<0 ){
- oputf("%*s%s", aw-n, "", zUtf);
+ sqlite3_fprintf(out, "%*s%s", aw-n, "", zUtf);
}else{
- oputf("%s%*s", zUtf, aw-n, "");
+ sqlite3_fprintf(out, "%s%*s", zUtf, aw-n, "");
}
}
@@ -1738,7 +1290,7 @@ static FILE * openChrSource(const char *zFile){
/* On Windows, open first, then check the stream nature. This order
** is necessary because _stat() and sibs, when checking a named pipe,
** effectively break the pipe as its supplier sees it. */
- FILE *rv = fopen(zFile, "rb");
+ FILE *rv = sqlite3_fopen(zFile, "rb");
if( rv==0 ) return 0;
if( _fstat64(_fileno(rv), &x) != 0
|| !STAT_CHR_SRC(x.st_mode)){
@@ -1752,7 +1304,7 @@ static FILE * openChrSource(const char *zFile){
# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
if( rc!=0 ) return 0;
if( STAT_CHR_SRC(x.st_mode) ){
- return fopen(zFile, "rb");
+ return sqlite3_fopen(zFile, "rb");
}else{
return 0;
}
@@ -1779,7 +1331,7 @@ static char *local_getline(char *zLine, FILE *in){
zLine = realloc(zLine, nLine);
shell_check_oom(zLine);
}
- if( fgets(&zLine[n], nLine - n, in)==0 ){
+ if( sqlite3_fgets(&zLine[n], nLine - n, in)==0 ){
if( n==0 ){
free(zLine);
return 0;
@@ -1978,9 +1530,9 @@ static void appendText(ShellText *p, const char *zAppend, char quote){
static char quoteChar(const char *zName){
int i;
if( zName==0 ) return '"';
- if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
+ if( !IsAlpha(zName[0]) && zName[0]!='_' ) return '"';
for(i=0; zName[i]; i++){
- if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
+ if( !IsAlnum(zName[i]) && zName[i]!='_' ) return '"';
}
return sqlite3_keyword_check(zName, i) ? '"' : 0;
}
@@ -2072,30 +1624,6 @@ static void shellDtostr(
sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
}
-
-/*
-** 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;
- char *zFake;
- UNUSED_PARAMETER(nVal);
- zName = (const char*)sqlite3_value_text(apVal[0]);
- zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0;
- if( zFake ){
- sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
- -1, sqlite3_free);
- free(zFake);
- }
-}
-
/*
** SQL function: shell_add_schema(S,X)
**
@@ -2270,6 +1798,7 @@ static void shellAddSchemaName(
# else
# define NAME_MAX (260)
# endif
+# define DIRENT_NAME_MAX (NAME_MAX)
#endif
/*
@@ -2313,8 +1842,7 @@ struct DIR {
/*
** 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.
+** the next directory entry that should be returned by the readdir().
*/
#ifndef is_filtered
@@ -2330,12 +1858,11 @@ 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.
+** readdir(), 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) */
@@ -2392,11 +1919,13 @@ const char *windirent_getenv(
** Implementation of the POSIX opendir() function using the MSVCRT.
*/
LPDIR opendir(
- const char *dirname
+ const char *dirname /* Directory name, UTF8 encoding */
){
- struct _finddata_t data;
+ struct _wfinddata_t data;
LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR));
SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]);
+ wchar_t *b1;
+ sqlite3_int64 sz;
if( dirp==NULL ) return NULL;
memset(dirp, 0, sizeof(DIR));
@@ -2406,9 +1935,25 @@ LPDIR opendir(
dirname = windirent_getenv("SystemDrive");
}
- memset(&data, 0, sizeof(struct _finddata_t));
- _snprintf(data.name, namesize, "%s\\*", dirname);
- dirp->d_handle = _findfirst(data.name, &data);
+ memset(&data, 0, sizeof(data));
+ sz = strlen(dirname);
+ b1 = sqlite3_malloc64( (sz+3)*sizeof(b1[0]) );
+ if( b1==0 ){
+ closedir(dirp);
+ return NULL;
+ }
+ sz = MultiByteToWideChar(CP_UTF8, 0, dirname, sz, b1, sz);
+ b1[sz++] = '\\';
+ b1[sz++] = '*';
+ b1[sz] = 0;
+ if( sz+1>(sqlite3_int64)namesize ){
+ closedir(dirp);
+ sqlite3_free(b1);
+ return NULL;
+ }
+ memcpy(data.name, b1, (sz+1)*sizeof(b1[0]));
+ sqlite3_free(b1);
+ dirp->d_handle = _wfindfirst(data.name, &data);
if( dirp->d_handle==BAD_INTPTR_T ){
closedir(dirp);
@@ -2419,8 +1964,8 @@ LPDIR opendir(
if( is_filtered(data) ){
next:
- memset(&data, 0, sizeof(struct _finddata_t));
- if( _findnext(dirp->d_handle, &data)==-1 ){
+ memset(&data, 0, sizeof(data));
+ if( _wfindnext(dirp->d_handle, &data)==-1 ){
closedir(dirp);
return NULL;
}
@@ -2430,9 +1975,8 @@ 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';
-
+ WideCharToMultiByte(CP_UTF8, 0, data.name, -1,
+ dirp->d_first.d_name, DIRENT_NAME_MAX, 0, 0);
return dirp;
}
@@ -2442,7 +1986,7 @@ next:
LPDIRENT readdir(
LPDIR dirp
){
- struct _finddata_t data;
+ struct _wfinddata_t data;
if( dirp==NULL ) return NULL;
@@ -2455,66 +1999,20 @@ LPDIRENT readdir(
next:
- memset(&data, 0, sizeof(struct _finddata_t));
- if( _findnext(dirp->d_handle, &data)==-1 ) return NULL;
+ memset(&data, 0, sizeof(data));
+ if( _wfindnext(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';
-
+ WideCharToMultiByte(CP_UTF8, 0, data.name, -1,
+ dirp->d_next.d_name, DIRENT_NAME_MAX, 0, 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(
@@ -2845,13 +2343,23 @@ int sqlite3PcacheTraceDeactivate(void){
**
** This SQLite extension implements functions that compute SHA3 hashes
** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard.
-** Two SQL functions are implemented:
+** Three SQL functions are implemented:
**
** sha3(X,SIZE)
-** sha3_query(Y,SIZE)
+** sha3_agg(Y,SIZE)
+** sha3_query(Z,SIZE)
**
** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
-** X is NULL.
+** X is NULL. If inputs X is text, the UTF-8 rendering of that text is
+** used to compute the hash. If X is a BLOB, then the binary data of the
+** blob is used to compute the hash. If X is an integer or real number,
+** then that number if converted into UTF-8 text and the hash is computed
+** over the text.
+**
+** The sha3_agg(Y) function computes the SHA3 hash of all Y inputs. Since
+** order is important for the hash, it is recommended that the Y expression
+** by followed by an ORDER BY clause to guarantee that the inputs occur
+** in the desired order.
**
** The sha3_query(Y) function evaluates all queries in the SQL statements of Y
** and returns a hash of their results.
@@ -2859,6 +2367,68 @@ int sqlite3PcacheTraceDeactivate(void){
** 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.
+**
+** Because the sha3_agg() and sha3_query() functions compute a hash over
+** multiple values, the values are encode to use include type information.
+**
+** In sha3_agg(), the sequence of bytes that gets hashed for each input
+** Y depends on the datatype of Y:
+**
+** typeof(Y)='null' A single "N" is hashed. (One byte)
+**
+** typeof(Y)='integer' The data hash is the character "I" followed
+** by an 8-byte big-endian binary of the
+** 64-bit signed integer. (Nine bytes total.)
+**
+** typeof(Y)='real' The character "F" followed by an 8-byte
+** big-ending binary of the double. (Nine
+** bytes total.)
+**
+** typeof(Y)='text' The hash is over prefix "Tnnn:" followed
+** by the UTF8 encoding of the text. The "nnn"
+** in the prefix is the minimum-length decimal
+** representation of the octet_length of the text.
+** Notice the ":" at the end of the prefix, which
+** is needed to separate the prefix from the
+** content in cases where the content starts
+** with a digit.
+**
+** typeof(Y)='blob' The hash is taken over prefix "Bnnn:" followed
+** by the binary content of the blob. The "nnn"
+** in the prefix is the minimum-length decimal
+** representation of the byte-length of the blob.
+**
+** According to the rules above, all of the following SELECT statements
+** should return TRUE:
+**
+** SELECT sha3(1) = sha3('1');
+**
+** SELECT sha3('hello') = sha3(x'68656c6c6f');
+**
+** WITH a(x) AS (VALUES('xyzzy'))
+** SELECT sha3_agg(x) = sha3('T5:xyzzy') FROM a;
+**
+** WITH a(x) AS (VALUES(x'010203'))
+** SELECT sha3_agg(x) = sha3(x'42333a010203') FROM a;
+**
+** WITH a(x) AS (VALUES(0x123456))
+** SELECT sha3_agg(x) = sha3(x'490000000000123456') FROM a;
+**
+** WITH a(x) AS (VALUES(100.015625))
+** SELECT sha3_agg(x) = sha3(x'464059010000000000') FROM a;
+**
+** WITH a(x) AS (VALUES(NULL))
+** SELECT sha3_agg(x) = sha3('N') FROM a;
+**
+**
+** In sha3_query(), individual column values are encoded as with
+** sha3_agg(), but with the addition that a single "R" character is
+** inserted at the start of each row.
+**
+** Note that sha3_agg() hashes rows for which Y is NULL. Add a FILTER
+** clause if NULL rows should be excluded:
+**
+** SELECT sha3_agg(x ORDER BY rowid) FILTER(WHERE x NOT NULL) FROM t1;
*/
/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
@@ -2908,6 +2478,7 @@ struct SHA3Context {
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]. */
+ unsigned iSize; /* 224, 256, 358, or 512 */
};
/*
@@ -3237,6 +2808,7 @@ static void KeccakF1600Step(SHA3Context *p){
*/
static void SHA3Init(SHA3Context *p, int iSize){
memset(p, 0, sizeof(*p));
+ p->iSize = iSize;
if( iSize>=128 && iSize<=512 ){
p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
}else{
@@ -3381,6 +2953,60 @@ static void sha3_step_vformat(
}
/*
+** Update a SHA3Context using a single sqlite3_value.
+*/
+static void sha3UpdateFromValue(SHA3Context *p, sqlite3_value *pVal){
+ switch( sqlite3_value_type(pVal) ){
+ case SQLITE_NULL: {
+ SHA3Update(p, (const unsigned char*)"N",1);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ sqlite3_int64 v = sqlite3_value_int64(pVal);
+ memcpy(&u, &v, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'I';
+ SHA3Update(p, x, 9);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ double r = sqlite3_value_double(pVal);
+ memcpy(&u, &r, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'F';
+ SHA3Update(p,x,9);
+ break;
+ }
+ case SQLITE_TEXT: {
+ int n2 = sqlite3_value_bytes(pVal);
+ const unsigned char *z2 = sqlite3_value_text(pVal);
+ sha3_step_vformat(p,"T%d:",n2);
+ SHA3Update(p, z2, n2);
+ break;
+ }
+ case SQLITE_BLOB: {
+ int n2 = sqlite3_value_bytes(pVal);
+ const unsigned char *z2 = sqlite3_value_blob(pVal);
+ sha3_step_vformat(p,"B%d:",n2);
+ SHA3Update(p, z2, n2);
+ break;
+ }
+ }
+}
+
+/*
** Implementation of the sha3_query(SQL,SIZE) function.
**
** This function compiles and runs the SQL statement(s) given in the
@@ -3469,9 +3095,425 @@ static void sha3QueryFunc(
while( SQLITE_ROW==sqlite3_step(pStmt) ){
SHA3Update(&cx,(const unsigned char*)"R",1);
for(i=0; i<nCol; i++){
+ sha3UpdateFromValue(&cx, sqlite3_column_value(pStmt,i));
+ }
+ }
+ sqlite3_finalize(pStmt);
+ }
+ sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
+}
+
+/*
+** xStep function for sha3_agg().
+*/
+static void sha3AggStep(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ SHA3Context *p;
+ p = (SHA3Context*)sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( p->nRate==0 ){
+ int sz = 256;
+ if( argc==2 ){
+ sz = sqlite3_value_int(argv[1]);
+ if( sz!=224 && sz!=384 && sz!=512 ){
+ sz = 256;
+ }
+ }
+ SHA3Init(p, sz);
+ }
+ sha3UpdateFromValue(p, argv[0]);
+}
+
+
+/*
+** xFinal function for sha3_agg().
+*/
+static void sha3AggFinal(sqlite3_context *context){
+ SHA3Context *p;
+ p = (SHA3Context*)sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( p->iSize ){
+ sqlite3_result_blob(context, SHA3Final(p), p->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_agg", 1,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, 0, sha3AggStep, sha3AggFinal);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3_agg", 2,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, 0, sha3AggStep, sha3AggFinal);
+ }
+ 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/sha1.c ******************/
+/*
+** 2017-01-27
+**
+** 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 SHA1 hashes.
+** Two SQL functions are implemented:
+**
+** sha1(X)
+** sha1_query(Y)
+**
+** The sha1(X) function computes the SHA1 hash of the input X, or NULL if
+** X is NULL.
+**
+** The sha1_query(Y) function evalutes all queries in the SQL statements of Y
+** and returns a hash of their results.
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <stdarg.h>
+
+/******************************************************************************
+** The Hash Engine
+*/
+/* Context for the SHA1 hash */
+typedef struct SHA1Context SHA1Context;
+struct SHA1Context {
+ unsigned int state[5];
+ unsigned int count[2];
+ unsigned char buffer[64];
+};
+
+#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
+#define rol(x,k) SHA_ROT(x,k,32-(k))
+#define ror(x,k) SHA_ROT(x,32-(k),k)
+
+#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
+ |(rol(block[i],8)&0x00FF00FF))
+#define blk0be(i) block[i]
+#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
+ ^block[(i+2)&15]^block[i&15],1))
+
+/*
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ *
+ * Rl0() for little-endian and Rb0() for big-endian. Endianness is
+ * determined at run-time.
+ */
+#define Rl0(v,w,x,y,z,i) \
+ z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
+#define Rb0(v,w,x,y,z,i) \
+ z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
+#define R1(v,w,x,y,z,i) \
+ z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
+#define R2(v,w,x,y,z,i) \
+ z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
+#define R3(v,w,x,y,z,i) \
+ z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
+#define R4(v,w,x,y,z,i) \
+ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
+
+/*
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+static void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
+ unsigned int qq[5]; /* a, b, c, d, e; */
+ static int one = 1;
+ unsigned int block[16];
+ memcpy(block, buffer, 64);
+ memcpy(qq,state,5*sizeof(unsigned int));
+
+#define a qq[0]
+#define b qq[1]
+#define c qq[2]
+#define d qq[3]
+#define e qq[4]
+
+ /* Copy p->state[] to working vars */
+ /*
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ */
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ if( 1 == *(unsigned char*)&one ){
+ Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
+ Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
+ Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
+ Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
+ }else{
+ Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
+ Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
+ Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
+ Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
+ }
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+#undef a
+#undef b
+#undef c
+#undef d
+#undef e
+}
+
+
+/* Initialize a SHA1 context */
+static void hash_init(SHA1Context *p){
+ /* SHA1 initialization constants */
+ p->state[0] = 0x67452301;
+ p->state[1] = 0xEFCDAB89;
+ p->state[2] = 0x98BADCFE;
+ p->state[3] = 0x10325476;
+ p->state[4] = 0xC3D2E1F0;
+ p->count[0] = p->count[1] = 0;
+}
+
+/* Add new content to the SHA1 hash */
+static void hash_step(
+ SHA1Context *p, /* Add content to this context */
+ const unsigned char *data, /* Data to be added */
+ unsigned int len /* Number of bytes in data */
+){
+ unsigned int i, j;
+
+ j = p->count[0];
+ if( (p->count[0] += len << 3) < j ){
+ p->count[1] += (len>>29)+1;
+ }
+ j = (j >> 3) & 63;
+ if( (j + len) > 63 ){
+ (void)memcpy(&p->buffer[j], data, (i = 64-j));
+ SHA1Transform(p->state, p->buffer);
+ for(; i + 63 < len; i += 64){
+ SHA1Transform(p->state, &data[i]);
+ }
+ j = 0;
+ }else{
+ i = 0;
+ }
+ (void)memcpy(&p->buffer[j], &data[i], len - i);
+}
+
+/* Compute a string using sqlite3_vsnprintf() and hash it */
+static void hash_step_vformat(
+ SHA1Context *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);
+ hash_step(p, (unsigned char*)zBuf, n);
+}
+
+
+/* Add padding and compute the message digest. Render the
+** message digest as lower-case hexadecimal and put it into
+** zOut[]. zOut[] must be at least 41 bytes long. */
+static void hash_finish(
+ SHA1Context *p, /* The SHA1 context to finish and render */
+ char *zOut, /* Store hex or binary hash here */
+ int bAsBinary /* 1 for binary hash, 0 for hex hash */
+){
+ unsigned int i;
+ unsigned char finalcount[8];
+ unsigned char digest[20];
+ static const char zEncode[] = "0123456789abcdef";
+
+ for (i = 0; i < 8; i++){
+ finalcount[i] = (unsigned char)((p->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ hash_step(p, (const unsigned char *)"\200", 1);
+ while ((p->count[0] & 504) != 448){
+ hash_step(p, (const unsigned char *)"\0", 1);
+ }
+ hash_step(p, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++){
+ digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ if( bAsBinary ){
+ memcpy(zOut, digest, 20);
+ }else{
+ for(i=0; i<20; i++){
+ zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
+ zOut[i*2+1] = zEncode[digest[i] & 0xf];
+ }
+ zOut[i*2]= 0;
+ }
+}
+/* End of the hashing logic
+*****************************************************************************/
+
+/*
+** Implementation of the sha1(X) function.
+**
+** Return a lower-case hexadecimal rendering of the SHA1 hash of the
+** argument X. If X is a BLOB, it is hashed as is. For all other
+** types of input, X is converted into a UTF-8 string and the string
+** is hash without the trailing 0x00 terminator. The hash of a NULL
+** value is NULL.
+*/
+static void sha1Func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ SHA1Context cx;
+ int eType = sqlite3_value_type(argv[0]);
+ int nByte = sqlite3_value_bytes(argv[0]);
+ char zOut[44];
+
+ assert( argc==1 );
+ if( eType==SQLITE_NULL ) return;
+ hash_init(&cx);
+ if( eType==SQLITE_BLOB ){
+ hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
+ }else{
+ hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
+ }
+ if( sqlite3_user_data(context)!=0 ){
+ hash_finish(&cx, zOut, 1);
+ sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT);
+ }else{
+ hash_finish(&cx, zOut, 0);
+ sqlite3_result_blob(context, zOut, 40, SQLITE_TRANSIENT);
+ }
+}
+
+/*
+** Implementation of the sha1_query(SQL) function.
+**
+** This function compiles and runs the SQL statement(s) given in the
+** argument. The results are hashed using SHA1 and that hash is returned.
+**
+** The original SQL text is included as part of the hash.
+**
+** The hash is not just a concatenation of the outputs. Each query
+** is delimited and each row and value within the query is delimited,
+** with all values being marked with their datatypes.
+*/
+static void sha1QueryFunc(
+ 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;
+ SHA1Context cx;
+ char zOut[44];
+
+ assert( argc==1 );
+ if( zSql==0 ) return;
+ hash_init(&cx);
+ 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);
+ hash_step(&cx,(unsigned char*)z,n);
+
+ /* Compute a hash over the result of the query */
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ hash_step(&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);
+ hash_step(&cx, (const unsigned char*)"N",1);
break;
}
case SQLITE_INTEGER: {
@@ -3485,7 +3527,7 @@ static void sha3QueryFunc(
u >>= 8;
}
x[0] = 'I';
- SHA3Update(&cx, x, 9);
+ hash_step(&cx, x, 9);
break;
}
case SQLITE_FLOAT: {
@@ -3499,21 +3541,21 @@ static void sha3QueryFunc(
u >>= 8;
}
x[0] = 'F';
- SHA3Update(&cx,x,9);
+ hash_step(&cx,x,9);
break;
}
case SQLITE_TEXT: {
int n2 = sqlite3_column_bytes(pStmt, i);
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
- sha3_step_vformat(&cx,"T%d:",n2);
- SHA3Update(&cx, z2, n2);
+ hash_step_vformat(&cx,"T%d:",n2);
+ hash_step(&cx, z2, n2);
break;
}
case SQLITE_BLOB: {
int n2 = sqlite3_column_bytes(pStmt, i);
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
- sha3_step_vformat(&cx,"B%d:",n2);
- SHA3Update(&cx, z2, n2);
+ hash_step_vformat(&cx,"B%d:",n2);
+ hash_step(&cx, z2, n2);
break;
}
}
@@ -3521,43 +3563,40 @@ static void sha3QueryFunc(
}
sqlite3_finalize(pStmt);
}
- sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
+ hash_finish(&cx, zOut, 0);
+ sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
}
#ifdef _WIN32
#endif
-int sqlite3_shathree_init(
+int sqlite3_sha_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
+ static int one = 1;
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);
+ rc = sqlite3_create_function(db, "sha1", 1,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, sha1Func, 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);
+ rc = sqlite3_create_function(db, "sha1b", 1,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ (void*)&one, sha1Func, 0, 0);
}
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sha3_query", 2,
- SQLITE_UTF8 | SQLITE_DIRECTONLY,
- 0, sha3QueryFunc, 0, 0);
+ rc = sqlite3_create_function(db, "sha1_query", 1,
+ SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
+ sha1QueryFunc, 0, 0);
}
return rc;
}
-/************************* End ../ext/misc/shathree.c ********************/
+/************************* End ../ext/misc/sha1.c ********************/
/************************* Begin ../ext/misc/uint.c ******************/
/*
** 2020-04-14
@@ -3577,7 +3616,7 @@ int sqlite3_shathree_init(
** 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
+** they do not mess of the magnitude comparison of embedded
** strings of digits. "x00123y" is equal to "x123y".
**
** * Only unsigned integers are recognized. Plus and minus
@@ -3683,6 +3722,9 @@ SQLITE_EXTENSION_INIT1
# define UNUSED_PARAMETER(X) (void)(X)
#endif
+#ifndef IsSpace
+#define IsSpace(X) isspace((unsigned char)X)
+#endif
/* A decimal object */
typedef struct Decimal Decimal;
@@ -3732,7 +3774,7 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
p->nFrac = 0;
p->a = sqlite3_malloc64( n+1 );
if( p->a==0 ) goto new_from_text_failed;
- for(i=0; isspace(zIn[i]); i++){}
+ for(i=0; IsSpace(zIn[i]); i++){}
if( zIn[i]=='-' ){
p->sign = 1;
i++;
@@ -4387,7 +4429,7 @@ static void decimalSubFunc(
decimal_free(pB);
}
-/* Aggregate funcion: decimal_sum(X)
+/* Aggregate function: decimal_sum(X)
**
** Works like sum() except that it uses decimal arithmetic for unlimited
** precision.
@@ -4540,6 +4582,512 @@ int sqlite3_decimal_init(
}
/************************* End ../ext/misc/decimal.c ********************/
+/************************* Begin ../ext/misc/percentile.c ******************/
+/*
+** 2013-05-28
+**
+** 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 the percentile(Y,P) SQL function
+** and similar as described below:
+**
+** (1) The percentile(Y,P) function is an aggregate function taking
+** exactly two arguments.
+**
+** (2) If the P argument to percentile(Y,P) is not the same for every
+** row in the aggregate then an error is thrown. The word "same"
+** in the previous sentence means that the value differ by less
+** than 0.001.
+**
+** (3) If the P argument to percentile(Y,P) evaluates to anything other
+** than a number in the range of 0.0 to 100.0 inclusive then an
+** error is thrown.
+**
+** (4) If any Y argument to percentile(Y,P) evaluates to a value that
+** is not NULL and is not numeric then an error is thrown.
+**
+** (5) If any Y argument to percentile(Y,P) evaluates to plus or minus
+** infinity then an error is thrown. (SQLite always interprets NaN
+** values as NULL.)
+**
+** (6) Both Y and P in percentile(Y,P) can be arbitrary expressions,
+** including CASE WHEN expressions.
+**
+** (7) The percentile(Y,P) aggregate is able to handle inputs of at least
+** one million (1,000,000) rows.
+**
+** (8) If there are no non-NULL values for Y, then percentile(Y,P)
+** returns NULL.
+**
+** (9) If there is exactly one non-NULL value for Y, the percentile(Y,P)
+** returns the one Y value.
+**
+** (10) If there N non-NULL values of Y where N is two or more and
+** the Y values are ordered from least to greatest and a graph is
+** drawn from 0 to N-1 such that the height of the graph at J is
+** the J-th Y value and such that straight lines are drawn between
+** adjacent Y values, then the percentile(Y,P) function returns
+** the height of the graph at P*(N-1)/100.
+**
+** (11) The percentile(Y,P) function always returns either a floating
+** point number or NULL.
+**
+** (12) The percentile(Y,P) is implemented as a single C99 source-code
+** file that compiles into a shared-library or DLL that can be loaded
+** into SQLite using the sqlite3_load_extension() interface.
+**
+** (13) A separate median(Y) function is the equivalent percentile(Y,50).
+**
+** (14) A separate percentile_cont(Y,P) function is equivalent to
+** percentile(Y,P/100.0). In other words, the fraction value in
+** the second argument is in the range of 0 to 1 instead of 0 to 100.
+**
+** (15) A separate percentile_disc(Y,P) function is like
+** percentile_cont(Y,P) except that instead of returning the weighted
+** average of the nearest two input values, it returns the next lower
+** value. So the percentile_disc(Y,P) will always return a value
+** that was one of the inputs.
+**
+** (16) All of median(), percentile(Y,P), percentile_cont(Y,P) and
+** percentile_disc(Y,P) can be used as window functions.
+**
+** Differences from standard SQL:
+**
+** * The percentile_cont(X,P) function is equivalent to the following in
+** standard SQL:
+**
+** (percentile_cont(P) WITHIN GROUP (ORDER BY X))
+**
+** The SQLite syntax is much more compact. The standard SQL syntax
+** is also supported if SQLite is compiled with the
+** -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES option.
+**
+** * No median(X) function exists in the SQL standard. App developers
+** are expected to write "percentile_cont(0.5)WITHIN GROUP(ORDER BY X)".
+**
+** * No percentile(Y,P) function exists in the SQL standard. Instead of
+** percential(Y,P), developers must write this:
+** "percentile_cont(P/100.0) WITHIN GROUP (ORDER BY Y)". Note that
+** the fraction parameter to percentile() goes from 0 to 100 whereas
+** the fraction parameter in SQL standard percentile_cont() goes from
+** 0 to 1.
+**
+** Implementation notes as of 2024-08-31:
+**
+** * The regular aggregate-function versions of these routines work
+** by accumulating all values in an array of doubles, then sorting
+** that array using quicksort before computing the answer. Thus
+** the runtime is O(NlogN) where N is the number of rows of input.
+**
+** * For the window-function versions of these routines, the array of
+** inputs is sorted as soon as the first value is computed. Thereafter,
+** the array is kept in sorted order using an insert-sort. This
+** results in O(N*K) performance where K is the size of the window.
+** One can imagine alternative implementations that give O(N*logN*logK)
+** performance, but they require more complex logic and data structures.
+** The developers have elected to keep the asymptotically slower
+** algorithm for now, for simplicity, under the theory that window
+** functions are seldom used and when they are, the window size K is
+** often small. The developers might revisit that decision later,
+** should the need arise.
+*/
+#if defined(SQLITE3_H)
+ /* no-op */
+#elif defined(SQLITE_STATIC_PERCENTILE)
+/* # include "sqlite3.h" */
+#else
+/* # include "sqlite3ext.h" */
+ SQLITE_EXTENSION_INIT1
+#endif
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* The following object is the group context for a single percentile()
+** aggregate. Remember all input Y values until the very end.
+** Those values are accumulated in the Percentile.a[] array.
+*/
+typedef struct Percentile Percentile;
+struct Percentile {
+ unsigned nAlloc; /* Number of slots allocated for a[] */
+ unsigned nUsed; /* Number of slots actually used in a[] */
+ char bSorted; /* True if a[] is already in sorted order */
+ char bKeepSorted; /* True if advantageous to keep a[] sorted */
+ char bPctValid; /* True if rPct is valid */
+ double rPct; /* Fraction. 0.0 to 1.0 */
+ double *a; /* Array of Y values */
+};
+
+/* Details of each function in the percentile family */
+typedef struct PercentileFunc PercentileFunc;
+struct PercentileFunc {
+ const char *zName; /* Function name */
+ char nArg; /* Number of arguments */
+ char mxFrac; /* Maximum value of the "fraction" input */
+ char bDiscrete; /* True for percentile_disc() */
+};
+static const PercentileFunc aPercentFunc[] = {
+ { "median", 1, 1, 0 },
+ { "percentile", 2, 100, 0 },
+ { "percentile_cont", 2, 1, 0 },
+ { "percentile_disc", 2, 1, 1 },
+};
+
+/*
+** Return TRUE if the input floating-point number is an infinity.
+*/
+static int percentIsInfinity(double r){
+ sqlite3_uint64 u;
+ assert( sizeof(u)==sizeof(r) );
+ memcpy(&u, &r, sizeof(u));
+ return ((u>>52)&0x7ff)==0x7ff;
+}
+
+/*
+** Return TRUE if two doubles differ by 0.001 or less.
+*/
+static int percentSameValue(double a, double b){
+ a -= b;
+ return a>=-0.001 && a<=0.001;
+}
+
+/*
+** Search p (which must have p->bSorted) looking for an entry with
+** value y. Return the index of that entry.
+**
+** If bExact is true, return -1 if the entry is not found.
+**
+** If bExact is false, return the index at which a new entry with
+** value y should be insert in order to keep the values in sorted
+** order. The smallest return value in this case will be 0, and
+** the largest return value will be p->nUsed.
+*/
+static int percentBinarySearch(Percentile *p, double y, int bExact){
+ int iFirst = 0; /* First element of search range */
+ int iLast = p->nUsed - 1; /* Last element of search range */
+ while( iLast>=iFirst ){
+ int iMid = (iFirst+iLast)/2;
+ double x = p->a[iMid];
+ if( x<y ){
+ iFirst = iMid + 1;
+ }else if( x>y ){
+ iLast = iMid - 1;
+ }else{
+ return iMid;
+ }
+ }
+ if( bExact ) return -1;
+ return iFirst;
+}
+
+/*
+** Generate an error for a percentile function.
+**
+** The error format string must have exactly one occurrence of "%%s()"
+** (with two '%' characters). That substring will be replaced by the name
+** of the function.
+*/
+static void percentError(sqlite3_context *pCtx, const char *zFormat, ...){
+ PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
+ char *zMsg1;
+ char *zMsg2;
+ va_list ap;
+
+ va_start(ap, zFormat);
+ zMsg1 = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ zMsg2 = zMsg1 ? sqlite3_mprintf(zMsg1, pFunc->zName) : 0;
+ sqlite3_result_error(pCtx, zMsg2, -1);
+ sqlite3_free(zMsg1);
+ sqlite3_free(zMsg2);
+}
+
+/*
+** The "step" function for percentile(Y,P) is called once for each
+** input row.
+*/
+static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){
+ Percentile *p;
+ double rPct;
+ int eType;
+ double y;
+ assert( argc==2 || argc==1 );
+
+ if( argc==1 ){
+ /* Requirement 13: median(Y) is the same as percentile(Y,50). */
+ rPct = 0.5;
+ }else{
+ /* Requirement 3: P must be a number between 0 and 100 */
+ PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
+ eType = sqlite3_value_numeric_type(argv[1]);
+ rPct = sqlite3_value_double(argv[1])/(double)pFunc->mxFrac;
+ if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
+ || rPct<0.0 || rPct>1.0
+ ){
+ percentError(pCtx, "the fraction argument to %%s()"
+ " is not between 0.0 and %.1f",
+ (double)pFunc->mxFrac);
+ return;
+ }
+ }
+
+ /* Allocate the session context. */
+ p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p==0 ) return;
+
+ /* Remember the P value. Throw an error if the P value is different
+ ** from any prior row, per Requirement (2). */
+ if( !p->bPctValid ){
+ p->rPct = rPct;
+ p->bPctValid = 1;
+ }else if( !percentSameValue(p->rPct,rPct) ){
+ percentError(pCtx, "the fraction argument to %%s()"
+ " is not the same for all input rows");
+ return;
+ }
+
+ /* Ignore rows for which Y is NULL */
+ eType = sqlite3_value_type(argv[0]);
+ if( eType==SQLITE_NULL ) return;
+
+ /* If not NULL, then Y must be numeric. Otherwise throw an error.
+ ** Requirement 4 */
+ if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
+ percentError(pCtx, "input to %%s() is not numeric");
+ return;
+ }
+
+ /* Throw an error if the Y value is infinity or NaN */
+ y = sqlite3_value_double(argv[0]);
+ if( percentIsInfinity(y) ){
+ percentError(pCtx, "Inf input to %%s()");
+ return;
+ }
+
+ /* Allocate and store the Y */
+ if( p->nUsed>=p->nAlloc ){
+ unsigned n = p->nAlloc*2 + 250;
+ double *a = sqlite3_realloc64(p->a, sizeof(double)*n);
+ if( a==0 ){
+ sqlite3_free(p->a);
+ memset(p, 0, sizeof(*p));
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ p->nAlloc = n;
+ p->a = a;
+ }
+ if( p->nUsed==0 ){
+ p->a[p->nUsed++] = y;
+ p->bSorted = 1;
+ }else if( !p->bSorted || y>=p->a[p->nUsed-1] ){
+ p->a[p->nUsed++] = y;
+ }else if( p->bKeepSorted ){
+ int i;
+ i = percentBinarySearch(p, y, 0);
+ if( i<(int)p->nUsed ){
+ memmove(&p->a[i+1], &p->a[i], (p->nUsed-i)*sizeof(p->a[0]));
+ }
+ p->a[i] = y;
+ p->nUsed++;
+ }else{
+ p->a[p->nUsed++] = y;
+ p->bSorted = 0;
+ }
+}
+
+/*
+** Interchange two doubles.
+*/
+#define SWAP_DOUBLE(X,Y) {double ttt=(X);(X)=(Y);(Y)=ttt;}
+
+/*
+** Sort an array of doubles.
+**
+** Algorithm: quicksort
+**
+** This is implemented separately rather than using the qsort() routine
+** from the standard library because:
+**
+** (1) To avoid a dependency on qsort()
+** (2) To avoid the function call to the comparison routine for each
+** comparison.
+*/
+static void percentSort(double *a, unsigned int n){
+ int iLt; /* Entries before a[iLt] are less than rPivot */
+ int iGt; /* Entries at or after a[iGt] are greater than rPivot */
+ int i; /* Loop counter */
+ double rPivot; /* The pivot value */
+
+ assert( n>=2 );
+ if( a[0]>a[n-1] ){
+ SWAP_DOUBLE(a[0],a[n-1])
+ }
+ if( n==2 ) return;
+ iGt = n-1;
+ i = n/2;
+ if( a[0]>a[i] ){
+ SWAP_DOUBLE(a[0],a[i])
+ }else if( a[i]>a[iGt] ){
+ SWAP_DOUBLE(a[i],a[iGt])
+ }
+ if( n==3 ) return;
+ rPivot = a[i];
+ iLt = i = 1;
+ do{
+ if( a[i]<rPivot ){
+ if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt])
+ iLt++;
+ i++;
+ }else if( a[i]>rPivot ){
+ do{
+ iGt--;
+ }while( iGt>i && a[iGt]>rPivot );
+ SWAP_DOUBLE(a[i],a[iGt])
+ }else{
+ i++;
+ }
+ }while( i<iGt );
+ if( iLt>=2 ) percentSort(a, iLt);
+ if( n-iGt>=2 ) percentSort(a+iGt, n-iGt);
+
+/* Uncomment for testing */
+#if 0
+ for(i=0; i<n-1; i++){
+ assert( a[i]<=a[i+1] );
+ }
+#endif
+}
+
+
+/*
+** The "inverse" function for percentile(Y,P) is called to remove a
+** row that was previously inserted by "step".
+*/
+static void percentInverse(sqlite3_context *pCtx,int argc,sqlite3_value **argv){
+ Percentile *p;
+ int eType;
+ double y;
+ int i;
+ assert( argc==2 || argc==1 );
+
+ /* Allocate the session context. */
+ p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ assert( p!=0 );
+
+ /* Ignore rows for which Y is NULL */
+ eType = sqlite3_value_type(argv[0]);
+ if( eType==SQLITE_NULL ) return;
+
+ /* If not NULL, then Y must be numeric. Otherwise throw an error.
+ ** Requirement 4 */
+ if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
+ return;
+ }
+
+ /* Ignore the Y value if it is infinity or NaN */
+ y = sqlite3_value_double(argv[0]);
+ if( percentIsInfinity(y) ){
+ return;
+ }
+ if( p->bSorted==0 ){
+ assert( p->nUsed>1 );
+ percentSort(p->a, p->nUsed);
+ p->bSorted = 1;
+ }
+ p->bKeepSorted = 1;
+
+ /* Find and remove the row */
+ i = percentBinarySearch(p, y, 1);
+ if( i>=0 ){
+ p->nUsed--;
+ if( i<(int)p->nUsed ){
+ memmove(&p->a[i], &p->a[i+1], (p->nUsed - i)*sizeof(p->a[0]));
+ }
+ }
+}
+
+/*
+** Compute the final output of percentile(). Clean up all allocated
+** memory if and only if bIsFinal is true.
+*/
+static void percentCompute(sqlite3_context *pCtx, int bIsFinal){
+ Percentile *p;
+ PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
+ unsigned i1, i2;
+ double v1, v2;
+ double ix, vx;
+ p = (Percentile*)sqlite3_aggregate_context(pCtx, 0);
+ if( p==0 ) return;
+ if( p->a==0 ) return;
+ if( p->nUsed ){
+ if( p->bSorted==0 ){
+ assert( p->nUsed>1 );
+ percentSort(p->a, p->nUsed);
+ p->bSorted = 1;
+ }
+ ix = p->rPct*(p->nUsed-1);
+ i1 = (unsigned)ix;
+ if( pFunc->bDiscrete ){
+ vx = p->a[i1];
+ }else{
+ i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1;
+ v1 = p->a[i1];
+ v2 = p->a[i2];
+ vx = v1 + (v2-v1)*(ix-i1);
+ }
+ sqlite3_result_double(pCtx, vx);
+ }
+ if( bIsFinal ){
+ sqlite3_free(p->a);
+ memset(p, 0, sizeof(*p));
+ }else{
+ p->bKeepSorted = 1;
+ }
+}
+static void percentFinal(sqlite3_context *pCtx){
+ percentCompute(pCtx, 1);
+}
+static void percentValue(sqlite3_context *pCtx){
+ percentCompute(pCtx, 0);
+}
+
+#if defined(_WIN32) && !defined(SQLITE3_H) && !defined(SQLITE_STATIC_PERCENTILE)
+
+#endif
+int sqlite3_percentile_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ unsigned int i;
+#ifdef SQLITE3EXT_H
+ SQLITE_EXTENSION_INIT2(pApi);
+#else
+ (void)pApi; /* Unused parameter */
+#endif
+ (void)pzErrMsg; /* Unused parameter */
+ for(i=0; i<sizeof(aPercentFunc)/sizeof(aPercentFunc[0]); i++){
+ rc = sqlite3_create_window_function(db,
+ aPercentFunc[i].zName,
+ aPercentFunc[i].nArg,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_SELFORDER1,
+ (void*)&aPercentFunc[i],
+ percentStep, percentFinal, percentValue, percentInverse, 0);
+ if( rc ) break;
+ }
+ return rc;
+}
+
+/************************* End ../ext/misc/percentile.c ********************/
#undef sqlite3_base_init
#define sqlite3_base_init sqlite3_base64_init
/************************* Begin ../ext/misc/base64.c ******************/
@@ -4720,15 +5268,15 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
case ND:
/* Treat dark non-digits as pad, but they terminate decode too. */
ncIn = 0;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case WS:
/* Treat whitespace as pad and terminate this group.*/
nti = nac;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case PC:
bdp = 0;
--nbo;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
default: /* bdp is the digit value. */
qv = qv<<6 | bdp;
break;
@@ -4737,10 +5285,13 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
switch( nbo ){
case 3:
pOut[2] = (qv) & 0xff;
+ deliberate_fall_through; /* FALLTHRU */
case 2:
pOut[1] = (qv>>8) & 0xff;
+ deliberate_fall_through; /* FALLTHRU */
case 1:
pOut[0] = (qv>>16) & 0xff;
+ break;
}
pOut += nbo;
}
@@ -5075,12 +5626,16 @@ static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){
switch( nbo ){
case 4:
*pOut++ = (qv >> 24)&0xff;
+ /* FALLTHRU */
case 3:
*pOut++ = (qv >> 16)&0xff;
+ /* FALLTHRU */
case 2:
*pOut++ = (qv >> 8)&0xff;
+ /* FALLTHRU */
case 1:
*pOut++ = qv&0xff;
+ /* FALLTHRU */
case 0:
break;
}
@@ -5375,7 +5930,7 @@ int main(int na, char *av[]){
** WITH c(name,bin) AS (VALUES
** ('minimum positive value', x'0000000000000001'),
** ('maximum subnormal value', x'000fffffffffffff'),
-** ('mininum positive nornal value', x'0010000000000000'),
+** ('minimum positive normal 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);
@@ -5683,8 +6238,7 @@ int sqlite3_ieee_init(
** step HIDDEN
** );
**
-** The virtual table also has a rowid, logically equivalent to n+1 where
-** "n" is the ascending integer in the aforesaid production definition.
+** The virtual table also has a rowid which is an alias for the value.
**
** Function arguments in queries against this virtual table are translated
** into equality constraints against successive hidden columns. In other
@@ -5713,12 +6267,33 @@ int sqlite3_ieee_init(
** and a very large cost if either start or stop are unavailable. This
** encourages the query planner to order joins such that the bounds of the
** series are well-defined.
+**
+** Update on 2024-08-22:
+** xBestIndex now also looks for equality and inequality constraints against
+** the value column and uses those constraints as additional bounds against
+** the sequence range. Thus, a query like this:
+**
+** SELECT value FROM generate_series($SA,$EA)
+** WHERE value BETWEEN $SB AND $EB;
+**
+** Is logically the same as:
+**
+** SELECT value FROM generate_series(max($SA,$SB),min($EA,$EB));
+**
+** Constraints on the value column can server as substitutes for constraints
+** on the hidden start and stop columns. So, the following two queries
+** are equivalent:
+**
+** SELECT value FROM generate_series($S,$E);
+** SELECT value FROM generate_series WHERE value BETWEEN $S and $E;
+**
*/
/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <limits.h>
+#include <math.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
@@ -5742,7 +6317,7 @@ static sqlite3_int64 genSeqMember(
smBase += (mxI64 - mxI64/2) * smStep;
}
/* Under UBSAN (or on 1's complement machines), must do this last term
- * in steps to avoid the dreaded (and harmless) signed multiply overlow. */
+ * in steps to avoid the dreaded (and harmless) signed multiply overflow. */
if( ix>=2 ){
sqlite3_int64 ix2 = (sqlite3_int64)ix/2;
smBase += ix2*smStep;
@@ -5754,8 +6329,10 @@ static sqlite3_int64 genSeqMember(
/* typedef unsigned char u8; */
typedef struct SequenceSpec {
- sqlite3_int64 iBase; /* Starting value ("start") */
- sqlite3_int64 iTerm; /* Given terminal value ("stop") */
+ sqlite3_int64 iOBase; /* Original starting value ("start") */
+ sqlite3_int64 iOTerm; /* Original terminal value ("stop") */
+ sqlite3_int64 iBase; /* Starting value to actually use */
+ sqlite3_int64 iTerm; /* Terminal value to actually use */
sqlite3_int64 iStep; /* Increment ("step") */
sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
@@ -5877,6 +6454,7 @@ static int seriesConnect(
int rc;
/* Column numbers */
+#define SERIES_COLUMN_ROWID (-1)
#define SERIES_COLUMN_VALUE 0
#define SERIES_COLUMN_START 1
#define SERIES_COLUMN_STOP 2
@@ -5948,9 +6526,9 @@ static int seriesColumn(
series_cursor *pCur = (series_cursor*)cur;
sqlite3_int64 x = 0;
switch( i ){
- case SERIES_COLUMN_START: x = pCur->ss.iBase; break;
- case SERIES_COLUMN_STOP: x = pCur->ss.iTerm; break;
- case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
+ case SERIES_COLUMN_START: x = pCur->ss.iOBase; break;
+ case SERIES_COLUMN_STOP: x = pCur->ss.iOTerm; break;
+ case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
default: x = pCur->ss.iValueNow; break;
}
sqlite3_result_int64(ctx, x);
@@ -5958,17 +6536,17 @@ static int seriesColumn(
}
#ifndef LARGEST_UINT64
+#define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
#define LARGEST_UINT64 (0xffffffff|(((sqlite3_uint64)0xffffffff)<<32))
+#define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
#endif
/*
-** Return the rowid for the current row, logically equivalent to n+1 where
-** "n" is the ascending integer in the aforesaid production definition.
+** The rowid is the same as the value.
*/
static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
series_cursor *pCur = (series_cursor*)cur;
- sqlite3_uint64 n = pCur->ss.uSeqIndexNow;
- *pRowid = (sqlite3_int64)((n<LARGEST_UINT64)? n+1 : 0);
+ *pRowid = pCur->ss.iValueNow;
return SQLITE_OK;
}
@@ -5999,13 +6577,18 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
** parameter. (idxStr is not used in this implementation.) idxNum
** is a bitmask showing which constraints are available:
**
-** 0x01: start=VALUE
-** 0x02: stop=VALUE
-** 0x04: step=VALUE
-** 0x08: descending order
-** 0x10: ascending order
-** 0x20: LIMIT VALUE
-** 0x40: OFFSET VALUE
+** 0x0001: start=VALUE
+** 0x0002: stop=VALUE
+** 0x0004: step=VALUE
+** 0x0008: descending order
+** 0x0010: ascending order
+** 0x0020: LIMIT VALUE
+** 0x0040: OFFSET VALUE
+** 0x0080: value=VALUE
+** 0x0100: value>=VALUE
+** 0x0200: value>VALUE
+** 0x1000: value<=VALUE
+** 0x2000: value<VALUE
**
** This routine should initialize the cursor and position it so that it
** is pointing at the first row, or pointing off the end of the table
@@ -6018,6 +6601,12 @@ static int seriesFilter(
){
series_cursor *pCur = (series_cursor *)pVtabCursor;
int i = 0;
+ int returnNoRows = 0;
+ sqlite3_int64 iMin = SMALLEST_INT64;
+ sqlite3_int64 iMax = LARGEST_INT64;
+ sqlite3_int64 iLimit = 0;
+ sqlite3_int64 iOffset = 0;
+
(void)idxStrUnused;
if( idxNum & 0x01 ){
pCur->ss.iBase = sqlite3_value_int64(argv[i++]);
@@ -6039,16 +6628,123 @@ static int seriesFilter(
}else{
pCur->ss.iStep = 1;
}
+
+ /* If there are constraints on the value column but there are
+ ** no constraints on the start, stop, and step columns, then
+ ** initialize the default range to be the entire range of 64-bit signed
+ ** integers. This range will contracted by the value column constraints
+ ** further below.
+ */
+ if( (idxNum & 0x05)==0 && (idxNum & 0x0380)!=0 ){
+ pCur->ss.iBase = SMALLEST_INT64;
+ }
+ if( (idxNum & 0x06)==0 && (idxNum & 0x3080)!=0 ){
+ pCur->ss.iTerm = LARGEST_INT64;
+ }
+ pCur->ss.iOBase = pCur->ss.iBase;
+ pCur->ss.iOTerm = pCur->ss.iTerm;
+
+ /* Extract the LIMIT and OFFSET values, but do not apply them yet.
+ ** The range must first be constrained by the limits on value.
+ */
if( idxNum & 0x20 ){
- sqlite3_int64 iLimit = sqlite3_value_int64(argv[i++]);
- sqlite3_int64 iTerm;
+ iLimit = sqlite3_value_int64(argv[i++]);
if( idxNum & 0x40 ){
- sqlite3_int64 iOffset = sqlite3_value_int64(argv[i++]);
- if( iOffset>0 ){
- pCur->ss.iBase += pCur->ss.iStep*iOffset;
+ iOffset = sqlite3_value_int64(argv[i++]);
+ }
+ }
+
+ if( idxNum & 0x3380 ){
+ /* Extract the maximum range of output values determined by
+ ** constraints on the "value" column.
+ */
+ if( idxNum & 0x0080 ){
+ if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
+ double r = sqlite3_value_double(argv[i++]);
+ if( r==ceil(r) ){
+ iMin = iMax = (sqlite3_int64)r;
+ }else{
+ returnNoRows = 1;
+ }
+ }else{
+ iMin = iMax = sqlite3_value_int64(argv[i++]);
+ }
+ }else{
+ if( idxNum & 0x0300 ){
+ if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
+ double r = sqlite3_value_double(argv[i++]);
+ if( idxNum & 0x0200 && r==ceil(r) ){
+ iMin = (sqlite3_int64)ceil(r+1.0);
+ }else{
+ iMin = (sqlite3_int64)ceil(r);
+ }
+ }else{
+ iMin = sqlite3_value_int64(argv[i++]);
+ if( idxNum & 0x0200 ){
+ if( iMin==LARGEST_INT64 ){
+ returnNoRows = 1;
+ }else{
+ iMin++;
+ }
+ }
+ }
}
+ if( idxNum & 0x3000 ){
+ if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
+ double r = sqlite3_value_double(argv[i++]);
+ if( (idxNum & 0x2000)!=0 && r==floor(r) ){
+ iMax = (sqlite3_int64)(r-1.0);
+ }else{
+ iMax = (sqlite3_int64)floor(r);
+ }
+ }else{
+ iMax = sqlite3_value_int64(argv[i++]);
+ if( idxNum & 0x2000 ){
+ if( iMax==SMALLEST_INT64 ){
+ returnNoRows = 1;
+ }else{
+ iMax--;
+ }
+ }
+ }
+ }
+ if( iMin>iMax ){
+ returnNoRows = 1;
+ }
+ }
+
+ /* Try to reduce the range of values to be generated based on
+ ** constraints on the "value" column.
+ */
+ if( pCur->ss.iStep>0 ){
+ sqlite3_int64 szStep = pCur->ss.iStep;
+ if( pCur->ss.iBase<iMin ){
+ sqlite3_uint64 d = iMin - pCur->ss.iBase;
+ pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
+ }
+ if( pCur->ss.iTerm>iMax ){
+ pCur->ss.iTerm = iMax;
+ }
+ }else{
+ sqlite3_int64 szStep = -pCur->ss.iStep;
+ assert( szStep>0 );
+ if( pCur->ss.iBase>iMax ){
+ sqlite3_uint64 d = pCur->ss.iBase - iMax;
+ pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep;
+ }
+ if( pCur->ss.iTerm<iMin ){
+ pCur->ss.iTerm = iMin;
+ }
+ }
+ }
+
+ /* Apply LIMIT and OFFSET constraints, if any */
+ if( idxNum & 0x20 ){
+ if( iOffset>0 ){
+ pCur->ss.iBase += pCur->ss.iStep*iOffset;
}
if( iLimit>=0 ){
+ sqlite3_int64 iTerm;
iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep;
if( pCur->ss.iStep<0 ){
if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
@@ -6057,16 +6753,21 @@ static int seriesFilter(
}
}
}
+
+
for(i=0; i<argc; i++){
if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
/* If any of the constraints have a NULL value, then return no rows.
- ** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
- pCur->ss.iBase = 1;
- pCur->ss.iTerm = 0;
- pCur->ss.iStep = 1;
+ ** See ticket https://sqlite.org/src/info/fac496b61722daf2 */
+ returnNoRows = 1;
break;
}
}
+ if( returnNoRows ){
+ pCur->ss.iBase = 1;
+ pCur->ss.iTerm = 0;
+ pCur->ss.iStep = 1;
+ }
if( idxNum & 0x08 ){
pCur->ss.isReversing = pCur->ss.iStep > 0;
}else{
@@ -6087,13 +6788,35 @@ static int seriesFilter(
**
** The query plan is represented by bits in idxNum:
**
-** 0x01 start = $value -- constraint exists
-** 0x02 stop = $value -- constraint exists
-** 0x04 step = $value -- constraint exists
-** 0x08 output is in descending order
-** 0x10 output is in ascending order
-** 0x20 LIMIT $value -- constraint exists
-** 0x40 OFFSET $value -- constraint exists
+** 0x0001 start = $num
+** 0x0002 stop = $num
+** 0x0004 step = $num
+** 0x0008 output is in descending order
+** 0x0010 output is in ascending order
+** 0x0020 LIMIT $num
+** 0x0040 OFFSET $num
+** 0x0080 value = $num
+** 0x0100 value >= $num
+** 0x0200 value > $num
+** 0x1000 value <= $num
+** 0x2000 value < $num
+**
+** Only one of 0x0100 or 0x0200 will be returned. Similarly, only
+** one of 0x1000 or 0x2000 will be returned. If the 0x0080 is set, then
+** none of the 0xff00 bits will be set.
+**
+** The order of parameters passed to xFilter is as follows:
+**
+** * The argument to start= if bit 0x0001 is in the idxNum mask
+** * The argument to stop= if bit 0x0002 is in the idxNum mask
+** * The argument to step= if bit 0x0004 is in the idxNum mask
+** * The argument to LIMIT if bit 0x0020 is in the idxNum mask
+** * The argument to OFFSET if bit 0x0040 is in the idxNum mask
+** * The argument to value=, or value>= or value> if any of
+** bits 0x0380 are in the idxNum mask
+** * The argument to value<= or value< if either of bits 0x3000
+** are in the mask
+**
*/
static int seriesBestIndex(
sqlite3_vtab *pVTab,
@@ -6106,7 +6829,9 @@ static int seriesBestIndex(
#endif
int unusableMask = 0; /* Mask of unusable constraints */
int nArg = 0; /* Number of arguments that seriesFilter() expects */
- int aIdx[5]; /* Constraints on start, stop, step, LIMIT, OFFSET */
+ int aIdx[7]; /* Constraints on start, stop, step, LIMIT, OFFSET,
+ ** and value. aIdx[5] covers value=, value>=, and
+ ** value>, aIdx[6] covers value<= and value< */
const struct sqlite3_index_constraint *pConstraint;
/* This implementation assumes that the start, stop, and step columns
@@ -6114,7 +6839,7 @@ static int seriesBestIndex(
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
- aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = -1;
+ aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = aIdx[5] = aIdx[6] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
int iCol; /* 0 for start, 1 for stop, 2 for step */
@@ -6135,7 +6860,61 @@ static int seriesBestIndex(
}
continue;
}
- if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
+ if( pConstraint->iColumn<SERIES_COLUMN_START ){
+ if( (pConstraint->iColumn==SERIES_COLUMN_VALUE ||
+ pConstraint->iColumn==SERIES_COLUMN_ROWID)
+ && pConstraint->usable
+ ){
+ switch( op ){
+ case SQLITE_INDEX_CONSTRAINT_EQ:
+ case SQLITE_INDEX_CONSTRAINT_IS: {
+ idxNum |= 0x0080;
+ idxNum &= ~0x3300;
+ aIdx[5] = i;
+ aIdx[6] = -1;
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
+ bStartSeen = 1;
+#endif
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_GE: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x0100;
+ idxNum &= ~0x0200;
+ aIdx[5] = i;
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
+ bStartSeen = 1;
+#endif
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_GT: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x0200;
+ idxNum &= ~0x0100;
+ aIdx[5] = i;
+#ifndef ZERO_ARGUMENT_GENERATE_SERIES
+ bStartSeen = 1;
+#endif
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_LE: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x1000;
+ idxNum &= ~0x2000;
+ aIdx[6] = i;
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_LT: {
+ if( idxNum & 0x0080 ) break;
+ idxNum |= 0x2000;
+ idxNum &= ~0x1000;
+ aIdx[6] = i;
+ break;
+ }
+ }
+ }
+ continue;
+ }
iCol = pConstraint->iColumn - SERIES_COLUMN_START;
assert( iCol>=0 && iCol<=2 );
iMask = 1 << iCol;
@@ -6157,7 +6936,7 @@ static int seriesBestIndex(
idxNum &= ~0x60;
aIdx[4] = 0;
}
- for(i=0; i<5; i++){
+ for(i=0; i<7; i++){
if( (j = aIdx[i])>=0 ){
pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
pIdxInfo->aConstraintUsage[j].omit =
@@ -6205,6 +6984,9 @@ static int seriesBestIndex(
pIdxInfo->estimatedRows = 2147483647;
}
pIdxInfo->idxNum = idxNum;
+#ifdef SQLITE_INDEX_SCAN_HEX
+ pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_HEX;
+#endif
return SQLITE_OK;
}
@@ -6923,7 +7705,8 @@ static const char *re_subcompile_string(ReCompiled *p){
** regular expression. Applications should invoke this routine once
** for every call to re_compile() to avoid memory leaks.
*/
-static void re_free(ReCompiled *pRe){
+static void re_free(void *p){
+ ReCompiled *pRe = (ReCompiled*)p;
if( pRe ){
sqlite3_free(pRe->aOp);
sqlite3_free(pRe->aArg);
@@ -7192,7 +7975,7 @@ int sqlite3_regexp_init(
** 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
+** If five or more arguments are passed to this function and an
** error is encountered, an exception is raised.
**
** READFILE(FILE):
@@ -7244,24 +8027,27 @@ SQLITE_EXTENSION_INIT1
# include <dirent.h>
# include <utime.h>
# include <sys/time.h>
+# define STRUCT_STAT struct stat
#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)
+# define STRUCT_STAT struct _stat
+# define chmod(path,mode) fileio_chmod(path,mode)
+# define mkdir(path,mode) fileio_mkdir(path)
#endif
#include <time.h>
#include <errno.h>
+/* When used as part of the CLI, the sqlite3_stdio.h module will have
+** been included before this one. In that case use the sqlite3_stdio.h
+** #defines. If not, create our own for fopen().
+*/
+#ifndef _SQLITE3_STDIO_H_
+# define sqlite3_fopen fopen
+#endif
/*
** Structure of the fsdir() table-valued function
@@ -7275,6 +8061,40 @@ SQLITE_EXTENSION_INIT1
#define FSDIR_COLUMN_PATH 4 /* Path to top of search */
#define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */
+/*
+** UTF8 chmod() function for Windows
+*/
+#if defined(_WIN32) || defined(WIN32)
+static int fileio_chmod(const char *zPath, int pmode){
+ sqlite3_int64 sz = strlen(zPath);
+ wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) );
+ int rc;
+ if( b1==0 ) return -1;
+ sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz);
+ b1[sz] = 0;
+ rc = _wchmod(b1, pmode);
+ sqlite3_free(b1);
+ return rc;
+}
+#endif
+
+/*
+** UTF8 mkdir() function for Windows
+*/
+#if defined(_WIN32) || defined(WIN32)
+static int fileio_mkdir(const char *zPath){
+ sqlite3_int64 sz = strlen(zPath);
+ wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) );
+ int rc;
+ if( b1==0 ) return -1;
+ sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz);
+ b1[sz] = 0;
+ rc = _wmkdir(b1);
+ sqlite3_free(b1);
+ return rc;
+}
+#endif
+
/*
** Set the result stored by context ctx to a blob containing the
@@ -7294,7 +8114,7 @@ static void readFileContents(sqlite3_context *ctx, const char *zName){
sqlite3 *db;
int mxBlob;
- in = fopen(zName, "rb");
+ in = sqlite3_fopen(zName, "rb");
if( in==0 ){
/* File does not exist or is unreadable. Leave the result set to NULL. */
return;
@@ -7405,7 +8225,7 @@ LPWSTR utf8_to_utf16(const char *z){
*/
static void statTimesToUtc(
const char *zPath,
- struct stat *pStatBuf
+ STRUCT_STAT *pStatBuf
){
HANDLE hFindFile;
WIN32_FIND_DATAW fd;
@@ -7433,10 +8253,16 @@ static void statTimesToUtc(
*/
static int fileStat(
const char *zPath,
- struct stat *pStatBuf
+ STRUCT_STAT *pStatBuf
){
#if defined(_WIN32)
- int rc = stat(zPath, pStatBuf);
+ sqlite3_int64 sz = strlen(zPath);
+ wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) );
+ int rc;
+ if( b1==0 ) return 1;
+ sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz);
+ b1[sz] = 0;
+ rc = _wstat(b1, pStatBuf);
if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
return rc;
#else
@@ -7451,12 +8277,10 @@ static int fileStat(
*/
static int fileLinkStat(
const char *zPath,
- struct stat *pStatBuf
+ STRUCT_STAT *pStatBuf
){
#if defined(_WIN32)
- int rc = lstat(zPath, pStatBuf);
- if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
- return rc;
+ return fileStat(zPath, pStatBuf);
#else
return lstat(zPath, pStatBuf);
#endif
@@ -7486,7 +8310,7 @@ static int makeDirectory(
int i = 1;
while( rc==SQLITE_OK ){
- struct stat sStat;
+ STRUCT_STAT sStat;
int rc2;
for(; zCopy[i]!='/' && i<nCopy; i++);
@@ -7536,7 +8360,7 @@ static int writeFile(
** 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;
+ STRUCT_STAT sStat;
if( errno!=EEXIST
|| 0!=fileStat(zFile, &sStat)
|| !S_ISDIR(sStat.st_mode)
@@ -7549,7 +8373,7 @@ static int writeFile(
sqlite3_int64 nWrite = 0;
const char *z;
int rc = 0;
- FILE *out = fopen(zFile, "wb");
+ FILE *out = sqlite3_fopen(zFile, "wb");
if( out==0 ) return 1;
z = (const char*)sqlite3_value_blob(pData);
if( z ){
@@ -7582,7 +8406,7 @@ static int writeFile(
GetSystemTime(&currentTime);
SystemTimeToFileTime(&currentTime, &lastAccess);
- intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
+ intervals = (mtime*10000000) + 116444736000000000;
lastWrite.dwLowDateTime = (DWORD)intervals;
lastWrite.dwHighDateTime = intervals >> 32;
zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
@@ -7738,7 +8562,7 @@ struct fsdir_cursor {
const char *zBase;
int nBase;
- struct stat sStat; /* Current lstat() results */
+ STRUCT_STAT sStat; /* Current lstat() results */
char *zPath; /* Path to current entry */
sqlite3_int64 iRowid; /* Current rowid */
};
@@ -8235,6 +9059,11 @@ SQLITE_EXTENSION_INIT1
#ifndef SQLITE_OMIT_VIRTUALTABLE
+#ifndef IsAlnum
+#define IsAlnum(X) isalnum((unsigned char)X)
+#endif
+
+
/* completion_vtab is a subclass of sqlite3_vtab which will
** serve as the underlying representation of a completion virtual table
*/
@@ -8445,7 +9274,7 @@ static int completionNext(sqlite3_vtab_cursor *cur){
zSql = sqlite3_mprintf(
"%z%s"
"SELECT pti.name FROM \"%w\".sqlite_schema AS sm"
- " JOIN pragma_table_info(sm.name,%Q) AS pti"
+ " JOIN pragma_table_xinfo(sm.name,%Q) AS pti"
" WHERE sm.type='table'",
zSql, zSep, zDb, zDb
);
@@ -8571,7 +9400,7 @@ static int completionFilter(
}
if( pCur->zLine!=0 && pCur->zPrefix==0 ){
int i = pCur->nLine;
- while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){
+ while( i>0 && (IsAlnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){
i--;
}
pCur->nPrefix = pCur->nLine - i;
@@ -9405,10 +10234,20 @@ SQLITE_EXTENSION_INIT1
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <stdint.h>
+#ifndef SQLITE_NO_STDINT
+# include <stdint.h>
+#endif
#include <zlib.h>
+/* When used as part of the CLI, the sqlite3_stdio.h module will have
+** been included before this one. In that case use the sqlite3_stdio.h
+** #defines. If not, create our own for fopen().
+*/
+#ifndef _SQLITE3_STDIO_H_
+# define sqlite3_fopen fopen
+#endif
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
#ifndef SQLITE_AMALGAMATION
@@ -10665,7 +11504,7 @@ static int zipfileFilter(
}
if( 0==pTab->pWriteFd && 0==bInMemory ){
- pCsr->pFile = zFile ? fopen(zFile, "rb") : 0;
+ pCsr->pFile = zFile ? sqlite3_fopen(zFile, "rb") : 0;
if( pCsr->pFile==0 ){
zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
rc = SQLITE_ERROR;
@@ -10855,7 +11694,7 @@ static int zipfileBegin(sqlite3_vtab *pVtab){
** 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+");
+ pTab->pWriteFd = sqlite3_fopen(pTab->zFile, "ab+");
if( pTab->pWriteFd==0 ){
pTab->base.zErrMsg = sqlite3_mprintf(
"zipfile: failed to open file %s for writing", pTab->zFile
@@ -13308,6 +14147,66 @@ static int idxProcessTriggers(sqlite3expert *p, char **pzErr){
return rc;
}
+/*
+** This function tests if the schema of the main database of database handle
+** db contains an object named zTab. Assuming no error occurs, output parameter
+** (*pbContains) is set to true if zTab exists, or false if it does not.
+**
+** Or, if an error occurs, an SQLite error code is returned. The final value
+** of (*pbContains) is undefined in this case.
+*/
+static int expertDbContainsObject(
+ sqlite3 *db,
+ const char *zTab,
+ int *pbContains /* OUT: True if object exists */
+){
+ const char *zSql = "SELECT 1 FROM sqlite_schema WHERE name = ?";
+ sqlite3_stmt *pSql = 0;
+ int rc = SQLITE_OK;
+ int ret = 0;
+
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_text(pSql, 1, zTab, -1, SQLITE_STATIC);
+ if( SQLITE_ROW==sqlite3_step(pSql) ){
+ ret = 1;
+ }
+ rc = sqlite3_finalize(pSql);
+ }
+
+ *pbContains = ret;
+ return rc;
+}
+
+/*
+** Execute SQL command zSql using database handle db. If no error occurs,
+** set (*pzErr) to NULL and return SQLITE_OK.
+**
+** If an error does occur, return an SQLite error code and set (*pzErr) to
+** point to a buffer containing an English language error message. Except,
+** if the error message begins with "no such module:", then ignore the
+** error and return as if the SQL statement had succeeded.
+**
+** This is used to copy as much of the database schema as possible while
+** ignoring any errors related to missing virtual table modules.
+*/
+static int expertSchemaSql(sqlite3 *db, const char *zSql, char **pzErr){
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+
+ rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
+ if( rc!=SQLITE_OK && zErr ){
+ int nErr = STRLEN(zErr);
+ if( nErr>=15 && memcmp(zErr, "no such module:", 15)==0 ){
+ sqlite3_free(zErr);
+ rc = SQLITE_OK;
+ zErr = 0;
+ }
+ }
+
+ *pzErr = zErr;
+ return rc;
+}
static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
int rc = idxRegisterVtab(p);
@@ -13319,26 +14218,35 @@ static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
** 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_%%' "
+ "SELECT type, name, sql, 1, "
+ " substr(sql,1,14)=='create virtual' COLLATE nocase "
+ "FROM sqlite_schema "
+ "WHERE type IN ('table','view') AND "
+ " substr(name,1,7)!='sqlite_' COLLATE nocase "
" UNION ALL "
- "SELECT type, name, sql, 2 FROM sqlite_schema "
+ "SELECT type, name, sql, 2, 0 FROM sqlite_schema "
"WHERE type = 'trigger'"
" AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
- "ORDER BY 4, 1"
+ "ORDER BY 4, 5 DESC, 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);
+ int bVirtual = sqlite3_column_int(pSchema, 4);
+ int bExists = 0;
if( zType==0 || zName==0 ) continue;
- if( zType[0]=='v' || zType[1]=='r' ){
- if( zSql ) rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
+ rc = expertDbContainsObject(p->dbv, zName, &bExists);
+ if( rc || bExists ) continue;
+
+ if( zType[0]=='v' || zType[1]=='r' || bVirtual ){
+ /* A view. Or a trigger on a view. */
+ if( zSql ) rc = expertSchemaSql(p->dbv, zSql, pzErrmsg);
}else{
IdxTable *pTab;
rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && ALWAYS(pTab!=0) ){
int i;
char *zInner = 0;
char *zOuter = 0;
@@ -13539,6 +14447,12 @@ static int idxPopulateOneStat1(
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);
+ if( zName==0 ){
+ /* This index contains an expression. Ignore it. */
+ sqlite3_free(zCols);
+ sqlite3_free(zOrder);
+ return sqlite3_reset(pIndexXInfo);
+ }
zCols = idxAppendText(&rc, zCols,
"%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s",
zComma, zName, nCol, zName, zColl
@@ -13867,12 +14781,18 @@ sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
if( rc==SQLITE_OK ){
sqlite3_stmt *pSql = 0;
rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
- "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
- " AND sql NOT LIKE 'CREATE VIRTUAL %%' ORDER BY rowid"
+ "SELECT sql, name, substr(sql,1,14)=='create virtual' COLLATE nocase"
+ " FROM sqlite_schema WHERE substr(name,1,7)!='sqlite_' COLLATE nocase"
+ " ORDER BY 3 DESC, rowid"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
- if( zSql ) rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
+ const char *zName = (const char*)sqlite3_column_text(pSql, 1);
+ int bExists = 0;
+ rc = expertDbContainsObject(pNew->dbm, zName, &bExists);
+ if( rc==SQLITE_OK && zSql && bExists==0 ){
+ rc = expertSchemaSql(pNew->dbm, zSql, pzErrmsg);
+ }
}
idxFinalize(&rc, pSql);
}
@@ -13887,7 +14807,7 @@ sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
sqlite3_set_authorizer(pNew->dbv, idxAuthCallback, (void*)pNew);
}
- /* If an error has occurred, free the new object and reutrn NULL. Otherwise,
+ /* If an error has occurred, free the new object and return NULL. Otherwise,
** return the new sqlite3expert handle. */
if( rc!=SQLITE_OK ){
sqlite3_expert_destroy(pNew);
@@ -14069,7 +14989,6 @@ void sqlite3_expert_destroy(sqlite3expert *p){
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
/************************* End ../ext/expert/sqlite3expert.c ********************/
-
/************************* Begin ../ext/intck/sqlite3intck.h ******************/
/*
** 2024-02-08
@@ -15187,6 +16106,1320 @@ const char *sqlite3_intck_test_sql(sqlite3_intck *p, const char *zObj){
}
/************************* End ../ext/intck/sqlite3intck.c ********************/
+/************************* Begin ../ext/misc/stmtrand.c ******************/
+/*
+** 2024-05-24
+**
+** 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.
+**
+******************************************************************************
+**
+** An SQL function that return pseudo-random non-negative integers.
+**
+** SELECT stmtrand(123);
+**
+** A special feature of this function is that the same sequence of random
+** integers is returned for each invocation of the statement. This makes
+** the results repeatable, and hence useful for testing. The argument is
+** an integer which is the seed for the random number sequence. The seed
+** is used by the first invocation of this function only and is ignored
+** for all subsequent calls within the same statement.
+**
+** Resetting a statement (sqlite3_reset()) also resets the random number
+** sequence.
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+/* State of the pseudo-random number generator */
+typedef struct Stmtrand {
+ unsigned int x, y;
+} Stmtrand;
+
+/* auxdata key */
+#define STMTRAND_KEY (-4418371)
+
+/*
+** Function: stmtrand(SEED)
+**
+** Return a pseudo-random number.
+*/
+static void stmtrandFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Stmtrand *p;
+
+ p = (Stmtrand*)sqlite3_get_auxdata(context, STMTRAND_KEY);
+ if( p==0 ){
+ unsigned int seed;
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ if( argc>=1 ){
+ seed = (unsigned int)sqlite3_value_int(argv[0]);
+ }else{
+ seed = 0;
+ }
+ p->x = seed | 1;
+ p->y = seed;
+ sqlite3_set_auxdata(context, STMTRAND_KEY, p, sqlite3_free);
+ p = (Stmtrand*)sqlite3_get_auxdata(context, STMTRAND_KEY);
+ if( p==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ }
+ p->x = (p->x>>1) ^ ((1+~(p->x&1)) & 0xd0000001);
+ p->y = p->y*1103515245 + 12345;
+ sqlite3_result_int(context, (int)((p->x ^ p->y)&0x7fffffff));
+}
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_stmtrand_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, "stmtrand", 1, SQLITE_UTF8, 0,
+ stmtrandFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "stmtrand", 0, SQLITE_UTF8, 0,
+ stmtrandFunc, 0, 0);
+ }
+ return rc;
+}
+
+/************************* End ../ext/misc/stmtrand.c ********************/
+/************************* Begin ../ext/misc/vfstrace.c ******************/
+/*
+** 2011 March 16
+**
+** 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 implements a VFS shim that writes diagnostic
+** output for each VFS call, similar to "strace".
+**
+** USAGE:
+**
+** This source file exports a single symbol which is the name of a
+** function:
+**
+** int vfstrace_register(
+** const char *zTraceName, // Name of the newly constructed VFS
+** const char *zOldVfsName, // Name of the underlying VFS
+** int (*xOut)(const char*,void*), // Output routine. ex: fputs
+** void *pOutArg, // 2nd argument to xOut. ex: stderr
+** int makeDefault // Make the new VFS the default
+** );
+**
+** Applications that want to trace their VFS usage must provide a callback
+** function with this prototype:
+**
+** int traceOutput(const char *zMessage, void *pAppData);
+**
+** This function will "output" the trace messages, where "output" can
+** mean different things to different applications. The traceOutput function
+** for the command-line shell (see shell.c) is "fputs" from the standard
+** library, which means that all trace output is written on the stream
+** specified by the second argument. In the case of the command-line shell
+** the second argument is stderr. Other applications might choose to output
+** trace information to a file, over a socket, or write it into a buffer.
+**
+** The vfstrace_register() function creates a new "shim" VFS named by
+** the zTraceName parameter. A "shim" VFS is an SQLite backend that does
+** not really perform the duties of a true backend, but simply filters or
+** interprets VFS calls before passing them off to another VFS which does
+** the actual work. In this case the other VFS - the one that does the
+** real work - is identified by the second parameter, zOldVfsName. If
+** the 2nd parameter is NULL then the default VFS is used. The common
+** case is for the 2nd parameter to be NULL.
+**
+** The third and fourth parameters are the pointer to the output function
+** and the second argument to the output function. For the SQLite
+** command-line shell, when the -vfstrace option is used, these parameters
+** are fputs and stderr, respectively.
+**
+** The fifth argument is true (non-zero) to cause the newly created VFS
+** to become the default VFS. The common case is for the fifth parameter
+** to be true.
+**
+** The call to vfstrace_register() simply creates the shim VFS that does
+** tracing. The application must also arrange to use the new VFS for
+** all database connections that are created and for which tracing is
+** desired. This can be done by specifying the trace VFS using URI filename
+** notation, or by specifying the trace VFS as the 4th parameter to
+** sqlite3_open_v2() or by making the trace VFS be the default (by setting
+** the 5th parameter of vfstrace_register() to 1).
+**
+**
+** ENABLING VFSTRACE IN A COMMAND-LINE SHELL
+**
+** The SQLite command line shell implemented by the shell.c source file
+** can be used with this module. To compile in -vfstrace support, first
+** gather this file (test_vfstrace.c), the shell source file (shell.c),
+** and the SQLite amalgamation source files (sqlite3.c, sqlite3.h) into
+** the working directory. Then compile using a command like the following:
+**
+** gcc -o sqlite3 -Os -I. -DSQLITE_ENABLE_VFSTRACE \
+** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
+** -DHAVE_READLINE -DHAVE_USLEEP=1 \
+** shell.c test_vfstrace.c sqlite3.c -ldl -lreadline -lncurses
+**
+** The gcc command above works on Linux and provides (in addition to the
+** -vfstrace option) support for FTS3 and FTS4, RTREE, and command-line
+** editing using the readline library. The command-line shell does not
+** use threads so we added -DSQLITE_THREADSAFE=0 just to make the code
+** run a little faster. For compiling on a Mac, you'll probably need
+** to omit the -DHAVE_READLINE, the -lreadline, and the -lncurses options.
+** The compilation could be simplified to just this:
+**
+** gcc -DSQLITE_ENABLE_VFSTRACE \
+** shell.c test_vfstrace.c sqlite3.c -ldl -lpthread
+**
+** In this second example, all unnecessary options have been removed
+** Note that since the code is now threadsafe, we had to add the -lpthread
+** option to pull in the pthreads library.
+**
+** To cross-compile for windows using MinGW, a command like this might
+** work:
+**
+** /opt/mingw/bin/i386-mingw32msvc-gcc -o sqlite3.exe -Os -I \
+** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_VFSTRACE \
+** shell.c test_vfstrace.c sqlite3.c
+**
+** Similar compiler commands will work on different systems. The key
+** invariants are (1) you must have -DSQLITE_ENABLE_VFSTRACE so that
+** the shell.c source file will know to include the -vfstrace command-line
+** option and (2) you must compile and link the three source files
+** shell,c, test_vfstrace.c, and sqlite3.c.
+**
+** RUNTIME CONTROL OF VFSTRACE OUTPUT
+**
+** The application can use the "vfstrace" pragma to control which VFS
+** APIs are traced. To disable all output:
+**
+** PRAGMA vfstrace('-all');
+**
+** To enable all output (which is the default setting):
+**
+** PRAGMA vfstrace('+all');
+**
+** Individual APIs can be enabled or disabled by name, with or without
+** the initial "x" character. For example, to set up for tracing lock
+** primitives only:
+**
+** PRAGMA vfstrace('-all, +Lock,Unlock,ShmLock');
+**
+** The argument to the vfstrace pragma ignores capitalization and any
+** characters other than alphabetics, '+', and '-'.
+*/
+#include <stdlib.h>
+#include <string.h>
+/* #include "sqlite3.h" */
+
+/*
+** An instance of this structure is attached to the each trace VFS to
+** provide auxiliary information.
+*/
+typedef struct vfstrace_info vfstrace_info;
+struct vfstrace_info {
+ sqlite3_vfs *pRootVfs; /* The underlying real VFS */
+ int (*xOut)(const char*, void*); /* Send output here */
+ unsigned int mTrace; /* Mask of interfaces to trace */
+ u8 bOn; /* Tracing on/off */
+ void *pOutArg; /* First argument to xOut */
+ const char *zVfsName; /* Name of this trace-VFS */
+ sqlite3_vfs *pTraceVfs; /* Pointer back to the trace VFS */
+};
+
+/*
+** The sqlite3_file object for the trace VFS
+*/
+typedef struct vfstrace_file vfstrace_file;
+struct vfstrace_file {
+ sqlite3_file base; /* Base class. Must be first */
+ vfstrace_info *pInfo; /* The trace-VFS to which this file belongs */
+ const char *zFName; /* Base name of the file */
+ sqlite3_file *pReal; /* The real underlying file */
+};
+
+/*
+** Bit values for vfstrace_info.mTrace.
+*/
+#define VTR_CLOSE 0x00000001
+#define VTR_READ 0x00000002
+#define VTR_WRITE 0x00000004
+#define VTR_TRUNC 0x00000008
+#define VTR_SYNC 0x00000010
+#define VTR_FSIZE 0x00000020
+#define VTR_LOCK 0x00000040
+#define VTR_UNLOCK 0x00000080
+#define VTR_CRL 0x00000100
+#define VTR_FCTRL 0x00000200
+#define VTR_SECSZ 0x00000400
+#define VTR_DEVCHAR 0x00000800
+#define VTR_SHMLOCK 0x00001000
+#define VTR_SHMMAP 0x00002000
+#define VTR_SHMBAR 0x00004000
+#define VTR_SHMUNMAP 0x00008000
+#define VTR_OPEN 0x00010000
+#define VTR_DELETE 0x00020000
+#define VTR_ACCESS 0x00040000
+#define VTR_FULLPATH 0x00080000
+#define VTR_DLOPEN 0x00100000
+#define VTR_DLERR 0x00200000
+#define VTR_DLSYM 0x00400000
+#define VTR_DLCLOSE 0x00800000
+#define VTR_RAND 0x01000000
+#define VTR_SLEEP 0x02000000
+#define VTR_CURTIME 0x04000000
+#define VTR_LASTERR 0x08000000
+#define VTR_FETCH 0x10000000 /* Also coverse xUnfetch */
+
+/*
+** Method declarations for vfstrace_file.
+*/
+static int vfstraceClose(sqlite3_file*);
+static int vfstraceRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int vfstraceWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
+static int vfstraceTruncate(sqlite3_file*, sqlite3_int64 size);
+static int vfstraceSync(sqlite3_file*, int flags);
+static int vfstraceFileSize(sqlite3_file*, sqlite3_int64 *pSize);
+static int vfstraceLock(sqlite3_file*, int);
+static int vfstraceUnlock(sqlite3_file*, int);
+static int vfstraceCheckReservedLock(sqlite3_file*, int *);
+static int vfstraceFileControl(sqlite3_file*, int op, void *pArg);
+static int vfstraceSectorSize(sqlite3_file*);
+static int vfstraceDeviceCharacteristics(sqlite3_file*);
+static int vfstraceShmLock(sqlite3_file*,int,int,int);
+static int vfstraceShmMap(sqlite3_file*,int,int,int, void volatile **);
+static void vfstraceShmBarrier(sqlite3_file*);
+static int vfstraceShmUnmap(sqlite3_file*,int);
+
+/*
+** Method declarations for vfstrace_vfs.
+*/
+static int vfstraceOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+static int vfstraceDelete(sqlite3_vfs*, const char *zName, int syncDir);
+static int vfstraceAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int vfstraceFullPathname(sqlite3_vfs*, const char *zName, int, char *);
+static void *vfstraceDlOpen(sqlite3_vfs*, const char *zFilename);
+static void vfstraceDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
+static void (*vfstraceDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
+static void vfstraceDlClose(sqlite3_vfs*, void*);
+static int vfstraceRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int vfstraceSleep(sqlite3_vfs*, int microseconds);
+static int vfstraceCurrentTime(sqlite3_vfs*, double*);
+static int vfstraceGetLastError(sqlite3_vfs*, int, char*);
+static int vfstraceCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+static int vfstraceSetSystemCall(sqlite3_vfs*,const char*, sqlite3_syscall_ptr);
+static sqlite3_syscall_ptr vfstraceGetSystemCall(sqlite3_vfs*, const char *);
+static const char *vfstraceNextSystemCall(sqlite3_vfs*, const char *zName);
+
+/*
+** Return a pointer to the tail of the pathname. Examples:
+**
+** /home/drh/xyzzy.txt -> xyzzy.txt
+** xyzzy.txt -> xyzzy.txt
+*/
+static const char *fileTail(const char *z){
+ size_t i;
+ if( z==0 ) return 0;
+ i = strlen(z)-1;
+ while( i>0 && z[i-1]!='/' ){ i--; }
+ return &z[i];
+}
+
+/*
+** Send trace output defined by zFormat and subsequent arguments.
+*/
+static void vfstrace_printf(
+ vfstrace_info *pInfo,
+ const char *zFormat,
+ ...
+){
+ va_list ap;
+ char *zMsg;
+ if( pInfo->bOn ){
+ va_start(ap, zFormat);
+ zMsg = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ pInfo->xOut(zMsg, pInfo->pOutArg);
+ sqlite3_free(zMsg);
+ }
+}
+
+/*
+** Try to convert an error code into a symbolic name for that error code.
+*/
+static const char *vfstrace_errcode_name(int rc ){
+ const char *zVal = 0;
+ switch( rc ){
+ case SQLITE_OK: zVal = "SQLITE_OK"; break;
+ case SQLITE_INTERNAL: zVal = "SQLITE_INTERNAL"; break;
+ case SQLITE_ERROR: zVal = "SQLITE_ERROR"; break;
+ case SQLITE_PERM: zVal = "SQLITE_PERM"; break;
+ case SQLITE_ABORT: zVal = "SQLITE_ABORT"; break;
+ case SQLITE_BUSY: zVal = "SQLITE_BUSY"; break;
+ case SQLITE_LOCKED: zVal = "SQLITE_LOCKED"; break;
+ case SQLITE_NOMEM: zVal = "SQLITE_NOMEM"; break;
+ case SQLITE_READONLY: zVal = "SQLITE_READONLY"; break;
+ case SQLITE_INTERRUPT: zVal = "SQLITE_INTERRUPT"; break;
+ case SQLITE_IOERR: zVal = "SQLITE_IOERR"; break;
+ case SQLITE_CORRUPT: zVal = "SQLITE_CORRUPT"; break;
+ case SQLITE_NOTFOUND: zVal = "SQLITE_NOTFOUND"; break;
+ case SQLITE_FULL: zVal = "SQLITE_FULL"; break;
+ case SQLITE_CANTOPEN: zVal = "SQLITE_CANTOPEN"; break;
+ case SQLITE_PROTOCOL: zVal = "SQLITE_PROTOCOL"; break;
+ case SQLITE_EMPTY: zVal = "SQLITE_EMPTY"; break;
+ case SQLITE_SCHEMA: zVal = "SQLITE_SCHEMA"; break;
+ case SQLITE_TOOBIG: zVal = "SQLITE_TOOBIG"; break;
+ case SQLITE_CONSTRAINT: zVal = "SQLITE_CONSTRAINT"; break;
+ case SQLITE_MISMATCH: zVal = "SQLITE_MISMATCH"; break;
+ case SQLITE_MISUSE: zVal = "SQLITE_MISUSE"; break;
+ case SQLITE_NOLFS: zVal = "SQLITE_NOLFS"; break;
+ case SQLITE_IOERR_READ: zVal = "SQLITE_IOERR_READ"; break;
+ case SQLITE_IOERR_SHORT_READ: zVal = "SQLITE_IOERR_SHORT_READ"; break;
+ case SQLITE_IOERR_WRITE: zVal = "SQLITE_IOERR_WRITE"; break;
+ case SQLITE_IOERR_FSYNC: zVal = "SQLITE_IOERR_FSYNC"; break;
+ case SQLITE_IOERR_DIR_FSYNC: zVal = "SQLITE_IOERR_DIR_FSYNC"; break;
+ case SQLITE_IOERR_TRUNCATE: zVal = "SQLITE_IOERR_TRUNCATE"; break;
+ case SQLITE_IOERR_FSTAT: zVal = "SQLITE_IOERR_FSTAT"; break;
+ case SQLITE_IOERR_UNLOCK: zVal = "SQLITE_IOERR_UNLOCK"; break;
+ case SQLITE_IOERR_RDLOCK: zVal = "SQLITE_IOERR_RDLOCK"; break;
+ case SQLITE_IOERR_DELETE: zVal = "SQLITE_IOERR_DELETE"; break;
+ case SQLITE_IOERR_BLOCKED: zVal = "SQLITE_IOERR_BLOCKED"; break;
+ case SQLITE_IOERR_NOMEM: zVal = "SQLITE_IOERR_NOMEM"; break;
+ case SQLITE_IOERR_ACCESS: zVal = "SQLITE_IOERR_ACCESS"; break;
+ case SQLITE_IOERR_CHECKRESERVEDLOCK:
+ zVal = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
+ case SQLITE_IOERR_LOCK: zVal = "SQLITE_IOERR_LOCK"; break;
+ case SQLITE_IOERR_CLOSE: zVal = "SQLITE_IOERR_CLOSE"; break;
+ case SQLITE_IOERR_DIR_CLOSE: zVal = "SQLITE_IOERR_DIR_CLOSE"; break;
+ case SQLITE_IOERR_SHMOPEN: zVal = "SQLITE_IOERR_SHMOPEN"; break;
+ case SQLITE_IOERR_SHMSIZE: zVal = "SQLITE_IOERR_SHMSIZE"; break;
+ case SQLITE_IOERR_SHMLOCK: zVal = "SQLITE_IOERR_SHMLOCK"; break;
+ case SQLITE_IOERR_SHMMAP: zVal = "SQLITE_IOERR_SHMMAP"; break;
+ case SQLITE_IOERR_SEEK: zVal = "SQLITE_IOERR_SEEK"; break;
+ case SQLITE_IOERR_GETTEMPPATH: zVal = "SQLITE_IOERR_GETTEMPPATH"; break;
+ case SQLITE_IOERR_CONVPATH: zVal = "SQLITE_IOERR_CONVPATH"; break;
+ case SQLITE_READONLY_DBMOVED: zVal = "SQLITE_READONLY_DBMOVED"; break;
+ case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
+ case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
+ case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;
+ }
+ return zVal;
+}
+
+/*
+** Convert value rc into a string and print it using zFormat. zFormat
+** should have exactly one %s
+*/
+static void vfstrace_print_errcode(
+ vfstrace_info *pInfo,
+ const char *zFormat,
+ int rc
+){
+ const char *zVal;
+ char zBuf[50];
+ zVal = vfstrace_errcode_name(rc);
+ if( zVal==0 ){
+ zVal = vfstrace_errcode_name(rc&0xff);
+ if( zVal ){
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%s | 0x%x", zVal, rc&0xffff00);
+ }else{
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d (0x%x)", rc, rc);
+ }
+ zVal = zBuf;
+ }
+ vfstrace_printf(pInfo, zFormat, zVal);
+}
+
+/*
+** Append to a buffer.
+*/
+static void strappend(char *z, int *pI, const char *zAppend){
+ int i = *pI;
+ while( zAppend[0] ){ z[i++] = *(zAppend++); }
+ z[i] = 0;
+ *pI = i;
+}
+
+/*
+** Turn tracing output on or off according to mMask.
+*/
+static void vfstraceOnOff(vfstrace_info *pInfo, unsigned int mMask){
+ pInfo->bOn = (pInfo->mTrace & mMask)!=0;
+}
+
+/*
+** Close an vfstrace-file.
+*/
+static int vfstraceClose(sqlite3_file *pFile){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_CLOSE);
+ vfstrace_printf(pInfo, "%s.xClose(%s)", pInfo->zVfsName, p->zFName);
+ rc = p->pReal->pMethods->xClose(p->pReal);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ if( rc==SQLITE_OK ){
+ sqlite3_free((void*)p->base.pMethods);
+ p->base.pMethods = 0;
+ }
+ return rc;
+}
+
+/*
+** Read data from an vfstrace-file.
+*/
+static int vfstraceRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_READ);
+ vfstrace_printf(pInfo, "%s.xRead(%s,n=%d,ofst=%lld)",
+ pInfo->zVfsName, p->zFName, iAmt, iOfst);
+ rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+
+/*
+** Write data to an vfstrace-file.
+*/
+static int vfstraceWrite(
+ sqlite3_file *pFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_WRITE);
+ vfstrace_printf(pInfo, "%s.xWrite(%s,n=%d,ofst=%lld)",
+ pInfo->zVfsName, p->zFName, iAmt, iOfst);
+ rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+
+/*
+** Truncate an vfstrace-file.
+*/
+static int vfstraceTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_TRUNC);
+ vfstrace_printf(pInfo, "%s.xTruncate(%s,%lld)", pInfo->zVfsName, p->zFName,
+ size);
+ rc = p->pReal->pMethods->xTruncate(p->pReal, size);
+ vfstrace_printf(pInfo, " -> %d\n", rc);
+ return rc;
+}
+
+/*
+** Sync an vfstrace-file.
+*/
+static int vfstraceSync(sqlite3_file *pFile, int flags){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ int i;
+ char zBuf[100];
+ memcpy(zBuf, "|0", 3);
+ i = 0;
+ if( flags & SQLITE_SYNC_FULL ) strappend(zBuf, &i, "|FULL");
+ else if( flags & SQLITE_SYNC_NORMAL ) strappend(zBuf, &i, "|NORMAL");
+ if( flags & SQLITE_SYNC_DATAONLY ) strappend(zBuf, &i, "|DATAONLY");
+ if( flags & ~(SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY) ){
+ sqlite3_snprintf(sizeof(zBuf)-i, &zBuf[i], "|0x%x", flags);
+ }
+ vfstraceOnOff(pInfo, VTR_SYNC);
+ vfstrace_printf(pInfo, "%s.xSync(%s,%s)", pInfo->zVfsName, p->zFName,
+ &zBuf[1]);
+ rc = p->pReal->pMethods->xSync(p->pReal, flags);
+ vfstrace_printf(pInfo, " -> %d\n", rc);
+ return rc;
+}
+
+/*
+** Return the current file-size of an vfstrace-file.
+*/
+static int vfstraceFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_FSIZE);
+ vfstrace_printf(pInfo, "%s.xFileSize(%s)", pInfo->zVfsName, p->zFName);
+ rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
+ vfstrace_print_errcode(pInfo, " -> %s,", rc);
+ vfstrace_printf(pInfo, " size=%lld\n", *pSize);
+ return rc;
+}
+
+/*
+** Return the name of a lock.
+*/
+static const char *lockName(int eLock){
+ const char *azLockNames[] = {
+ "NONE", "SHARED", "RESERVED", "PENDING", "EXCLUSIVE"
+ };
+ if( eLock<0 || eLock>=(int)(sizeof(azLockNames)/sizeof(azLockNames[0])) ){
+ return "???";
+ }else{
+ return azLockNames[eLock];
+ }
+}
+
+/*
+** Lock an vfstrace-file.
+*/
+static int vfstraceLock(sqlite3_file *pFile, int eLock){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_LOCK);
+ vfstrace_printf(pInfo, "%s.xLock(%s,%s)", pInfo->zVfsName, p->zFName,
+ lockName(eLock));
+ rc = p->pReal->pMethods->xLock(p->pReal, eLock);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+
+/*
+** Unlock an vfstrace-file.
+*/
+static int vfstraceUnlock(sqlite3_file *pFile, int eLock){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_UNLOCK);
+ vfstrace_printf(pInfo, "%s.xUnlock(%s,%s)", pInfo->zVfsName, p->zFName,
+ lockName(eLock));
+ rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an vfstrace-file.
+*/
+static int vfstraceCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_CRL);
+ vfstrace_printf(pInfo, "%s.xCheckReservedLock(%s,%d)",
+ pInfo->zVfsName, p->zFName);
+ rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
+ vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
+ return rc;
+}
+
+/*
+** File control method. For custom operations on an vfstrace-file.
+*/
+static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ char zBuf[100];
+ char zBuf2[100];
+ char *zOp;
+ char *zRVal = 0;
+ vfstraceOnOff(pInfo, VTR_FCTRL);
+ switch( op ){
+ case SQLITE_FCNTL_LOCKSTATE: zOp = "LOCKSTATE"; break;
+ case SQLITE_GET_LOCKPROXYFILE: zOp = "GET_LOCKPROXYFILE"; break;
+ case SQLITE_SET_LOCKPROXYFILE: zOp = "SET_LOCKPROXYFILE"; break;
+ case SQLITE_LAST_ERRNO: zOp = "LAST_ERRNO"; break;
+ case SQLITE_FCNTL_SIZE_HINT: {
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "SIZE_HINT,%lld",
+ *(sqlite3_int64*)pArg);
+ zOp = zBuf;
+ break;
+ }
+ case SQLITE_FCNTL_CHUNK_SIZE: {
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "CHUNK_SIZE,%d", *(int*)pArg);
+ zOp = zBuf;
+ break;
+ }
+ case SQLITE_FCNTL_FILE_POINTER: zOp = "FILE_POINTER"; break;
+ case SQLITE_FCNTL_WIN32_AV_RETRY: zOp = "WIN32_AV_RETRY"; break;
+ case SQLITE_FCNTL_PERSIST_WAL: {
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "PERSIST_WAL,%d", *(int*)pArg);
+ zOp = zBuf;
+ break;
+ }
+ case SQLITE_FCNTL_OVERWRITE: zOp = "OVERWRITE"; break;
+ case SQLITE_FCNTL_VFSNAME: zOp = "VFSNAME"; break;
+ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: zOp = "POWERSAFE_OVERWRITE"; break;
+ case SQLITE_FCNTL_PRAGMA: {
+ const char *const* a = (const char*const*)pArg;
+ if( a[1] && strcmp(a[1],"vfstrace")==0 && a[2] ){
+ const u8 *zArg = (const u8*)a[2];
+ if( zArg[0]>='0' && zArg[0]<='9' ){
+ pInfo->mTrace = (sqlite3_uint64)strtoll(a[2], 0, 0);
+ }else{
+ static const struct {
+ const char *z;
+ unsigned int m;
+ } aKw[] = {
+ { "all", 0xffffffff },
+ { "close", VTR_CLOSE },
+ { "read", VTR_READ },
+ { "write", VTR_WRITE },
+ { "truncate", VTR_TRUNC },
+ { "sync", VTR_SYNC },
+ { "filesize", VTR_FSIZE },
+ { "lock", VTR_LOCK },
+ { "unlock", VTR_UNLOCK },
+ { "checkreservedlock", VTR_CRL },
+ { "filecontrol", VTR_FCTRL },
+ { "sectorsize", VTR_SECSZ },
+ { "devicecharacteristics", VTR_DEVCHAR },
+ { "shmlock", VTR_SHMLOCK },
+ { "shmmap", VTR_SHMMAP },
+ { "shmummap", VTR_SHMUNMAP },
+ { "shmbarrier", VTR_SHMBAR },
+ { "open", VTR_OPEN },
+ { "delete", VTR_DELETE },
+ { "access", VTR_ACCESS },
+ { "fullpathname", VTR_FULLPATH },
+ { "dlopen", VTR_DLOPEN },
+ { "dlerror", VTR_DLERR },
+ { "dlsym", VTR_DLSYM },
+ { "dlclose", VTR_DLCLOSE },
+ { "randomness", VTR_RAND },
+ { "sleep", VTR_SLEEP },
+ { "currenttime", VTR_CURTIME },
+ { "currenttimeint64", VTR_CURTIME },
+ { "getlasterror", VTR_LASTERR },
+ { "fetch", VTR_FETCH },
+ };
+ int onOff = 1;
+ while( zArg[0] ){
+ int jj, n;
+ while( zArg[0]!=0 && zArg[0]!='-' && zArg[0]!='+'
+ && !isalpha(zArg[0]) ) zArg++;
+ if( zArg[0]==0 ) break;
+ if( zArg[0]=='-' ){
+ onOff = 0;
+ zArg++;
+ }else if( zArg[0]=='+' ){
+ onOff = 1;
+ zArg++;
+ }
+ while( !isalpha(zArg[0]) ){
+ if( zArg[0]==0 ) break;
+ zArg++;
+ }
+ if( zArg[0]=='x' && isalpha(zArg[1]) ) zArg++;
+ for(n=0; isalpha(zArg[n]); n++){}
+ for(jj=0; jj<(int)(sizeof(aKw)/sizeof(aKw[0])); jj++){
+ if( sqlite3_strnicmp(aKw[jj].z,(const char*)zArg,n)==0 ){
+ if( onOff ){
+ pInfo->mTrace |= aKw[jj].m;
+ }else{
+ pInfo->mTrace &= ~aKw[jj].m;
+ }
+ break;
+ }
+ }
+ zArg += n;
+ }
+ }
+ }
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "PRAGMA,[%s,%s]",a[1],a[2]);
+ zOp = zBuf;
+ break;
+ }
+ case SQLITE_FCNTL_BUSYHANDLER: zOp = "BUSYHANDLER"; break;
+ case SQLITE_FCNTL_TEMPFILENAME: zOp = "TEMPFILENAME"; break;
+ case SQLITE_FCNTL_MMAP_SIZE: {
+ sqlite3_int64 iMMap = *(sqlite3_int64*)pArg;
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "MMAP_SIZE,%lld",iMMap);
+ zOp = zBuf;
+ break;
+ }
+ case SQLITE_FCNTL_TRACE: zOp = "TRACE"; break;
+ case SQLITE_FCNTL_HAS_MOVED: zOp = "HAS_MOVED"; break;
+ case SQLITE_FCNTL_SYNC: zOp = "SYNC"; break;
+ case SQLITE_FCNTL_COMMIT_PHASETWO: zOp = "COMMIT_PHASETWO"; break;
+ case SQLITE_FCNTL_WIN32_SET_HANDLE: zOp = "WIN32_SET_HANDLE"; break;
+ case SQLITE_FCNTL_WAL_BLOCK: zOp = "WAL_BLOCK"; break;
+ case SQLITE_FCNTL_ZIPVFS: zOp = "ZIPVFS"; break;
+ case SQLITE_FCNTL_RBU: zOp = "RBU"; break;
+ case SQLITE_FCNTL_VFS_POINTER: zOp = "VFS_POINTER"; break;
+ case SQLITE_FCNTL_JOURNAL_POINTER: zOp = "JOURNAL_POINTER"; break;
+ case SQLITE_FCNTL_WIN32_GET_HANDLE: zOp = "WIN32_GET_HANDLE"; break;
+ case SQLITE_FCNTL_PDB: zOp = "PDB"; break;
+ case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: zOp = "BEGIN_ATOMIC_WRITE"; break;
+ case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: zOp = "COMMIT_ATOMIC_WRITE"; break;
+ case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
+ zOp = "ROLLBACK_ATOMIC_WRITE";
+ break;
+ }
+ case SQLITE_FCNTL_LOCK_TIMEOUT: {
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "LOCK_TIMEOUT,%d", *(int*)pArg);
+ zOp = zBuf;
+ break;
+ }
+ case SQLITE_FCNTL_DATA_VERSION: zOp = "DATA_VERSION"; break;
+ case SQLITE_FCNTL_SIZE_LIMIT: zOp = "SIZE_LIMIT"; break;
+ case SQLITE_FCNTL_CKPT_DONE: zOp = "CKPT_DONE"; break;
+ case SQLITE_FCNTL_RESERVE_BYTES: zOp = "RESERVED_BYTES"; break;
+ case SQLITE_FCNTL_CKPT_START: zOp = "CKPT_START"; break;
+ case SQLITE_FCNTL_EXTERNAL_READER: zOp = "EXTERNAL_READER"; break;
+ case SQLITE_FCNTL_CKSM_FILE: zOp = "CKSM_FILE"; break;
+ case SQLITE_FCNTL_RESET_CACHE: zOp = "RESET_CACHE"; break;
+ case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
+ default: {
+ sqlite3_snprintf(sizeof zBuf, zBuf, "%d", op);
+ zOp = zBuf;
+ break;
+ }
+ }
+ vfstrace_printf(pInfo, "%s.xFileControl(%s,%s)",
+ pInfo->zVfsName, p->zFName, zOp);
+ rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
+ if( rc==SQLITE_OK ){
+ switch( op ){
+ case SQLITE_FCNTL_VFSNAME: {
+ *(char**)pArg = sqlite3_mprintf("vfstrace.%s/%z",
+ pInfo->zVfsName, *(char**)pArg);
+ zRVal = *(char**)pArg;
+ break;
+ }
+ case SQLITE_FCNTL_MMAP_SIZE: {
+ sqlite3_snprintf(sizeof(zBuf2), zBuf2, "%lld", *(sqlite3_int64*)pArg);
+ zRVal = zBuf2;
+ break;
+ }
+ case SQLITE_FCNTL_HAS_MOVED:
+ case SQLITE_FCNTL_PERSIST_WAL: {
+ sqlite3_snprintf(sizeof(zBuf2), zBuf2, "%d", *(int*)pArg);
+ zRVal = zBuf2;
+ break;
+ }
+ case SQLITE_FCNTL_PRAGMA:
+ case SQLITE_FCNTL_TEMPFILENAME: {
+ zRVal = *(char**)pArg;
+ break;
+ }
+ }
+ }
+ if( zRVal ){
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
+ vfstrace_printf(pInfo, ", %s\n", zRVal);
+ }else{
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ }
+ return rc;
+}
+
+/*
+** Return the sector-size in bytes for an vfstrace-file.
+*/
+static int vfstraceSectorSize(sqlite3_file *pFile){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_SECSZ);
+ vfstrace_printf(pInfo, "%s.xSectorSize(%s)", pInfo->zVfsName, p->zFName);
+ rc = p->pReal->pMethods->xSectorSize(p->pReal);
+ vfstrace_printf(pInfo, " -> %d\n", rc);
+ return rc;
+}
+
+/*
+** Return the device characteristic flags supported by an vfstrace-file.
+*/
+static int vfstraceDeviceCharacteristics(sqlite3_file *pFile){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_DEVCHAR);
+ vfstrace_printf(pInfo, "%s.xDeviceCharacteristics(%s)",
+ pInfo->zVfsName, p->zFName);
+ rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
+ vfstrace_printf(pInfo, " -> 0x%08x\n", rc);
+ return rc;
+}
+
+/*
+** Shared-memory operations.
+*/
+static int vfstraceShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
+ static const char *azLockName[] = {
+ "WRITE",
+ "CKPT",
+ "RECOVER",
+ "READ0",
+ "READ1",
+ "READ2",
+ "READ3",
+ "READ4",
+ };
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ char zLck[100];
+ int i = 0;
+ vfstraceOnOff(pInfo, VTR_SHMLOCK);
+ memcpy(zLck, "|0", 3);
+ if( flags & SQLITE_SHM_UNLOCK ) strappend(zLck, &i, "|UNLOCK");
+ if( flags & SQLITE_SHM_LOCK ) strappend(zLck, &i, "|LOCK");
+ if( flags & SQLITE_SHM_SHARED ) strappend(zLck, &i, "|SHARED");
+ if( flags & SQLITE_SHM_EXCLUSIVE ) strappend(zLck, &i, "|EXCLUSIVE");
+ if( flags & ~(0xf) ){
+ sqlite3_snprintf(sizeof(zLck)-i, &zLck[i], "|0x%x", flags);
+ }
+ if( ofst>=0 && ofst<(int)(sizeof(azLockName)/sizeof(azLockName[0])) ){
+ vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=%d(%s),n=%d,%s)",
+ pInfo->zVfsName, p->zFName, ofst, azLockName[ofst],
+ n, &zLck[1]);
+ }else{
+ vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=5d,n=%d,%s)",
+ pInfo->zVfsName, p->zFName, ofst,
+ n, &zLck[1]);
+ }
+ rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+static int vfstraceShmMap(
+ sqlite3_file *pFile,
+ int iRegion,
+ int szRegion,
+ int isWrite,
+ void volatile **pp
+){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_SHMMAP);
+ vfstrace_printf(pInfo, "%s.xShmMap(%s,iRegion=%d,szRegion=%d,isWrite=%d,*)",
+ pInfo->zVfsName, p->zFName, iRegion, szRegion, isWrite);
+ rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+static void vfstraceShmBarrier(sqlite3_file *pFile){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ vfstraceOnOff(pInfo, VTR_SHMBAR);
+ vfstrace_printf(pInfo, "%s.xShmBarrier(%s)\n", pInfo->zVfsName, p->zFName);
+ p->pReal->pMethods->xShmBarrier(p->pReal);
+}
+static int vfstraceShmUnmap(sqlite3_file *pFile, int delFlag){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_SHMUNMAP);
+ vfstrace_printf(pInfo, "%s.xShmUnmap(%s,delFlag=%d)",
+ pInfo->zVfsName, p->zFName, delFlag);
+ rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+static int vfstraceFetch(sqlite3_file *pFile, i64 iOff, int nAmt, void **pptr){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_FETCH);
+ vfstrace_printf(pInfo, "%s.xFetch(%s,iOff=%lld,nAmt=%d,p=%p)",
+ pInfo->zVfsName, p->zFName, iOff, nAmt, *pptr);
+ rc = p->pReal->pMethods->xFetch(p->pReal, iOff, nAmt, pptr);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+static int vfstraceUnfetch(sqlite3_file *pFile, i64 iOff, void *ptr){
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = p->pInfo;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_FETCH);
+ vfstrace_printf(pInfo, "%s.xUnfetch(%s,iOff=%lld,p=%p)",
+ pInfo->zVfsName, p->zFName, iOff, ptr);
+ rc = p->pReal->pMethods->xUnfetch(p->pReal, iOff, ptr);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+
+
+/*
+** Open an vfstrace file handle.
+*/
+static int vfstraceOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ int rc;
+ vfstrace_file *p = (vfstrace_file *)pFile;
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ p->pInfo = pInfo;
+ p->zFName = zName ? fileTail(zName) : "<temp>";
+ p->pReal = (sqlite3_file *)&p[1];
+ rc = pRoot->xOpen(pRoot, zName, p->pReal, flags, pOutFlags);
+ vfstraceOnOff(pInfo, VTR_OPEN);
+ vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
+ pInfo->zVfsName, p->zFName, flags);
+ if( p->pReal->pMethods ){
+ sqlite3_io_methods *pNew = sqlite3_malloc( sizeof(*pNew) );
+ const sqlite3_io_methods *pSub = p->pReal->pMethods;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->iVersion = pSub->iVersion;
+ pNew->xClose = vfstraceClose;
+ pNew->xRead = vfstraceRead;
+ pNew->xWrite = vfstraceWrite;
+ pNew->xTruncate = vfstraceTruncate;
+ pNew->xSync = vfstraceSync;
+ pNew->xFileSize = vfstraceFileSize;
+ pNew->xLock = vfstraceLock;
+ pNew->xUnlock = vfstraceUnlock;
+ pNew->xCheckReservedLock = vfstraceCheckReservedLock;
+ pNew->xFileControl = vfstraceFileControl;
+ pNew->xSectorSize = vfstraceSectorSize;
+ pNew->xDeviceCharacteristics = vfstraceDeviceCharacteristics;
+ if( pNew->iVersion>=2 ){
+ pNew->xShmMap = pSub->xShmMap ? vfstraceShmMap : 0;
+ pNew->xShmLock = pSub->xShmLock ? vfstraceShmLock : 0;
+ pNew->xShmBarrier = pSub->xShmBarrier ? vfstraceShmBarrier : 0;
+ pNew->xShmUnmap = pSub->xShmUnmap ? vfstraceShmUnmap : 0;
+ }
+ if( pNew->iVersion>=3 ){
+ pNew->xFetch = pSub->xFetch ? vfstraceFetch : 0;
+ pNew->xUnfetch = pSub->xUnfetch ? vfstraceUnfetch : 0;
+ }
+ pFile->pMethods = pNew;
+ }
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
+ if( pOutFlags ){
+ vfstrace_printf(pInfo, ", outFlags=0x%x\n", *pOutFlags);
+ }else{
+ vfstrace_printf(pInfo, "\n");
+ }
+ return rc;
+}
+
+/*
+** 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 vfstraceDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_DELETE);
+ vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
+ pInfo->zVfsName, zPath, dirSync);
+ rc = pRoot->xDelete(pRoot, zPath, dirSync);
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
+ return rc;
+}
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int vfstraceAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_ACCESS);
+ vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)",
+ pInfo->zVfsName, zPath, flags);
+ rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
+ vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
+ return rc;
+}
+
+/*
+** 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 (DEVSYM_MAX_PATHNAME+1) bytes.
+*/
+static int vfstraceFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_FULLPATH);
+ vfstrace_printf(pInfo, "%s.xFullPathname(\"%s\")",
+ pInfo->zVfsName, zPath);
+ rc = pRoot->xFullPathname(pRoot, zPath, nOut, zOut);
+ vfstrace_print_errcode(pInfo, " -> %s", rc);
+ vfstrace_printf(pInfo, ", out=\"%.*s\"\n", nOut, zOut);
+ return rc;
+}
+
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *vfstraceDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ vfstraceOnOff(pInfo, VTR_DLOPEN);
+ vfstrace_printf(pInfo, "%s.xDlOpen(\"%s\")\n", pInfo->zVfsName, zPath);
+ return pRoot->xDlOpen(pRoot, 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 vfstraceDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ vfstraceOnOff(pInfo, VTR_DLERR);
+ vfstrace_printf(pInfo, "%s.xDlError(%d)", pInfo->zVfsName, nByte);
+ pRoot->xDlError(pRoot, nByte, zErrMsg);
+ vfstrace_printf(pInfo, " -> \"%s\"", zErrMsg);
+}
+
+/*
+** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
+*/
+static void (*vfstraceDlSym(sqlite3_vfs *pVfs,void *p,const char *zSym))(void){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ vfstrace_printf(pInfo, "%s.xDlSym(\"%s\")\n", pInfo->zVfsName, zSym);
+ return pRoot->xDlSym(pRoot, p, zSym);
+}
+
+/*
+** Close the dynamic library handle pHandle.
+*/
+static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ vfstraceOnOff(pInfo, VTR_DLCLOSE);
+ vfstrace_printf(pInfo, "%s.xDlClose()\n", pInfo->zVfsName);
+ pRoot->xDlClose(pRoot, pHandle);
+}
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int vfstraceRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ vfstraceOnOff(pInfo, VTR_RAND);
+ vfstrace_printf(pInfo, "%s.xRandomness(%d)\n", pInfo->zVfsName, nByte);
+ return pRoot->xRandomness(pRoot, nByte, zBufOut);
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int vfstraceSleep(sqlite3_vfs *pVfs, int nMicro){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ vfstraceOnOff(pInfo, VTR_SLEEP);
+ vfstrace_printf(pInfo, "%s.xSleep(%d)\n", pInfo->zVfsName, nMicro);
+ return pRoot->xSleep(pRoot, nMicro);
+}
+
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int vfstraceCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_CURTIME);
+ vfstrace_printf(pInfo, "%s.xCurrentTime()", pInfo->zVfsName);
+ rc = pRoot->xCurrentTime(pRoot, pTimeOut);
+ vfstrace_printf(pInfo, " -> %.17g\n", *pTimeOut);
+ return rc;
+}
+static int vfstraceCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_CURTIME);
+ vfstrace_printf(pInfo, "%s.xCurrentTimeInt64()", pInfo->zVfsName);
+ rc = pRoot->xCurrentTimeInt64(pRoot, pTimeOut);
+ vfstrace_printf(pInfo, " -> %lld\n", *pTimeOut);
+ return rc;
+}
+
+/*
+** Return the most recent error code and message
+*/
+static int vfstraceGetLastError(sqlite3_vfs *pVfs, int nErr, char *zErr){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ int rc;
+ vfstraceOnOff(pInfo, VTR_LASTERR);
+ vfstrace_printf(pInfo, "%s.xGetLastError(%d,zBuf)", pInfo->zVfsName, nErr);
+ if( nErr ) zErr[0] = 0;
+ rc = pRoot->xGetLastError(pRoot, nErr, zErr);
+ vfstrace_printf(pInfo, " -> zBuf[] = \"%s\", rc = %d\n", nErr?zErr:"", rc);
+ return rc;
+}
+
+/*
+** Override system calls.
+*/
+static int vfstraceSetSystemCall(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_syscall_ptr pFunc
+){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ return pRoot->xSetSystemCall(pRoot, zName, pFunc);
+}
+static sqlite3_syscall_ptr vfstraceGetSystemCall(
+ sqlite3_vfs *pVfs,
+ const char *zName
+){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ return pRoot->xGetSystemCall(pRoot, zName);
+}
+static const char *vfstraceNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
+ vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
+ sqlite3_vfs *pRoot = pInfo->pRootVfs;
+ return pRoot->xNextSystemCall(pRoot, zName);
+}
+
+
+/*
+** Clients invoke this routine to construct a new trace-vfs shim.
+**
+** Return SQLITE_OK on success.
+**
+** SQLITE_NOMEM is returned in the case of a memory allocation error.
+** SQLITE_NOTFOUND is returned if zOldVfsName does not exist.
+*/
+int vfstrace_register(
+ const char *zTraceName, /* Name of the newly constructed VFS */
+ const char *zOldVfsName, /* Name of the underlying VFS */
+ int (*xOut)(const char*,void*), /* Output routine. ex: fputs */
+ void *pOutArg, /* 2nd argument to xOut. ex: stderr */
+ int makeDefault /* True to make the new VFS the default */
+){
+ sqlite3_vfs *pNew;
+ sqlite3_vfs *pRoot;
+ vfstrace_info *pInfo;
+ size_t nName;
+ size_t nByte;
+
+ pRoot = sqlite3_vfs_find(zOldVfsName);
+ if( pRoot==0 ) return SQLITE_NOTFOUND;
+ nName = strlen(zTraceName);
+ nByte = sizeof(*pNew) + sizeof(*pInfo) + nName + 1;
+ pNew = sqlite3_malloc64( nByte );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, nByte);
+ pInfo = (vfstrace_info*)&pNew[1];
+ pNew->iVersion = pRoot->iVersion;
+ pNew->szOsFile = pRoot->szOsFile + sizeof(vfstrace_file);
+ pNew->mxPathname = pRoot->mxPathname;
+ pNew->zName = (char*)&pInfo[1];
+ memcpy((char*)&pInfo[1], zTraceName, nName+1);
+ pNew->pAppData = pInfo;
+ pNew->xOpen = vfstraceOpen;
+ pNew->xDelete = vfstraceDelete;
+ pNew->xAccess = vfstraceAccess;
+ pNew->xFullPathname = vfstraceFullPathname;
+ pNew->xDlOpen = pRoot->xDlOpen==0 ? 0 : vfstraceDlOpen;
+ pNew->xDlError = pRoot->xDlError==0 ? 0 : vfstraceDlError;
+ pNew->xDlSym = pRoot->xDlSym==0 ? 0 : vfstraceDlSym;
+ pNew->xDlClose = pRoot->xDlClose==0 ? 0 : vfstraceDlClose;
+ pNew->xRandomness = vfstraceRandomness;
+ pNew->xSleep = vfstraceSleep;
+ pNew->xCurrentTime = vfstraceCurrentTime;
+ pNew->xGetLastError = pRoot->xGetLastError==0 ? 0 : vfstraceGetLastError;
+ if( pNew->iVersion>=2 ){
+ pNew->xCurrentTimeInt64 = pRoot->xCurrentTimeInt64==0 ? 0 :
+ vfstraceCurrentTimeInt64;
+ if( pNew->iVersion>=3 ){
+ pNew->xSetSystemCall = pRoot->xSetSystemCall==0 ? 0 :
+ vfstraceSetSystemCall;
+ pNew->xGetSystemCall = pRoot->xGetSystemCall==0 ? 0 :
+ vfstraceGetSystemCall;
+ pNew->xNextSystemCall = pRoot->xNextSystemCall==0 ? 0 :
+ vfstraceNextSystemCall;
+ }
+ }
+ pInfo->pRootVfs = pRoot;
+ pInfo->xOut = xOut;
+ pInfo->pOutArg = pOutArg;
+ pInfo->zVfsName = pNew->zName;
+ pInfo->pTraceVfs = pNew;
+ pInfo->mTrace = 0xffffffff;
+ pInfo->bOn = 1;
+ vfstrace_printf(pInfo, "%s.enabled_for(\"%s\")\n",
+ pInfo->zVfsName, pRoot->zName);
+ return sqlite3_vfs_register(pNew, makeDefault);
+}
+
+/*
+** Look for the named VFS. If it is a TRACEVFS, then unregister it
+** and delete it.
+*/
+void vfstrace_unregister(const char *zTraceName){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(zTraceName);
+ if( pVfs==0 ) return;
+ if( pVfs->xOpen!=vfstraceOpen ) return;
+ sqlite3_vfs_unregister(pVfs);
+ sqlite3_free(pVfs);
+}
+
+/************************* End ../ext/misc/vfstrace.c ********************/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
#define SQLITE_SHELL_HAVE_RECOVER 1
@@ -16129,6 +18362,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
** near the end of a corrupt record. */
rc = dbdataBufferSize(&pCsr->rec, nPayload+DBDATA_PADDING_BYTES);
if( rc!=SQLITE_OK ) return rc;
+ assert( pCsr->rec.aBuf!=0 );
assert( nPayload!=0 );
/* Load the nLocal bytes of payload */
@@ -16457,6 +18691,9 @@ static int sqlite3DbdataRegister(sqlite3 *db){
return rc;
}
+#ifdef _WIN32
+
+#endif
int sqlite3_dbdata_init(
sqlite3 *db,
char **pzErrMsg,
@@ -16505,6 +18742,16 @@ int sqlite3_dbdata_init(sqlite3*, char**, const sqlite3_api_routines*);
/* typedef unsigned char u8; */
/* typedef sqlite3_int64 i64; */
+/*
+** Work around C99 "flex-array" syntax for pre-C99 compilers, so as
+** to avoid complaints from -fsanitize=strict-bounds.
+*/
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
+#endif
+
typedef struct RecoverTable RecoverTable;
typedef struct RecoverColumn RecoverColumn;
@@ -16612,9 +18859,12 @@ struct RecoverColumn {
typedef struct RecoverBitmap RecoverBitmap;
struct RecoverBitmap {
i64 nPg; /* Size of bitmap */
- u32 aElem[1]; /* Array of 32-bit bitmasks */
+ u32 aElem[FLEXARRAY]; /* Array of 32-bit bitmasks */
};
+/* Size in bytes of a RecoverBitmap object sufficient to cover 32 pages */
+#define SZ_RECOVERBITMAP_32 (16)
+
/*
** State variables (part of the sqlite3_recover structure) used while
** recovering data for tables identified in the recovered schema (state
@@ -16854,7 +19104,7 @@ static int recoverError(
*/
static RecoverBitmap *recoverBitmapAlloc(sqlite3_recover *p, i64 nPg){
int nElem = (nPg+1+31) / 32;
- int nByte = sizeof(RecoverBitmap) + nElem*sizeof(u32);
+ int nByte = SZ_RECOVERBITMAP_32 + nElem*sizeof(u32);
RecoverBitmap *pRet = (RecoverBitmap*)recoverMalloc(p, nByte);
if( pRet ){
@@ -17216,7 +19466,7 @@ static const char *recoverUnusedString(
}
/*
-** Implementation of scalar SQL function "escape_crnl". The argument passed to
+** Implementation of scalar SQL function "escape_crlf". 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"
@@ -17227,7 +19477,7 @@ static const char *recoverUnusedString(
** Or, if the first character of the input is not "'", then a copy of the input
** is returned.
*/
-static void recoverEscapeCrnl(
+static void recoverEscapeCrlf(
sqlite3_context *context,
int argc,
sqlite3_value **argv
@@ -17442,7 +19692,7 @@ static int recoverOpenOutput(sqlite3_recover *p){
{ "getpage", 1, recoverGetPage },
{ "page_is_used", 1, recoverPageIsUsed },
{ "read_i32", 2, recoverReadI32 },
- { "escape_crnl", 1, recoverEscapeCrnl },
+ { "escape_crlf", 1, recoverEscapeCrlf },
};
const int flags = SQLITE_OPEN_URI|SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
@@ -17795,7 +20045,7 @@ static sqlite3_stmt *recoverInsertStmt(
if( bSql ){
zBind = recoverMPrintf(p,
- "%z%sescape_crnl(quote(?%d))", zBind, zSqlSep, pTab->aCol[ii].iBind
+ "%z%sescape_crlf(quote(?%d))", zBind, zSqlSep, pTab->aCol[ii].iBind
);
zSqlSep = "||', '||";
}else{
@@ -18297,6 +20547,8 @@ static int recoverWriteDataStep(sqlite3_recover *p){
recoverError(p, SQLITE_NOMEM, 0);
}
p1->nVal = iField+1;
+ }else if( pTab->nCol==0 ){
+ p1->nVal = pTab->nCol;
}
p1->iPrevCell = iCell;
p1->iPrevPage = iPage;
@@ -19044,37 +21296,53 @@ static void recoverUninstallWrapper(sqlite3_recover *p){
static void recoverStep(sqlite3_recover *p){
assert( p && p->errCode==SQLITE_OK );
switch( p->eState ){
- case RECOVER_STATE_INIT:
+ case RECOVER_STATE_INIT: {
+ int bUseWrapper = 1;
/* This is the very first call to sqlite3_recover_step() on this object.
*/
recoverSqlCallback(p, "BEGIN");
recoverSqlCallback(p, "PRAGMA writable_schema = on");
+ recoverSqlCallback(p, "PRAGMA foreign_keys = off");
recoverEnterMutex();
- recoverInstallWrapper(p);
/* Open the output database. And register required virtual tables and
** user functions with the new handle. */
recoverOpenOutput(p);
- /* Open transactions on both the input and output databases. */
- sqlite3_file_control(p->dbIn, p->zDb, SQLITE_FCNTL_RESET_CACHE, 0);
- recoverExec(p, p->dbIn, "PRAGMA writable_schema = on");
- recoverExec(p, p->dbIn, "BEGIN");
- if( p->errCode==SQLITE_OK ) p->bCloseTransaction = 1;
- recoverExec(p, p->dbIn, "SELECT 1 FROM sqlite_schema");
- recoverTransferSettings(p);
- recoverOpenRecovery(p);
- recoverCacheSchema(p);
-
- recoverUninstallWrapper(p);
- recoverLeaveMutex();
+ /* Attempt to open a transaction and read page 1 of the input database.
+ ** Two attempts may be made - one with a wrapper installed to ensure
+ ** that the database header is sane, and then if that attempt returns
+ ** SQLITE_NOTADB, then again with no wrapper. The second attempt is
+ ** required for encrypted databases. */
+ if( p->errCode==SQLITE_OK ){
+ do{
+ p->errCode = SQLITE_OK;
+ if( bUseWrapper ) recoverInstallWrapper(p);
+
+ /* Open a transaction on the input database. */
+ sqlite3_file_control(p->dbIn, p->zDb, SQLITE_FCNTL_RESET_CACHE, 0);
+ recoverExec(p, p->dbIn, "PRAGMA writable_schema = on");
+ recoverExec(p, p->dbIn, "BEGIN");
+ if( p->errCode==SQLITE_OK ) p->bCloseTransaction = 1;
+ recoverExec(p, p->dbIn, "SELECT 1 FROM sqlite_schema");
+ recoverTransferSettings(p);
+ recoverOpenRecovery(p);
+ recoverCacheSchema(p);
+
+ if( bUseWrapper ) recoverUninstallWrapper(p);
+ }while( p->errCode==SQLITE_NOTADB
+ && (bUseWrapper--)
+ && SQLITE_OK==sqlite3_exec(p->dbIn, "ROLLBACK", 0, 0, 0)
+ );
+ }
+ recoverLeaveMutex();
recoverExec(p, p->dbOut, "BEGIN");
-
recoverWriteSchema1(p);
p->eState = RECOVER_STATE_WRITING;
break;
+ }
case RECOVER_STATE_WRITING: {
if( p->w1.pTbls==0 ){
@@ -19412,6 +21680,8 @@ struct ShellState {
u8 bSafeMode; /* True to prohibit unsafe operations */
u8 bSafeModePersist; /* The long-term value of bSafeMode */
u8 eRestoreState; /* See comments above doAutoDetectRestore() */
+ u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */
+ u8 eEscMode; /* Escape mode for text output */
ColModeOpts cmOpts; /* Option values affecting columnar mode output */
unsigned statsOn; /* True to display memory stats before each finalize */
unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
@@ -19512,6 +21782,15 @@ static ShellState shellState;
** top-level SQL statement */
#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
+/* Allowed values for ShellState.eEscMode. The default value should
+** be 0, so to change the default, reorder the names.
+*/
+#define SHELL_ESC_ASCII 0 /* Substitute ^Y for X where Y=X+0x40 */
+#define SHELL_ESC_SYMBOL 1 /* Substitute U+2400 graphics */
+#define SHELL_ESC_OFF 2 /* Send characters verbatim */
+
+static const char *shell_EscModeNames[] = { "ascii", "symbol", "off" };
+
/*
** These are the allowed shellFlgs values
*/
@@ -19557,6 +21836,7 @@ static ShellState shellState;
#define MODE_Count 17 /* Output only a count of the rows of output */
#define MODE_Off 18 /* No query output shown */
#define MODE_ScanExp 19 /* Like MODE_Explain, but for ".scanstats vm" */
+#define MODE_Www 20 /* Full web-page output */
static const char *modeDescr[] = {
"line",
@@ -19577,7 +21857,9 @@ static const char *modeDescr[] = {
"table",
"box",
"count",
- "off"
+ "off",
+ "scanexp",
+ "www",
};
/*
@@ -19605,7 +21887,7 @@ static const char *modeDescr[] = {
static void shellLog(void *pArg, int iErrCode, const char *zMsg){
ShellState *p = (ShellState*)pArg;
if( p->pLog==0 ) return;
- sputf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
+ sqlite3_fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
fflush(p->pLog);
}
@@ -19620,9 +21902,9 @@ static void shellPutsFunc(
int nVal,
sqlite3_value **apVal
){
- /* Unused: (ShellState*)sqlite3_user_data(pCtx); */
+ ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
(void)nVal;
- oputf("%s\n", sqlite3_value_text(apVal[0]));
+ sqlite3_fprintf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
sqlite3_result_value(pCtx, apVal[0]);
}
@@ -19641,7 +21923,7 @@ static void failIfSafeMode(
va_start(ap, zErrMsg);
zMsg = sqlite3_vmprintf(zErrMsg, ap);
va_end(ap);
- eputf("line %d: %s\n", p->lineno, zMsg);
+ sqlite3_fprintf(stderr, "line %d: %s\n", p->lineno, zMsg);
exit(1);
}
}
@@ -19674,7 +21956,7 @@ static void editFunc(
char *zCmd = 0;
int bBin;
int rc;
- int hasCRNL = 0;
+ int hasCRLF = 0;
FILE *f = 0;
sqlite3_int64 sz;
sqlite3_int64 x;
@@ -19708,7 +21990,7 @@ static void editFunc(
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");
+ f = sqlite3_fopen(zTempFile, bBin ? "wb" : "w");
if( f==0 ){
sqlite3_result_error(context, "edit() cannot open temp file", -1);
goto edit_func_end;
@@ -19719,7 +22001,7 @@ static void editFunc(
}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;
+ if( z && strstr(z,"\r\n")!=0 ) hasCRLF = 1;
x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
}
fclose(f);
@@ -19739,7 +22021,7 @@ static void editFunc(
sqlite3_result_error(context, "EDITOR returned non-zero", -1);
goto edit_func_end;
}
- f = fopen(zTempFile, "rb");
+ f = sqlite3_fopen(zTempFile, "rb");
if( f==0 ){
sqlite3_result_error(context,
"edit() cannot reopen temp file after edit", -1);
@@ -19764,7 +22046,7 @@ static void editFunc(
sqlite3_result_blob64(context, p, sz, sqlite3_free);
}else{
sqlite3_int64 i, j;
- if( hasCRNL ){
+ if( hasCRLF ){
/* If the original contains \r\n then do no conversions back to \n */
}else{
/* If the file did not originally contain \r\n then convert any new
@@ -19807,9 +22089,24 @@ static void outputModePop(ShellState *p){
}
/*
+** Set output mode to text or binary for Windows.
+*/
+static void setCrlfMode(ShellState *p){
+#ifdef _WIN32
+ if( p->crlfMode ){
+ sqlite3_fsetmode(p->out, _O_TEXT);
+ }else{
+ sqlite3_fsetmode(p->out, _O_BINARY);
+ }
+#else
+ UNUSED_PARAMETER(p);
+#endif
+}
+
+/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/
-static void output_hex_blob(const void *pBlob, int nBlob){
+static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
int i;
unsigned char *aBlob = (unsigned char*)pBlob;
@@ -19826,72 +22123,82 @@ static void output_hex_blob(const void *pBlob, int nBlob){
}
zStr[i*2] = '\0';
- oputf("X'%s'", zStr);
+ sqlite3_fprintf(out, "X'%s'", zStr);
sqlite3_free(zStr);
}
/*
-** Find a string that is not found anywhere in z[]. Return a pointer
-** to that string.
+** Output the given string as a quoted string using SQL quoting conventions:
**
-** 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.
+** (1) Single quotes (') within the string are doubled
+** (2) The whle string is enclosed in '...'
+** (3) Control characters other than \n, \t, and \r\n are escaped
+** using \u00XX notation and if such substitutions occur,
+** the whole string is enclosed in unistr('...') instead of '...'.
+**
+** Step (3) is omitted if the control-character escape mode is OFF.
**
-** See also: output_quoted_escaped_string()
+** See also: output_quoted_escaped_string() which does the same except
+** that it does not make exceptions for \n, \t, and \r\n in step (3).
*/
-static void output_quoted_string(const char *z){
+static void output_quoted_string(ShellState *p, const char *zInX){
int i;
- char c;
-#ifndef SQLITE_SHELL_FIDDLE
- FILE *pfO = setOutputStream(invalidFileStream);
- setBinaryMode(pfO, 1);
-#endif
+ int needUnistr = 0;
+ int needDblQuote = 0;
+ const unsigned char *z = (const unsigned char*)zInX;
+ unsigned char c;
+ FILE *out = p->out;
+ sqlite3_fsetmode(out, _O_BINARY);
if( z==0 ) return;
- for(i=0; (c = z[i])!=0 && c!='\''; i++){}
- if( c==0 ){
- oputf("'%s'",z);
+ for(i=0; (c = z[i])!=0; i++){
+ if( c=='\'' ){ needDblQuote = 1; }
+ if( c>0x1f ) continue;
+ if( c=='\t' || c=='\n' ) continue;
+ if( c=='\r' && z[i+1]=='\n' ) continue;
+ needUnistr = 1;
+ break;
+ }
+ if( (needDblQuote==0 && needUnistr==0)
+ || (needDblQuote==0 && p->eEscMode==SHELL_ESC_OFF)
+ ){
+ sqlite3_fprintf(out, "'%s'",z);
+ }else if( p->eEscMode==SHELL_ESC_OFF ){
+ char *zEncoded = sqlite3_mprintf("%Q", z);
+ sqlite3_fputs(zEncoded, out);
+ sqlite3_free(zEncoded);
}else{
- oputz("'");
+ if( needUnistr ){
+ sqlite3_fputs("unistr('", out);
+ }else{
+ sqlite3_fputs("'", out);
+ }
while( *z ){
- for(i=0; (c = z[i])!=0 && c!='\''; i++){}
- if( c=='\'' ) i++;
+ for(i=0; (c = z[i])!=0; i++){
+ if( c=='\'' ) break;
+ if( c>0x1f ) continue;
+ if( c=='\t' || c=='\n' ) continue;
+ if( c=='\r' && z[i+1]=='\n' ) continue;
+ break;
+ }
if( i ){
- oputf("%.*s", i, z);
+ sqlite3_fprintf(out, "%.*s", i, z);
z += i;
}
+ if( c==0 ) break;
if( c=='\'' ){
- oputz("'");
- continue;
- }
- if( c==0 ){
- break;
+ sqlite3_fputs("''", out);
+ }else{
+ sqlite3_fprintf(out, "\\u%04x", c);
}
z++;
}
- oputz("'");
+ if( needUnistr ){
+ sqlite3_fputs("')", out);
+ }else{
+ sqlite3_fputs("'", out);
+ }
}
-#ifndef SQLITE_SHELL_FIDDLE
- setTextMode(pfO, 1);
-#else
- setTextMode(stdout, 1);
-#endif
+ setCrlfMode(p);
}
/*
@@ -19903,69 +22210,17 @@ static void output_quoted_string(const char *z){
** This is like output_quoted_string() but with the addition of the \r\n
** escape mechanism.
*/
-static void output_quoted_escaped_string(const char *z){
- int i;
- char c;
-#ifndef SQLITE_SHELL_FIDDLE
- FILE *pfO = setOutputStream(invalidFileStream);
- setBinaryMode(pfO, 1);
-#endif
- for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
- if( c==0 ){
- oputf("'%s'",z);
+static void output_quoted_escaped_string(ShellState *p, const char *z){
+ char *zEscaped;
+ sqlite3_fsetmode(p->out, _O_BINARY);
+ if( p->eEscMode==SHELL_ESC_OFF ){
+ zEscaped = sqlite3_mprintf("%Q", z);
}else{
- 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 ){
- oputz("replace(");
- zNL = unused_string(z, "\\n", "\\012", zBuf1);
- }
- if( nCR ){
- oputz("replace(");
- zCR = unused_string(z, "\\r", "\\015", zBuf2);
- }
- oputz("'");
- while( *z ){
- for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
- if( c=='\'' ) i++;
- if( i ){
- oputf("%.*s", i, z);
- z += i;
- }
- if( c=='\'' ){
- oputz("'");
- continue;
- }
- if( c==0 ){
- break;
- }
- z++;
- if( c=='\n' ){
- oputz(zNL);
- continue;
- }
- oputz(zCR);
- }
- oputz("'");
- if( nCR ){
- oputf(",'%s',char(13))", zCR);
- }
- if( nNL ){
- oputf(",'%s',char(10))", zNL);
- }
+ zEscaped = sqlite3_mprintf("%#Q", z);
}
-#ifndef SQLITE_SHELL_FIDDLE
- setTextMode(pfO, 1);
-#else
- setTextMode(stdout, 1);
-#endif
+ sqlite3_fputs(zEscaped, p->out);
+ sqlite3_free(zEscaped);
+ setCrlfMode(p);
}
/*
@@ -19985,22 +22240,60 @@ static const char *anyOfInStr(const char *s, const char *zAny, size_t ns){
}
return pcFirst;
}
+
+/* Skip over as much z[] input char sequence as is valid UTF-8,
+** limited per nAccept char's or whole characters and containing
+** no char cn such that ((1<<cn) & ccm)!=0. On return, the
+** sequence z:return (inclusive:exclusive) is validated UTF-8.
+** Limit: nAccept>=0 => char count, nAccept<0 => character
+ */
+const char *zSkipValidUtf8(const char *z, int nAccept, long ccm){
+ int ng = (nAccept<0)? -nAccept : 0;
+ const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
+ assert(z!=0);
+ while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
+ unsigned char c = *(u8*)z;
+ if( c<0x7f ){
+ if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
+ ++z; /* ASCII */
+ }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
+ else{
+ const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
+ do{
+ if( pcLimit && zt >= pcLimit ) return z;
+ else{
+ char ct = *zt++;
+ if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
+ /* Trailing bytes are too few, too many, or invalid. */
+ return z;
+ }
+ }
+ } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
+ z = zt;
+ }
+ }
+ return z;
+}
+
+
/*
** Output the given string as a quoted according to C or TCL quoting rules.
*/
-static void output_c_string(const char *z){
+static void output_c_string(FILE *out, const char *z){
char c;
static const char *zq = "\"";
static long ctrlMask = ~0L;
static const char *zDQBSRO = "\"\\\x7f"; /* double-quote, backslash, rubout */
char ace[3] = "\\?";
char cbsSay;
- oputz(zq);
+ sqlite3_fputs(zq, out);
while( *z!=0 ){
const char *pcDQBSRO = anyOfInStr(z, zDQBSRO, ~(size_t)0);
const char *pcPast = zSkipValidUtf8(z, INT_MAX, ctrlMask);
const char *pcEnd = (pcDQBSRO && pcDQBSRO < pcPast)? pcDQBSRO : pcPast;
- if( pcEnd > z ) oputb(z, (int)(pcEnd-z));
+ if( pcEnd > z ){
+ sqlite3_fprintf(out, "%.*s", (int)(pcEnd-z), z);
+ }
if( (c = *pcEnd)==0 ) break;
++pcEnd;
switch( c ){
@@ -20015,23 +22308,23 @@ static void output_c_string(const char *z){
}
if( cbsSay ){
ace[1] = cbsSay;
- oputz(ace);
+ sqlite3_fputs(ace, out);
}else if( !isprint(c&0xff) ){
- oputf("\\%03o", c&0xff);
+ sqlite3_fprintf(out, "\\%03o", c&0xff);
}else{
ace[1] = (char)c;
- oputz(ace+1);
+ sqlite3_fputs(ace+1, out);
}
z = pcEnd;
}
- oputz(zq);
+ sqlite3_fputs(zq, out);
}
/*
-** Output the given string as a quoted according to JSON quoting rules.
+** Output the given string as quoted according to JSON quoting rules.
*/
-static void output_json_string(const char *z, i64 n){
- char c;
+static void output_json_string(FILE *out, const char *z, i64 n){
+ unsigned char c;
static const char *zq = "\"";
static long ctrlMask = ~0L;
static const char *zDQBS = "\"\\";
@@ -20041,17 +22334,17 @@ static void output_json_string(const char *z, i64 n){
if( z==0 ) z = "";
pcLimit = z + ((n<0)? strlen(z) : (size_t)n);
- oputz(zq);
+ sqlite3_fputs(zq, out);
while( z < pcLimit ){
const char *pcDQBS = anyOfInStr(z, zDQBS, pcLimit-z);
const char *pcPast = zSkipValidUtf8(z, (int)(pcLimit-z), ctrlMask);
const char *pcEnd = (pcDQBS && pcDQBS < pcPast)? pcDQBS : pcPast;
if( pcEnd > z ){
- oputb(z, (int)(pcEnd-z));
+ sqlite3_fprintf(out, "%.*s", (int)(pcEnd-z), z);
z = pcEnd;
}
if( z >= pcLimit ) break;
- c = *(z++);
+ c = (unsigned char)*(z++);
switch( c ){
case '"': case '\\':
cbsSay = (char)c;
@@ -20065,22 +22358,109 @@ static void output_json_string(const char *z, i64 n){
}
if( cbsSay ){
ace[1] = cbsSay;
- oputz(ace);
- }else if( c<=0x1f ){
- oputf("u%04x", c);
+ sqlite3_fputs(ace, out);
+ }else if( c<=0x1f || c>=0x7f ){
+ sqlite3_fprintf(out, "\\u%04x", c);
}else{
ace[1] = (char)c;
- oputz(ace+1);
+ sqlite3_fputs(ace+1, out);
+ }
+ }
+ sqlite3_fputs(zq, out);
+}
+
+/*
+** Escape the input string if it is needed and in accordance with
+** eEscMode.
+**
+** Escaping is needed if the string contains any control characters
+** other than \t, \n, and \r\n
+**
+** If no escaping is needed (the common case) then set *ppFree to NULL
+** and return the original string. If escapingn is needed, write the
+** escaped string into memory obtained from sqlite3_malloc64() or the
+** equivalent, and return the new string and set *ppFree to the new string
+** as well.
+**
+** The caller is responsible for freeing *ppFree if it is non-NULL in order
+** to reclaim memory.
+*/
+static const char *escapeOutput(
+ ShellState *p,
+ const char *zInX,
+ char **ppFree
+){
+ i64 i, j;
+ i64 nCtrl = 0;
+ unsigned char *zIn;
+ unsigned char c;
+ unsigned char *zOut;
+
+
+ /* No escaping if disabled */
+ if( p->eEscMode==SHELL_ESC_OFF ){
+ *ppFree = 0;
+ return zInX;
+ }
+
+ /* Count the number of control characters in the string. */
+ zIn = (unsigned char*)zInX;
+ for(i=0; (c = zIn[i])!=0; i++){
+ if( c<=0x1f
+ && c!='\t'
+ && c!='\n'
+ && (c!='\r' || zIn[i+1]!='\n')
+ ){
+ nCtrl++;
+ }
+ }
+ if( nCtrl==0 ){
+ *ppFree = 0;
+ return zInX;
+ }
+ if( p->eEscMode==SHELL_ESC_SYMBOL ) nCtrl *= 2;
+ zOut = sqlite3_malloc64( i + nCtrl + 1 );
+ shell_check_oom(zOut);
+ for(i=j=0; (c = zIn[i])!=0; i++){
+ if( c>0x1f
+ || c=='\t'
+ || c=='\n'
+ || (c=='\r' && zIn[i+1]=='\n')
+ ){
+ continue;
}
+ if( i>0 ){
+ memcpy(&zOut[j], zIn, i);
+ j += i;
+ }
+ zIn += i+1;
+ i = -1;
+ switch( p->eEscMode ){
+ case SHELL_ESC_SYMBOL:
+ zOut[j++] = 0xe2;
+ zOut[j++] = 0x90;
+ zOut[j++] = 0x80+c;
+ break;
+ case SHELL_ESC_ASCII:
+ zOut[j++] = '^';
+ zOut[j++] = 0x40+c;
+ break;
+ }
+ }
+ if( i>0 ){
+ memcpy(&zOut[j], zIn, i);
+ j += i;
}
- oputz(zq);
+ zOut[j] = 0;
+ *ppFree = (char*)zOut;
+ return (char*)zOut;
}
/*
** Output the given string with characters that are special to
** HTML escaped.
*/
-static void output_html_string(const char *z){
+static void output_html_string(FILE *out, const char *z){
int i;
if( z==0 ) z = "";
while( *z ){
@@ -20092,18 +22472,18 @@ static void output_html_string(const char *z){
&& z[i]!='\'';
i++){}
if( i>0 ){
- oputf("%.*s",i,z);
+ sqlite3_fprintf(out, "%.*s",i,z);
}
if( z[i]=='<' ){
- oputz("&lt;");
+ sqlite3_fputs("&lt;", out);
}else if( z[i]=='&' ){
- oputz("&amp;");
+ sqlite3_fputs("&amp;", out);
}else if( z[i]=='>' ){
- oputz("&gt;");
+ sqlite3_fputs("&gt;", out);
}else if( z[i]=='\"' ){
- oputz("&quot;");
+ sqlite3_fputs("&quot;", out);
}else if( z[i]=='\'' ){
- oputz("&#39;");
+ sqlite3_fputs("&#39;", out);
}else{
break;
}
@@ -20142,7 +22522,7 @@ static const char needCsvQuote[] = {
*/
static void output_csv(ShellState *p, const char *z, int bSep){
if( z==0 ){
- oputf("%s",p->nullValue);
+ sqlite3_fprintf(p->out, "%s",p->nullValue);
}else{
unsigned i;
for(i=0; z[i]; i++){
@@ -20154,14 +22534,14 @@ static void output_csv(ShellState *p, const char *z, int bSep){
if( i==0 || strstr(z, p->colSeparator)!=0 ){
char *zQuoted = sqlite3_mprintf("\"%w\"", z);
shell_check_oom(zQuoted);
- oputz(zQuoted);
+ sqlite3_fputs(zQuoted, p->out);
sqlite3_free(zQuoted);
}else{
- oputz(z);
+ sqlite3_fputs(z, p->out);
}
}
if( bSep ){
- oputz(p->colSeparator);
+ sqlite3_fputs(p->colSeparator, p->out);
}
}
@@ -20269,16 +22649,16 @@ static int shellAuth(
az[1] = zA2;
az[2] = zA3;
az[3] = zA4;
- oputf("authorizer: %s", azAction[op]);
+ sqlite3_fprintf(p->out, "authorizer: %s", azAction[op]);
for(i=0; i<4; i++){
- oputz(" ");
+ sqlite3_fputs(" ", p->out);
if( az[i] ){
- output_c_string(az[i]);
+ output_c_string(p->out, az[i]);
}else{
- oputz("NULL");
+ sqlite3_fputs("NULL", p->out);
}
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
return SQLITE_OK;
}
@@ -20294,7 +22674,7 @@ static int shellAuth(
** sqlite3_complete() returns false, try to terminate the comment before
** printing the result. https://sqlite.org/forum/forumpost/d7be961c5c
*/
-static void printSchemaLine(const char *z, const char *zTail){
+static void printSchemaLine(FILE *out, const char *z, const char *zTail){
char *zToFree = 0;
if( z==0 ) return;
if( zTail==0 ) return;
@@ -20316,16 +22696,16 @@ static void printSchemaLine(const char *z, const char *zTail){
}
}
if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
- oputf("CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
+ sqlite3_fprintf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
}else{
- oputf("%s%s", z, zTail);
+ sqlite3_fprintf(out, "%s%s", z, zTail);
}
sqlite3_free(zToFree);
}
-static void printSchemaLineN(char *z, int n, const char *zTail){
+static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
char c = z[n];
z[n] = 0;
- printSchemaLine(z, zTail);
+ printSchemaLine(out, z, zTail);
z[n] = c;
}
@@ -20353,7 +22733,7 @@ static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
if( zText==0 ) return;
nText = strlen(zText);
if( p->autoEQPtest ){
- oputf("%d,%d,%s\n", iEqpId, p2, zText);
+ sqlite3_fprintf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
}
pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
shell_check_oom(pNew);
@@ -20401,7 +22781,8 @@ static void eqp_render_level(ShellState *p, int iEqpId){
for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
pNext = eqp_next_row(p, iEqpId, pRow);
z = pRow->zText;
- oputf("%s%s%s\n", p->sGraph.zPrefix, pNext ? "|--" : "`--", z);
+ sqlite3_fprintf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
+ pNext ? "|--" : "`--", z);
if( n<(i64)sizeof(p->sGraph.zPrefix)-7 ){
memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
eqp_render_level(p, pRow->iEqpId);
@@ -20421,13 +22802,13 @@ static void eqp_render(ShellState *p, i64 nCycle){
eqp_reset(p);
return;
}
- oputf("%s\n", pRow->zText+3);
+ sqlite3_fprintf(p->out, "%s\n", pRow->zText+3);
p->sGraph.pRow = pRow->pNext;
sqlite3_free(pRow);
}else if( nCycle>0 ){
- oputf("QUERY PLAN (cycles=%lld [100%%])\n", nCycle);
+ sqlite3_fprintf(p->out, "QUERY PLAN (cycles=%lld [100%%])\n", nCycle);
}else{
- oputz("QUERY PLAN\n");
+ sqlite3_fputs("QUERY PLAN\n", p->out);
}
p->sGraph.zPrefix[0] = 0;
eqp_render_level(p, 0);
@@ -20443,13 +22824,13 @@ static int progress_handler(void *pClientData) {
ShellState *p = (ShellState*)pClientData;
p->nProgress++;
if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){
- oputf("Progress limit reached (%u)\n", p->nProgress);
+ sqlite3_fprintf(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 ){
- oputf("Progress %u\n", p->nProgress);
+ sqlite3_fprintf(p->out, "Progress %u\n", p->nProgress);
}
return 0;
}
@@ -20458,14 +22839,14 @@ static int progress_handler(void *pClientData) {
/*
** Print N dashes
*/
-static void print_dashes(int N){
+static void print_dashes(FILE *out, int N){
const char zDash[] = "--------------------------------------------------";
const int nDash = sizeof(zDash) - 1;
while( N>nDash ){
- oputz(zDash);
+ sqlite3_fputs(zDash, out);
N -= nDash;
}
- oputf("%.*s", N, zDash);
+ sqlite3_fprintf(out, "%.*s", N, zDash);
}
/*
@@ -20478,15 +22859,15 @@ static void print_row_separator(
){
int i;
if( nArg>0 ){
- oputz(zSep);
- print_dashes(p->actualWidth[0]+2);
+ sqlite3_fputs(zSep, p->out);
+ print_dashes(p->out, p->actualWidth[0]+2);
for(i=1; i<nArg; i++){
- oputz(zSep);
- print_dashes(p->actualWidth[i]+2);
+ sqlite3_fputs(zSep, p->out);
+ print_dashes(p->out, p->actualWidth[i]+2);
}
- oputz(zSep);
+ sqlite3_fputs(zSep, p->out);
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
/*
@@ -20516,10 +22897,14 @@ static int shell_callback(
int len = strlen30(azCol[i] ? azCol[i] : "");
if( len>w ) w = len;
}
- if( p->cnt++>0 ) oputz(p->rowSeparator);
+ if( p->cnt++>0 ) sqlite3_fputs(p->rowSeparator, p->out);
for(i=0; i<nArg; i++){
- oputf("%*s = %s%s", w, azCol[i],
- azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
+ char *pFree = 0;
+ const char *pDisplay;
+ pDisplay = escapeOutput(p, azArg[i] ? azArg[i] : p->nullValue, &pFree);
+ sqlite3_fprintf(p->out, "%*s = %s%s", w, azCol[i],
+ pDisplay, p->rowSeparator);
+ if( pFree ) sqlite3_free(pFree);
}
break;
}
@@ -20527,7 +22912,7 @@ static int shell_callback(
case MODE_Explain: {
static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
static const int aExplainMap[] = {0, 1, 2, 3, 4, 5, 6, 7 };
- static const int aScanExpWidth[] = {4, 6, 6, 13, 4, 4, 4, 13, 2, 13};
+ static const int aScanExpWidth[] = {4, 15, 6, 13, 4, 4, 4, 13, 2, 13};
static const int aScanExpMap[] = {0, 9, 8, 1, 2, 3, 4, 5, 6, 7 };
const int *aWidth = aExplainWidth;
@@ -20546,12 +22931,12 @@ static int shell_callback(
/* If this is the first row seen, print out the headers */
if( p->cnt++==0 ){
for(i=0; i<nArg; i++){
- utf8_width_print(aWidth[i], azCol[ aMap[i] ]);
- oputz(i==nArg-1 ? "\n" : " ");
+ utf8_width_print(p->out, aWidth[i], azCol[ aMap[i] ]);
+ sqlite3_fputs(i==nArg-1 ? "\n" : " ", p->out);
}
for(i=0; i<nArg; i++){
- print_dashes(aWidth[i]);
- oputz(i==nArg-1 ? "\n" : " ");
+ print_dashes(p->out, aWidth[i]);
+ sqlite3_fputs(i==nArg-1 ? "\n" : " ", p->out);
}
}
@@ -20569,17 +22954,17 @@ static int shell_callback(
}
if( i==iIndent && p->aiIndent && p->pStmt ){
if( p->iIndent<p->nIndent ){
- oputf("%*.s", p->aiIndent[p->iIndent], "");
+ sqlite3_fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
}
p->iIndent++;
}
- utf8_width_print(w, zVal ? zVal : p->nullValue);
- oputz(i==nArg-1 ? "\n" : zSep);
+ utf8_width_print(p->out, w, zVal ? zVal : p->nullValue);
+ sqlite3_fputs(i==nArg-1 ? "\n" : zSep, p->out);
}
break;
}
case MODE_Semi: { /* .schema and .fullschema output */
- printSchemaLine(azArg[0], ";\n");
+ printSchemaLine(p->out, azArg[0], ";\n");
break;
}
case MODE_Pretty: { /* .schema and .fullschema with --indent */
@@ -20589,14 +22974,18 @@ static int shell_callback(
char cEnd = 0;
char c;
int nLine = 0;
+ int isIndex;
+ int isWhere = 0;
assert( nArg==1 );
if( azArg[0]==0 ) break;
if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
|| sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
){
- oputf("%s;\n", azArg[0]);
+ sqlite3_fprintf(p->out, "%s;\n", azArg[0]);
break;
}
+ isIndex = sqlite3_strlike("CREATE INDEX%", azArg[0], 0)==0
+ || sqlite3_strlike("CREATE UNIQUE INDEX%", azArg[0], 0)==0;
z = sqlite3_mprintf("%s", azArg[0]);
shell_check_oom(z);
j = 0;
@@ -20626,17 +23015,29 @@ static int shell_callback(
nParen++;
}else if( c==')' ){
nParen--;
- if( nLine>0 && nParen==0 && j>0 ){
- printSchemaLineN(z, j, "\n");
+ if( nLine>0 && nParen==0 && j>0 && !isWhere ){
+ printSchemaLineN(p->out, z, j, "\n");
j = 0;
}
+ }else if( (c=='w' || c=='W')
+ && nParen==0 && isIndex
+ && sqlite3_strnicmp("WHERE",&z[i],5)==0
+ && !IsAlnum(z[i+5]) && z[i+5]!='_' ){
+ isWhere = 1;
+ }else if( isWhere && (c=='A' || c=='a')
+ && nParen==0
+ && sqlite3_strnicmp("AND",&z[i],3)==0
+ && !IsAlnum(z[i+3]) && z[i+3]!='_' ){
+ printSchemaLineN(p->out, z, j, "\n ");
+ j = 0;
}
z[j++] = c;
if( nParen==1 && cEnd==0
&& (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
+ && !isWhere
){
if( c=='\n' ) j--;
- printSchemaLineN(z, j, "\n ");
+ printSchemaLineN(p->out, z, j, "\n ");
j = 0;
nLine++;
while( IsSpace(z[i+1]) ){ i++; }
@@ -20644,118 +23045,136 @@ static int shell_callback(
}
z[j] = 0;
}
- printSchemaLine(z, ";\n");
+ printSchemaLine(p->out, z, ";\n");
sqlite3_free(z);
break;
}
case MODE_List: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- oputf("%s%s",azCol[i], i==nArg-1 ? p->rowSeparator : p->colSeparator);
+ char *z = azCol[i];
+ char *pFree;
+ const char *zOut = escapeOutput(p, z, &pFree);
+ sqlite3_fprintf(p->out, "%s%s", zOut,
+ i==nArg-1 ? p->rowSeparator : p->colSeparator);
+ if( pFree ) sqlite3_free(pFree);
}
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
char *z = azArg[i];
+ char *pFree;
+ const char *zOut;
if( z==0 ) z = p->nullValue;
- oputz(z);
- oputz((i<nArg-1)? p->colSeparator : p->rowSeparator);
+ zOut = escapeOutput(p, z, &pFree);
+ sqlite3_fputs(zOut, p->out);
+ if( pFree ) sqlite3_free(pFree);
+ sqlite3_fputs((i<nArg-1)? p->colSeparator : p->rowSeparator, p->out);
}
break;
}
+ case MODE_Www:
case MODE_Html: {
- if( p->cnt++==0 && p->showHeader ){
- oputz("<TR>");
+ if( p->cnt==0 && p->cMode==MODE_Www ){
+ sqlite3_fputs(
+ "</PRE>\n"
+ "<TABLE border='1' cellspacing='0' cellpadding='2'>\n"
+ ,p->out
+ );
+ }
+ if( p->cnt==0 && (p->showHeader || p->cMode==MODE_Www) ){
+ sqlite3_fputs("<TR>", p->out);
for(i=0; i<nArg; i++){
- oputz("<TH>");
- output_html_string(azCol[i]);
- oputz("</TH>\n");
+ sqlite3_fputs("<TH>", p->out);
+ output_html_string(p->out, azCol[i]);
+ sqlite3_fputs("</TH>\n", p->out);
}
- oputz("</TR>\n");
+ sqlite3_fputs("</TR>\n", p->out);
}
+ p->cnt++;
if( azArg==0 ) break;
- oputz("<TR>");
+ sqlite3_fputs("<TR>", p->out);
for(i=0; i<nArg; i++){
- oputz("<TD>");
- output_html_string(azArg[i] ? azArg[i] : p->nullValue);
- oputz("</TD>\n");
+ sqlite3_fputs("<TD>", p->out);
+ output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
+ sqlite3_fputs("</TD>\n", p->out);
}
- oputz("</TR>\n");
+ sqlite3_fputs("</TR>\n", p->out);
break;
}
case MODE_Tcl: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- output_c_string(azCol[i] ? azCol[i] : "");
- if(i<nArg-1) oputz(p->colSeparator);
+ output_c_string(p->out, azCol[i] ? azCol[i] : "");
+ if(i<nArg-1) sqlite3_fputs(p->colSeparator, p->out);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- output_c_string(azArg[i] ? azArg[i] : p->nullValue);
- if(i<nArg-1) oputz(p->colSeparator);
+ output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
+ if(i<nArg-1) sqlite3_fputs(p->colSeparator, p->out);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
break;
}
case MODE_Csv: {
- setBinaryMode(p->out, 1);
+ sqlite3_fsetmode(p->out, _O_BINARY);
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
if( nArg>0 ){
for(i=0; i<nArg; i++){
output_csv(p, azArg[i], i<nArg-1);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
- setTextMode(p->out, 1);
+ setCrlfMode(p);
break;
}
case MODE_Insert: {
if( azArg==0 ) break;
- oputf("INSERT INTO %s",p->zDestTable);
+ sqlite3_fprintf(p->out, "INSERT INTO %s",p->zDestTable);
if( p->showHeader ){
- oputz("(");
+ sqlite3_fputs("(", p->out);
for(i=0; i<nArg; i++){
- if( i>0 ) oputz(",");
+ if( i>0 ) sqlite3_fputs(",", p->out);
if( quoteChar(azCol[i]) ){
char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
shell_check_oom(z);
- oputz(z);
+ sqlite3_fputs(z, p->out);
sqlite3_free(z);
}else{
- oputf("%s", azCol[i]);
+ sqlite3_fprintf(p->out, "%s", azCol[i]);
}
}
- oputz(")");
+ sqlite3_fputs(")", p->out);
}
p->cnt++;
for(i=0; i<nArg; i++){
- oputz(i>0 ? "," : " VALUES(");
+ sqlite3_fputs(i>0 ? "," : " VALUES(", p->out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- oputz("NULL");
+ sqlite3_fputs("NULL", p->out);
}else if( aiType && aiType[i]==SQLITE_TEXT ){
if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(azArg[i]);
+ output_quoted_string(p, azArg[i]);
}else{
- output_quoted_escaped_string(azArg[i]);
+ output_quoted_escaped_string(p, azArg[i]);
}
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], 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 ){
- oputz("9.0e+999");
+ sqlite3_fputs("9.0e+999", p->out);
}else if( ur==0xfff0000000000000LL ){
- oputz("-9.0e+999");
+ sqlite3_fputs("-9.0e+999", p->out);
}else{
sqlite3_int64 ir = (sqlite3_int64)r;
if( r==(double)ir ){
@@ -20763,115 +23182,115 @@ static int shell_callback(
}else{
sqlite3_snprintf(50,z,"%!.20g", r);
}
- oputz(z);
+ sqlite3_fputs(z, p->out);
}
}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(pBlob, nBlob);
+ output_hex_blob(p->out, pBlob, nBlob);
}else if( isNumber(azArg[i], 0) ){
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], p->out);
}else if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(azArg[i]);
+ output_quoted_string(p, azArg[i]);
}else{
- output_quoted_escaped_string(azArg[i]);
+ output_quoted_escaped_string(p, azArg[i]);
}
}
- oputz(");\n");
+ sqlite3_fputs(");\n", p->out);
break;
}
case MODE_Json: {
if( azArg==0 ) break;
if( p->cnt==0 ){
- fputs("[{", p->out);
+ sqlite3_fputs("[{", p->out);
}else{
- fputs(",\n{", p->out);
+ sqlite3_fputs(",\n{", p->out);
}
p->cnt++;
for(i=0; i<nArg; i++){
- output_json_string(azCol[i], -1);
- oputz(":");
+ output_json_string(p->out, azCol[i], -1);
+ sqlite3_fputs(":", p->out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- oputz("null");
+ sqlite3_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 ){
- oputz("9.0e+999");
+ sqlite3_fputs("9.0e+999", p->out);
}else if( ur==0xfff0000000000000LL ){
- oputz("-9.0e+999");
+ sqlite3_fputs("-9.0e+999", p->out);
}else{
sqlite3_snprintf(50,z,"%!.20g", r);
- oputz(z);
+ sqlite3_fputs(z, p->out);
}
}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(pBlob, nBlob);
+ output_json_string(p->out, pBlob, nBlob);
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- output_json_string(azArg[i], -1);
+ output_json_string(p->out, azArg[i], -1);
}else{
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], p->out);
}
if( i<nArg-1 ){
- oputz(",");
+ sqlite3_fputs(",", p->out);
}
}
- oputz("}");
+ sqlite3_fputs("}", 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(azCol[i]);
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
+ output_quoted_string(p, azCol[i]);
}
- fputs(p->rowSeparator, p->out);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
p->cnt++;
for(i=0; i<nArg; i++){
- if( i>0 ) fputs(p->colSeparator, p->out);
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- oputz("NULL");
+ sqlite3_fputs("NULL", p->out);
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- output_quoted_string(azArg[i]);
+ output_quoted_string(p, azArg[i]);
}else if( aiType && aiType[i]==SQLITE_INTEGER ){
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], p->out);
}else if( aiType && aiType[i]==SQLITE_FLOAT ){
char z[50];
double r = sqlite3_column_double(p->pStmt, i);
sqlite3_snprintf(50,z,"%!.20g", r);
- oputz(z);
+ sqlite3_fputs(z, p->out);
}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(pBlob, nBlob);
+ output_hex_blob(p->out, pBlob, nBlob);
}else if( isNumber(azArg[i], 0) ){
- oputz(azArg[i]);
+ sqlite3_fputs(azArg[i], p->out);
}else{
- output_quoted_string(azArg[i]);
+ output_quoted_string(p, azArg[i]);
}
}
- fputs(p->rowSeparator, p->out);
+ sqlite3_fputs(p->rowSeparator, p->out);
break;
}
case MODE_Ascii: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
- if( i>0 ) oputz(p->colSeparator);
- oputz(azCol[i] ? azCol[i] : "");
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
+ sqlite3_fputs(azCol[i] ? azCol[i] : "", p->out);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- if( i>0 ) oputz(p->colSeparator);
- oputz(azArg[i] ? azArg[i] : p->nullValue);
+ if( i>0 ) sqlite3_fputs(p->colSeparator, p->out);
+ sqlite3_fputs(azArg[i] ? azArg[i] : p->nullValue, p->out);
}
- oputz(p->rowSeparator);
+ sqlite3_fputs(p->rowSeparator, p->out);
break;
}
case MODE_EQP: {
@@ -20950,7 +23369,7 @@ static void createSelftestTable(ShellState *p){
"DROP TABLE [_shell$self];"
,0,0,&zErrMsg);
if( zErrMsg ){
- eputf("SELFTEST initialization failure: %s\n", zErrMsg);
+ sqlite3_fprintf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
@@ -21053,7 +23472,7 @@ static int run_table_dump_query(
rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
if( rc!=SQLITE_OK || !pSelect ){
char *zContext = shell_error_context(zSelect, p->db);
- oputf("/**** ERROR: (%d) %s *****/\n%s",
+ sqlite3_fprintf(p->out, "/**** ERROR: (%d) %s *****/\n%s",
rc, sqlite3_errmsg(p->db), zContext);
sqlite3_free(zContext);
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
@@ -21063,22 +23482,23 @@ static int run_table_dump_query(
nResult = sqlite3_column_count(pSelect);
while( rc==SQLITE_ROW ){
z = (const char*)sqlite3_column_text(pSelect, 0);
- oputf("%s", z);
+ sqlite3_fprintf(p->out, "%s", z);
for(i=1; i<nResult; i++){
- oputf(",%s", sqlite3_column_text(pSelect, i));
+ sqlite3_fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i));
}
if( z==0 ) z = "";
while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
if( z[0] ){
- oputz("\n;\n");
+ sqlite3_fputs("\n;\n", p->out);
}else{
- oputz(";\n");
+ sqlite3_fputs(";\n", p->out);
}
rc = sqlite3_step(pSelect);
}
rc = sqlite3_finalize(pSelect);
if( rc!=SQLITE_OK ){
- oputf("/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
+ sqlite3_fprintf(p->out, "/**** ERROR: (%d) %s *****/\n",
+ rc, sqlite3_errmsg(p->db));
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
}
return rc;
@@ -21114,13 +23534,13 @@ static char *save_err_msg(
/*
** Attempt to display I/O stats on Linux using /proc/PID/io
*/
-static void displayLinuxIoStats(void){
+static void displayLinuxIoStats(FILE *out){
FILE *in;
char z[200];
sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
- in = fopen(z, "rb");
+ in = sqlite3_fopen(z, "rb");
if( in==0 ) return;
- while( fgets(z, sizeof(z), in)!=0 ){
+ while( sqlite3_fgets(z, sizeof(z), in)!=0 ){
static const struct {
const char *zPattern;
const char *zDesc;
@@ -21137,7 +23557,7 @@ static void displayLinuxIoStats(void){
for(i=0; i<ArraySize(aTrans); i++){
int n = strlen30(aTrans[i].zPattern);
if( cli_strncmp(aTrans[i].zPattern, z, n)==0 ){
- oputf("%-36s %s", aTrans[i].zDesc, &z[n]);
+ sqlite3_fprintf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
break;
}
}
@@ -21150,6 +23570,7 @@ static void displayLinuxIoStats(void){
** Display a single line of status using 64-bit values.
*/
static void displayStatLine(
+ FILE *out, /* Write to this channel */
char *zLabel, /* Label for this one line */
char *zFormat, /* Format for the result */
int iStatusCtrl, /* Which status to display */
@@ -21168,7 +23589,7 @@ static void displayStatLine(
}else{
sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
}
- oputf("%-36s %s\n", zLabel, zLine);
+ sqlite3_fprintf(out, "%-36s %s\n", zLabel, zLine);
}
/*
@@ -21181,28 +23602,31 @@ static int display_stats(
){
int iCur;
int iHiwtr;
+ FILE *out;
if( pArg==0 || pArg->out==0 ) return 0;
+ out = pArg->out;
if( pArg->pStmt && pArg->statsOn==2 ){
int nCol, i, x;
sqlite3_stmt *pStmt = pArg->pStmt;
char z[100];
nCol = sqlite3_column_count(pStmt);
- oputf("%-36s %d\n", "Number of output columns:", nCol);
+ sqlite3_fprintf(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);
- oputf("%-36s %s\n", z, sqlite3_column_name(pStmt,i));
+ sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_name(pStmt,i));
#ifndef SQLITE_OMIT_DECLTYPE
sqlite3_snprintf(30, z+x, "declared type:");
- oputf("%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
+ sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
#endif
#ifdef SQLITE_ENABLE_COLUMN_METADATA
sqlite3_snprintf(30, z+x, "database name:");
- oputf("%-36s %s\n", z, sqlite3_column_database_name(pStmt,i));
+ sqlite3_fprintf(out, "%-36s %s\n", z,
+ sqlite3_column_database_name(pStmt,i));
sqlite3_snprintf(30, z+x, "table name:");
- oputf("%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
+ sqlite3_fprintf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
sqlite3_snprintf(30, z+x, "origin name:");
- oputf("%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i));
+ sqlite3_fprintf(out, "%-36s %s\n", z,sqlite3_column_origin_name(pStmt,i));
#endif
}
}
@@ -21210,27 +23634,27 @@ static int display_stats(
if( pArg->statsOn==3 ){
if( pArg->pStmt ){
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP,bReset);
- oputf("VM-steps: %d\n", iCur);
+ sqlite3_fprintf(out, "VM-steps: %d\n", iCur);
}
return 0;
}
- displayStatLine("Memory Used:",
+ displayStatLine(out, "Memory Used:",
"%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
- displayStatLine("Number of Outstanding Allocations:",
+ displayStatLine(out, "Number of Outstanding Allocations:",
"%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
if( pArg->shellFlgs & SHFLG_Pagecache ){
- displayStatLine("Number of Pcache Pages Used:",
+ displayStatLine(out, "Number of Pcache Pages Used:",
"%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
}
- displayStatLine("Number of Pcache Overflow Bytes:",
+ displayStatLine(out, "Number of Pcache Overflow Bytes:",
"%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
- displayStatLine("Largest Allocation:",
+ displayStatLine(out, "Largest Allocation:",
"%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
- displayStatLine("Largest Pcache Allocation:",
+ displayStatLine(out, "Largest Pcache Allocation:",
"%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
#ifdef YYTRACKMAXSTACKDEPTH
- displayStatLine("Deepest Parser Stack:",
+ displayStatLine(out, "Deepest Parser Stack:",
"%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
#endif
@@ -21239,68 +23663,87 @@ static int display_stats(
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
&iCur, &iHiwtr, bReset);
- oputf("Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
+ sqlite3_fprintf(out,
+ "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
&iCur, &iHiwtr, bReset);
- oputf("Successful lookaside attempts: %d\n", iHiwtr);
+ sqlite3_fprintf(out,
+ "Successful lookaside attempts: %d\n", iHiwtr);
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
&iCur, &iHiwtr, bReset);
- oputf("Lookaside failures due to size: %d\n", iHiwtr);
+ sqlite3_fprintf(out,
+ "Lookaside failures due to size: %d\n", iHiwtr);
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
&iCur, &iHiwtr, bReset);
- oputf("Lookaside failures due to OOM: %d\n", iHiwtr);
+ sqlite3_fprintf(out,
+ "Lookaside failures due to OOM: %d\n", iHiwtr);
}
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
- oputf("Pager Heap Usage: %d bytes\n", iCur);
+ sqlite3_fprintf(out,
+ "Pager Heap Usage: %d bytes\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
- oputf("Page cache hits: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Page cache hits: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
- oputf("Page cache misses: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Page cache misses: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
- oputf("Page cache writes: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Page cache writes: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1);
- oputf("Page cache spills: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Page cache spills: %d\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
- oputf("Schema Heap Usage: %d bytes\n", iCur);
+ sqlite3_fprintf(out,
+ "Schema Heap Usage: %d bytes\n", iCur);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
- oputf("Statement Heap/Lookaside Usage: %d bytes\n", iCur);
+ sqlite3_fprintf(out,
+ "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
}
if( pArg->pStmt ){
int iHit, iMiss;
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
bReset);
- oputf("Fullscan Steps: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Fullscan Steps: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
- oputf("Sort Operations: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Sort Operations: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
- oputf("Autoindex Inserts: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Autoindex Inserts: %d\n", iCur);
iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT,
bReset);
iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS,
bReset);
if( iHit || iMiss ){
- oputf("Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss);
+ sqlite3_fprintf(out,
+ "Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss);
}
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
- oputf("Virtual Machine Steps: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Virtual Machine Steps: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
- oputf("Reprepare operations: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Reprepare operations: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
- oputf("Number of times run: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Number of times run: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
- oputf("Memory used by prepared stmt: %d\n", iCur);
+ sqlite3_fprintf(out,
+ "Memory used by prepared stmt: %d\n", iCur);
}
#ifdef __linux__
- displayLinuxIoStats();
+ displayLinuxIoStats(pArg->out);
#endif
/* Do not remove this machine readable comment: extra-stats-output-here */
@@ -21537,7 +23980,13 @@ static void display_scanstats(
if( pArg->scanstatsOn==3 ){
const char *zSql =
" SELECT addr, opcode, p1, p2, p3, p4, p5, comment, nexec,"
- " round(ncycle*100.0 / (sum(ncycle) OVER ()), 2)||'%' AS cycles"
+ " format('% 6s (%.2f%%)',"
+ " CASE WHEN ncycle<100_000 THEN ncycle || ' '"
+ " WHEN ncycle<100_000_000 THEN (ncycle/1_000) || 'K'"
+ " WHEN ncycle<100_000_000_000 THEN (ncycle/1_000_000) || 'M'"
+ " ELSE (ncycle/1000_000_000) || 'G' END,"
+ " ncycle*100.0/(sum(ncycle) OVER ())"
+ " ) AS cycles"
" FROM bytecode(?)";
int rc = SQLITE_OK;
@@ -21645,6 +24094,15 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
}else if( sqlite3_strlike("_INF", zVar, 0)==0 ){
sqlite3_bind_double(pStmt, i, INFINITY);
#endif
+ }else if( strncmp(zVar, "$int_", 5)==0 ){
+ sqlite3_bind_int(pStmt, i, atoi(&zVar[5]));
+ }else if( strncmp(zVar, "$text_", 6)==0 ){
+ size_t szVar = strlen(zVar);
+ char *zBuf = sqlite3_malloc64( szVar-5 );
+ if( zBuf ){
+ memcpy(zBuf, &zVar[6], szVar-5);
+ sqlite3_bind_text64(pStmt, i, zBuf, szVar-6, sqlite3_free, SQLITE_UTF8);
+ }
}else{
sqlite3_bind_null(pStmt, i);
}
@@ -21681,17 +24139,17 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
/* Draw horizontal line N characters long using unicode box
** characters
*/
-static void print_box_line(int N){
+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 ){
- oputz(zDash);
+ sqlite3_fputs(zDash, out);
N -= nDash;
}
- oputf("%.*s", N, zDash);
+ sqlite3_fprintf(out, "%.*s", N, zDash);
}
/*
@@ -21706,15 +24164,15 @@ static void print_box_row_separator(
){
int i;
if( nArg>0 ){
- oputz(zSep1);
- print_box_line(p->actualWidth[0]+2);
+ sqlite3_fputs(zSep1, p->out);
+ print_box_line(p->out, p->actualWidth[0]+2);
for(i=1; i<nArg; i++){
- oputz(zSep2);
- print_box_line(p->actualWidth[i]+2);
+ sqlite3_fputs(zSep2, p->out);
+ print_box_line(p->out, p->actualWidth[i]+2);
}
- oputz(zSep3);
+ sqlite3_fputs(zSep3, p->out);
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
/*
@@ -21729,6 +24187,7 @@ static void print_box_row_separator(
** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
*/
static char *translateForDisplayAndDup(
+ ShellState *p, /* To access current settings */
const unsigned char *z, /* Input text to be transformed */
const unsigned char **pzTail, /* OUT: Tail of the input for next line */
int mxWidth, /* Max width. 0 means no limit */
@@ -21748,12 +24207,23 @@ static char *translateForDisplayAndDup(
if( mxWidth==0 ) mxWidth = 1000000;
i = j = n = 0;
while( n<mxWidth ){
- if( z[i]>=' ' ){
+ unsigned char c = z[i];
+ if( c>=0xc0 ){
+ int u;
+ int len = decodeUtf8(&z[i], &u);
+ i += len;
+ j += len;
+ n += cli_wcwidth(u);
+ continue;
+ }
+ if( c>=' ' ){
n++;
- do{ i++; j++; }while( (z[i]&0xc0)==0x80 );
+ i++;
+ j++;
continue;
}
- if( z[i]=='\t' ){
+ if( c==0 || c=='\n' || (c=='\r' && z[i+1]=='\n') ) break;
+ if( c=='\t' ){
do{
n++;
j++;
@@ -21761,16 +24231,23 @@ static char *translateForDisplayAndDup(
i++;
continue;
}
- break;
+ if( c==0x1b && p->eEscMode==SHELL_ESC_OFF && (k = isVt100(&z[i]))>0 ){
+ i += k;
+ j += k;
+ }else{
+ n++;
+ j += 3;
+ i++;
+ }
}
if( n>=mxWidth && bWordWrap ){
/* Perhaps try to back up to a better place to break the line */
for(k=i; k>i/2; k--){
- if( isspace(z[k-1]) ) break;
+ if( IsSpace(z[k-1]) ) break;
}
if( k<=i/2 ){
for(k=i; k>i/2; k--){
- if( isalnum(z[k-1])!=isalnum(z[k]) && (z[k]&0xc0)!=0x80 ) break;
+ if( IsAlnum(z[k-1])!=IsAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break;
}
}
if( k<=i/2 ){
@@ -21795,11 +24272,20 @@ static char *translateForDisplayAndDup(
shell_check_oom(zOut);
i = j = n = 0;
while( i<k ){
- if( z[i]>=' ' ){
+ unsigned char c = z[i];
+ if( c>=0xc0 ){
+ int u;
+ int len = decodeUtf8(&z[i], &u);
+ do{ zOut[j++] = z[i++]; }while( (--len)>0 );
+ n += cli_wcwidth(u);
+ continue;
+ }
+ if( c>=' ' ){
n++;
- do{ zOut[j++] = z[i++]; }while( (z[i]&0xc0)==0x80 );
+ zOut[j++] = z[i++];
continue;
}
+ if( c==0 ) break;
if( z[i]=='\t' ){
do{
n++;
@@ -21808,12 +24294,44 @@ static char *translateForDisplayAndDup(
i++;
continue;
}
- break;
+ switch( p->eEscMode ){
+ case SHELL_ESC_SYMBOL:
+ zOut[j++] = 0xe2;
+ zOut[j++] = 0x90;
+ zOut[j++] = 0x80 + c;
+ break;
+ case SHELL_ESC_ASCII:
+ zOut[j++] = '^';
+ zOut[j++] = 0x40 + c;
+ break;
+ case SHELL_ESC_OFF: {
+ int nn;
+ if( c==0x1b && (nn = isVt100(&z[i]))>0 ){
+ memcpy(&zOut[j], &z[i], nn);
+ j += nn;
+ i += nn - 1;
+ }else{
+ zOut[j++] = c;
+ }
+ break;
+ }
+ }
+ i++;
}
zOut[j] = 0;
return (char*)zOut;
}
+/* Return true if the text string z[] contains characters that need
+** unistr() escaping.
+*/
+static int needUnistr(const unsigned char *z){
+ unsigned char c;
+ if( z==0 ) return 0;
+ while( (c = *z)>0x1f || c=='\t' || c=='\n' || (c=='\r' && z[1]=='\n') ){ z++; }
+ return c!=0;
+}
+
/* Extract the value of the i-th current column for pStmt as an SQL literal
** value. Memory is obtained from sqlite3_malloc64() and must be freed by
** the caller.
@@ -21828,7 +24346,8 @@ static char *quoted_column(sqlite3_stmt *pStmt, int i){
return sqlite3_mprintf("%s",sqlite3_column_text(pStmt,i));
}
case SQLITE_TEXT: {
- return sqlite3_mprintf("%Q",sqlite3_column_text(pStmt,i));
+ const unsigned char *zText = sqlite3_column_text(pStmt,i);
+ return sqlite3_mprintf(needUnistr(zText)?"%#Q":"%Q",zText);
}
case SQLITE_BLOB: {
int j;
@@ -21920,7 +24439,7 @@ static void exec_prepared_stmt_columnar(
if( wx<0 ) wx = -wx;
uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
if( uz==0 ) uz = (u8*)"";
- azData[i] = translateForDisplayAndDup(uz, &zNotUsed, wx, bw);
+ azData[i] = translateForDisplayAndDup(p, uz, &zNotUsed, wx, bw);
}
do{
int useNextLine = bNextLine;
@@ -21944,6 +24463,7 @@ static void exec_prepared_stmt_columnar(
uz = azNextLine[i];
if( uz==0 ) uz = (u8*)zEmpty;
}else if( p->cmOpts.bQuote ){
+ assert( azQuoted!=0 );
sqlite3_free(azQuoted[i]);
azQuoted[i] = quoted_column(pStmt,i);
uz = (const unsigned char*)azQuoted[i];
@@ -21952,7 +24472,7 @@ static void exec_prepared_stmt_columnar(
if( uz==0 ) uz = (u8*)zShowNull;
}
azData[nRow*nColumn + i]
- = translateForDisplayAndDup(uz, &azNextLine[i], wx, bw);
+ = translateForDisplayAndDup(p, uz, &azNextLine[i], wx, bw);
if( azNextLine[i] ){
bNextLine = 1;
abRowDiv[nRow-1] = 0;
@@ -21977,12 +24497,12 @@ static void exec_prepared_stmt_columnar(
for(i=0; i<nColumn; i++){
w = p->actualWidth[i];
if( p->colWidth[i]<0 ) w = -w;
- utf8_width_print(w, azData[i]);
- fputs(i==nColumn-1?"\n":" ", p->out);
+ utf8_width_print(p->out, w, azData[i]);
+ sqlite3_fputs(i==nColumn-1?"\n":" ", p->out);
}
for(i=0; i<nColumn; i++){
- print_dashes(p->actualWidth[i]);
- fputs(i==nColumn-1?"\n":" ", p->out);
+ print_dashes(p->out, p->actualWidth[i]);
+ sqlite3_fputs(i==nColumn-1?"\n":" ", p->out);
}
}
break;
@@ -21991,12 +24511,13 @@ static void exec_prepared_stmt_columnar(
colSep = " | ";
rowSep = " |\n";
print_row_separator(p, nColumn, "+");
- fputs("| ", p->out);
+ sqlite3_fputs("| ", p->out);
for(i=0; i<nColumn; i++){
w = p->actualWidth[i];
n = strlenChar(azData[i]);
- oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
- oputz(i==nColumn-1?" |\n":" | ");
+ sqlite3_fprintf(p->out, "%*s%s%*s", (w-n)/2, "",
+ azData[i], (w-n+1)/2, "");
+ sqlite3_fputs(i==nColumn-1?" |\n":" | ", p->out);
}
print_row_separator(p, nColumn, "+");
break;
@@ -22004,12 +24525,13 @@ static void exec_prepared_stmt_columnar(
case MODE_Markdown: {
colSep = " | ";
rowSep = " |\n";
- fputs("| ", p->out);
+ sqlite3_fputs("| ", p->out);
for(i=0; i<nColumn; i++){
w = p->actualWidth[i];
n = strlenChar(azData[i]);
- oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
- oputz(i==nColumn-1?" |\n":" | ");
+ sqlite3_fprintf(p->out, "%*s%s%*s", (w-n)/2, "",
+ azData[i], (w-n+1)/2, "");
+ sqlite3_fputs(i==nColumn-1?" |\n":" | ", p->out);
}
print_row_separator(p, nColumn, "|");
break;
@@ -22018,11 +24540,11 @@ static void exec_prepared_stmt_columnar(
colSep = " " BOX_13 " ";
rowSep = " " BOX_13 "\n";
print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
- oputz(BOX_13 " ");
+ sqlite3_fputs(BOX_13 " ", p->out);
for(i=0; i<nColumn; i++){
w = p->actualWidth[i];
n = strlenChar(azData[i]);
- oputf("%*s%s%*s%s",
+ sqlite3_fprintf(p->out, "%*s%s%*s%s",
(w-n)/2, "", azData[i], (w-n+1)/2, "",
i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
}
@@ -22032,28 +24554,28 @@ static void exec_prepared_stmt_columnar(
}
for(i=nColumn, j=0; i<nTotal; i++, j++){
if( j==0 && p->cMode!=MODE_Column ){
- oputz(p->cMode==MODE_Box?BOX_13" ":"| ");
+ sqlite3_fputs(p->cMode==MODE_Box?BOX_13" ":"| ", p->out);
}
z = azData[i];
if( z==0 ) z = p->nullValue;
w = p->actualWidth[j];
if( p->colWidth[j]<0 ) w = -w;
- utf8_width_print(w, z);
+ utf8_width_print(p->out, w, z);
if( j==nColumn-1 ){
- oputz(rowSep);
+ sqlite3_fputs(rowSep, p->out);
if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1<nTotal ){
if( p->cMode==MODE_Table ){
print_row_separator(p, nColumn, "+");
}else if( p->cMode==MODE_Box ){
print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
}else if( p->cMode==MODE_Column ){
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
}
j = -1;
if( seenInterrupt ) goto columnar_end;
}else{
- oputz(colSep);
+ sqlite3_fputs(colSep, p->out);
}
}
if( p->cMode==MODE_Table ){
@@ -22063,7 +24585,7 @@ static void exec_prepared_stmt_columnar(
}
columnar_end:
if( seenInterrupt ){
- oputz("Interrupt\n");
+ sqlite3_fputs("Interrupt\n", p->out);
}
nData = (nRow+1)*nColumn;
for(i=0; i<nData; i++){
@@ -22150,7 +24672,9 @@ static void exec_prepared_stmt(
} while( SQLITE_ROW == rc );
sqlite3_free(pData);
if( pArg->cMode==MODE_Json ){
- fputs("]\n", pArg->out);
+ sqlite3_fputs("]\n", pArg->out);
+ }else if( pArg->cMode==MODE_Www ){
+ sqlite3_fputs("</TABLE>\n<PRE>\n", pArg->out);
}else if( pArg->cMode==MODE_Count ){
char zBuf[200];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%llu row%s\n",
@@ -22199,6 +24723,7 @@ static int expertFinish(
){
int rc = SQLITE_OK;
sqlite3expert *p = pState->expert.pExpert;
+ FILE *out = pState->out;
assert( p );
assert( bCancel || pzErr==0 || *pzErr==0 );
if( bCancel==0 ){
@@ -22211,8 +24736,8 @@ static int expertFinish(
if( bVerbose ){
const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
- oputz("-- Candidates -----------------------------\n");
- oputf("%s\n", zCand);
+ sqlite3_fputs("-- Candidates -----------------------------\n", out);
+ sqlite3_fprintf(out, "%s\n", zCand);
}
for(i=0; i<nQuery; i++){
const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
@@ -22220,11 +24745,12 @@ static int expertFinish(
const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
if( zIdx==0 ) zIdx = "(no new indexes)\n";
if( bVerbose ){
- oputf("-- Query %d --------------------------------\n",i+1);
- oputf("%s\n\n", zSql);
+ sqlite3_fprintf(out,
+ "-- Query %d --------------------------------\n"
+ "%s\n\n"
+ ,i+1, zSql);
}
- oputf("%s\n", zIdx);
- oputf("%s\n", zEQP);
+ sqlite3_fprintf(out, "%s\n%s\n", zIdx, zEQP);
}
}
}
@@ -22259,18 +24785,18 @@ static int expertDotCommand(
}
else if( n>=2 && 0==cli_strncmp(z, "-sample", n) ){
if( i==(nArg-1) ){
- eputf("option requires an argument: %s\n", z);
+ sqlite3_fprintf(stderr, "option requires an argument: %s\n", z);
rc = SQLITE_ERROR;
}else{
iSample = (int)integerValue(azArg[++i]);
if( iSample<0 || iSample>100 ){
- eputf("value out of range: %s\n", azArg[i]);
+ sqlite3_fprintf(stderr,"value out of range: %s\n", azArg[i]);
rc = SQLITE_ERROR;
}
}
}
else{
- eputf("unknown option: %s\n", z);
+ sqlite3_fprintf(stderr,"unknown option: %s\n", z);
rc = SQLITE_ERROR;
}
}
@@ -22278,7 +24804,8 @@ static int expertDotCommand(
if( rc==SQLITE_OK ){
pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
if( pState->expert.pExpert==0 ){
- eputf("sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
+ sqlite3_fprintf(stderr,
+ "sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory");
rc = SQLITE_ERROR;
}else{
sqlite3_expert_config(
@@ -22360,6 +24887,7 @@ static int shell_exec(
sqlite3_reset(pExplain);
rc = sqlite3_stmt_explain(pExplain, 2);
if( rc==SQLITE_OK ){
+ bind_prepared_stmt(pArg, pExplain);
while( sqlite3_step(pExplain)==SQLITE_ROW ){
const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3);
int iEqpId = sqlite3_column_int(pExplain, 0);
@@ -22377,6 +24905,7 @@ static int shell_exec(
if( rc==SQLITE_OK ){
pArg->cMode = MODE_Explain;
assert( sqlite3_stmt_isexplain(pExplain)==1 );
+ bind_prepared_stmt(pArg, pExplain);
explain_data_prepare(pArg, pExplain);
exec_prepared_stmt(pArg, pExplain);
explain_data_delete(pArg);
@@ -22605,9 +25134,9 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
- if( !dataOnly ) oputz("DELETE FROM sqlite_sequence;\n");
+ /* no-op */
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
- if( !dataOnly ) oputz("ANALYZE sqlite_schema;\n");
+ if( !dataOnly ) sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
}else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( dataOnly ){
@@ -22615,7 +25144,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
}else if( cli_strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
char *zIns;
if( !p->writableSchema ){
- oputz("PRAGMA writable_schema=ON;\n");
+ sqlite3_fputs("PRAGMA writable_schema=ON;\n", p->out);
p->writableSchema = 1;
}
zIns = sqlite3_mprintf(
@@ -22623,11 +25152,11 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
shell_check_oom(zIns);
- oputf("%s\n", zIns);
+ sqlite3_fprintf(p->out, "%s\n", zIns);
sqlite3_free(zIns);
return 0;
}else{
- printSchemaLine(zSql, ";\n");
+ printSchemaLine(p->out, zSql, ";\n");
}
if( cli_strcmp(zType, "table")==0 ){
@@ -22685,7 +25214,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
p->mode = p->cMode = MODE_Insert;
rc = shell_exec(p, sSelect.z, 0);
if( (rc&0xff)==SQLITE_CORRUPT ){
- oputz("/****** CORRUPTION ERROR *******/\n");
+ sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out);
toggleSelectOrder(p->db);
shell_exec(p, sSelect.z, 0);
toggleSelectOrder(p->db);
@@ -22716,9 +25245,9 @@ static int run_schema_dump_query(
if( rc==SQLITE_CORRUPT ){
char *zQ2;
int len = strlen30(zQuery);
- oputz("/****** CORRUPTION ERROR *******/\n");
+ sqlite3_fputs("/****** CORRUPTION ERROR *******/\n", p->out);
if( zErr ){
- oputf("/****** %s ******/\n", zErr);
+ sqlite3_fprintf(p->out, "/****** %s ******/\n", zErr);
sqlite3_free(zErr);
zErr = 0;
}
@@ -22727,13 +25256,13 @@ static int run_schema_dump_query(
sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
if( rc ){
- oputf("/****** ERROR: %s ******/\n", zErr);
+ sqlite3_fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
}else{
rc = SQLITE_CORRUPT;
}
- sqlite3_free(zErr);
free(zQ2);
}
+ sqlite3_free(zErr);
return rc;
}
@@ -22790,14 +25319,13 @@ static const char *(azHelp[]) = {
".clone NEWDB Clone data into NEWDB from the existing database",
#endif
".connection [close] [#] Open or close an auxiliary database connection",
-#if defined(_WIN32) || defined(WIN32)
- ".crnl on|off Translate \\n to \\r\\n. Default ON",
-#endif
+ ".crlf ?on|off? Whether or not to use \\r\\n line endings",
".databases List names and files of attached databases",
".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
#if SQLITE_SHELL_HAVE_RECOVER
".dbinfo ?DB? Show status information about the database",
#endif
+ ".dbtotxt Hex dump of the database file",
".dump ?OBJECTS? Render database content as SQL",
" Options:",
" --data-only Output only INSERT statements",
@@ -22867,7 +25395,7 @@ static const char *(azHelp[]) = {
#else
".log on|off Turn logging on or off.",
#endif
- ".mode MODE ?OPTIONS? Set output mode",
+ ".mode ?MODE? ?OPTIONS? Set output mode",
" MODE is one of:",
" ascii Columns/rows delimited by 0x1F and 0x1E",
" box Tables using unicode box-drawing characters",
@@ -22885,6 +25413,7 @@ static const char *(azHelp[]) = {
" tabs Tab-separated values",
" tcl TCL list elements",
" OPTIONS: (for columnar modes or insert mode):",
+ " --escape T ctrl-char escape; T is one of: symbol, ascii, off",
" --wrap N Wrap output lines to no longer than N characters",
" --wordwrap B Wrap or not at word boundaries per B (on/off)",
" --ww Shorthand for \"--wordwrap 1\"",
@@ -22898,9 +25427,11 @@ static const char *(azHelp[]) = {
#ifndef SQLITE_SHELL_FIDDLE
".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\")",
+ " --bom Put a UTF8 byte-order mark at the beginning",
+ " -e Send output to the system text editor",
+ " --plain Use text/plain output instead of HTML for -w option",
+ " -w Send output as HTML to a web browser (same as \".www\")",
+ " -x Send output as CSV to a spreadsheet (same as \".excel\")",
/* Note that .open is (partially) available in WASM builds but is
** currently only intended to be used by the fiddle tool, not
** end users, so is "undocumented." */
@@ -22920,9 +25451,12 @@ static const char *(azHelp[]) = {
#ifndef SQLITE_SHELL_FIDDLE
".output ?FILE? Send output to FILE or stdout if FILE is omitted",
" If FILE begins with '|' then open it as a pipe.",
+ " If FILE is 'off' then output is disabled.",
" Options:",
" --bom Prefix output with a UTF8 byte-order mark",
" -e Send output to the system text editor",
+ " --plain Use text/plain for -w option",
+ " -w Send output to a web browser",
" -x Send output as CSV to a spreadsheet",
#endif
".parameter CMD ... Manage SQL parameter bindings",
@@ -23036,106 +25570,111 @@ static const char *(azHelp[]) = {
".vfsname ?AUX? Print the name of the VFS stack",
".width NUM1 NUM2 ... Set minimum column widths for columnar output",
" Negative values right-justify",
+#ifndef SQLITE_SHELL_FIDDLE
+ ".www Display output of the next command in web browser",
+ " --plain Show results as text/plain, not as HTML",
+#endif
};
/*
-** Output help text.
+** Output help text for commands that match zPattern.
+**
+** * If zPattern is NULL, then show all documented commands, but
+** only give a one-line summary of each.
+**
+** * If zPattern is "-a" or "-all" or "--all" then show all help text
+** for all commands except undocumented commands.
+**
+** * If zPattern is "0" then show all help for undocumented commands.
+** Undocumented commands begin with "," instead of "." in the azHelp[]
+** array.
+**
+** * If zPattern is a prefix for one or more documented commands, then
+** show help for those commands. If only a single command matches the
+** prefix, show the full text of the help. If multiple commands match,
+** Only show just the first line of each.
**
-** 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.
+** * Otherwise, show the complete text of any documented command for which
+** zPattern is a LIKE match for any text within that command help
+** text.
**
-** Return the number of matches.
+** Return the number commands that match zPattern.
*/
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'
- || cli_strcmp(zPattern,"-a")==0
- || cli_strcmp(zPattern,"-all")==0
- || cli_strcmp(zPattern,"--all")==0
+ if( zPattern==0 ){
+ /* Show just the first line for all help topics */
+ zPattern = "[a-z]";
+ }else if( cli_strcmp(zPattern,"-a")==0
+ || cli_strcmp(zPattern,"-all")==0
+ || cli_strcmp(zPattern,"--all")==0
){
- enum HelpWanted { HW_NoCull = 0, HW_SummaryOnly = 1, HW_Undoc = 2 };
- enum HelpHave { HH_Undoc = 2, HH_Summary = 1, HH_More = 0 };
- /* Show all or most commands
- ** *zPattern==0 => summary of documented commands only
- ** *zPattern=='0' => whole help for undocumented commands
- ** Otherwise => whole help for documented commands
- */
- enum HelpWanted hw = HW_SummaryOnly;
- enum HelpHave hh = HH_More;
- if( zPattern!=0 ){
- hw = (*zPattern=='0')? HW_NoCull|HW_Undoc : HW_NoCull;
- }
- for(i=0; i<ArraySize(azHelp); i++){
- switch( azHelp[i][0] ){
- case ',':
- hh = HH_Summary|HH_Undoc;
- break;
- case '.':
- hh = HH_Summary;
- break;
- default:
- hh &= ~HH_Summary;
- break;
- }
- if( ((hw^hh)&HH_Undoc)==0 ){
- if( (hh&HH_Summary)!=0 ){
- sputf(out, ".%s\n", azHelp[i]+1);
- ++n;
- }else if( (hw&HW_SummaryOnly)==0 ){
- sputf(out, "%s\n", azHelp[i]);
- }
- }
- }
- }else{
- /* Seek documented commands for which zPattern is an exact prefix */
- zPat = sqlite3_mprintf(".%s*", zPattern);
- shell_check_oom(zPat);
+ /* Show everything except undocumented commands */
+ zPattern = ".";
+ }else if( cli_strcmp(zPattern,"0")==0 ){
+ /* Show complete help text of undocumented commands */
+ int show = 0;
for(i=0; i<ArraySize(azHelp); i++){
- if( sqlite3_strglob(zPat, azHelp[i])==0 ){
- sputf(out, "%s\n", azHelp[i]);
- j = i+1;
+ if( azHelp[i][0]=='.' ){
+ show = 0;
+ }else if( azHelp[i][0]==',' ){
+ show = 1;
+ sqlite3_fprintf(out, ".%s\n", &azHelp[i][1]);
n++;
+ }else if( show ){
+ sqlite3_fprintf(out, "%s\n", azHelp[i]);
}
}
- 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]==' ' ){
- sputf(out, "%s\n", azHelp[j]);
- j++;
- }
- }
- return n;
+ return n;
+ }
+
+ /* Seek documented commands for which zPattern is an exact prefix */
+ zPat = sqlite3_mprintf(".%s*", zPattern);
+ shell_check_oom(zPat);
+ for(i=0; i<ArraySize(azHelp); i++){
+ if( sqlite3_strglob(zPat, azHelp[i])==0 ){
+ sqlite3_fprintf(out, "%s\n", azHelp[i]);
+ j = i+1;
+ n++;
}
- /* Look for documented commands that contain zPattern anywhere.
- ** Show complete text of all documented commands that match. */
- zPat = sqlite3_mprintf("%%%s%%", zPattern);
- shell_check_oom(zPat);
- for(i=0; i<ArraySize(azHelp); i++){
- if( azHelp[i][0]==',' ){
- while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i;
- continue;
+ }
+ 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]==' ' ){
+ sqlite3_fprintf(out, "%s\n", azHelp[j]);
+ j++;
}
- if( azHelp[i][0]=='.' ) j = i;
- if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
- sputf(out, "%s\n", azHelp[j]);
- while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
- j++;
- sputf(out, "%s\n", azHelp[j]);
- }
- i = j;
- n++;
+ }
+ return n;
+ }
+
+ /* Look for documented commands that contain zPattern anywhere.
+ ** Show complete text of all documented commands that match. */
+ zPat = sqlite3_mprintf("%%%s%%", zPattern);
+ shell_check_oom(zPat);
+ for(i=0; i<ArraySize(azHelp); i++){
+ if( azHelp[i][0]==',' ){
+ while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i;
+ continue;
+ }
+ if( azHelp[i][0]=='.' ) j = i;
+ if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
+ sqlite3_fprintf(out, "%s\n", azHelp[j]);
+ while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
+ j++;
+ sqlite3_fprintf(out, "%s\n", azHelp[j]);
}
+ i = j;
+ n++;
}
- sqlite3_free(zPat);
}
+ sqlite3_free(zPat);
return n;
}
@@ -23158,7 +25697,7 @@ static int process_input(ShellState *p);
** is undefined in this case.
*/
static char *readFile(const char *zName, int *pnByte){
- FILE *in = fopen(zName, "rb");
+ FILE *in = sqlite3_fopen(zName, "rb");
long nIn;
size_t nRead;
char *pBuf;
@@ -23166,7 +25705,7 @@ static char *readFile(const char *zName, int *pnByte){
if( in==0 ) return 0;
rc = fseek(in, 0, SEEK_END);
if( rc!=0 ){
- eputf("Error: '%s' not seekable\n", zName);
+ sqlite3_fprintf(stderr,"Error: '%s' not seekable\n", zName);
fclose(in);
return 0;
}
@@ -23174,7 +25713,7 @@ static char *readFile(const char *zName, int *pnByte){
rewind(in);
pBuf = sqlite3_malloc64( nIn+1 );
if( pBuf==0 ){
- eputz("Error: out of memory\n");
+ sqlite3_fputs("Error: out of memory\n", stderr);
fclose(in);
return 0;
}
@@ -23182,7 +25721,7 @@ static char *readFile(const char *zName, int *pnByte){
fclose(in);
if( nRead!=1 ){
sqlite3_free(pBuf);
- eputf("Error: cannot read '%s'\n", zName);
+ sqlite3_fprintf(stderr,"Error: cannot read '%s'\n", zName);
return 0;
}
pBuf[nIn] = 0;
@@ -23248,7 +25787,7 @@ static int session_filter(void *pCtx, const char *zTab){
** the type cannot be determined from content.
*/
int deduceDatabaseType(const char *zName, int dfltZip){
- FILE *f = fopen(zName, "rb");
+ FILE *f = sqlite3_fopen(zName, "rb");
size_t n;
int rc = SHELL_OPEN_UNSPEC;
char zBuf[100];
@@ -23301,9 +25840,9 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
unsigned int x[16];
char zLine[1000];
if( zDbFilename ){
- in = fopen(zDbFilename, "r");
+ in = sqlite3_fopen(zDbFilename, "r");
if( in==0 ){
- eputf("cannot open \"%s\" for reading\n", zDbFilename);
+ sqlite3_fprintf(stderr,"cannot open \"%s\" for reading\n", zDbFilename);
return 0;
}
nLine = 0;
@@ -23314,7 +25853,7 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
}
*pnData = 0;
nLine++;
- if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
+ if( sqlite3_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;
@@ -23324,10 +25863,10 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
shell_check_oom(a);
memset(a, 0, n);
if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
- eputz("invalid pagesize\n");
+ sqlite3_fputs("invalid pagesize\n", stderr);
goto readHexDb_error;
}
- for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
+ for(nLine++; sqlite3_fgets(zLine, sizeof(zLine), in)!=0; nLine++){
rc = sscanf(zLine, "| page %d offset %d", &j, &k);
if( rc==2 ){
iOffset = k;
@@ -23359,14 +25898,14 @@ readHexDb_error:
if( in!=p->in ){
fclose(in);
}else{
- while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
+ while( sqlite3_fgets(zLine, sizeof(zLine), p->in)!=0 ){
nLine++;
if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
}
p->lineno = nLine;
}
sqlite3_free(a);
- eputf("Error on line %d of --hexdb input\n", nLine);
+ sqlite3_fprintf(stderr,"Error on line %d of --hexdb input\n", nLine);
return 0;
}
#endif /* SQLITE_OMIT_DESERIALIZE */
@@ -23385,6 +25924,39 @@ static void shellUSleepFunc(
sqlite3_result_int(context, sleep);
}
+/*
+** 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;
+ char *zFake;
+ ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
+ FILE *pSavedLog = p->pLog;
+ UNUSED_PARAMETER(nVal);
+ zName = (const char*)sqlite3_value_text(apVal[0]);
+
+ /* Temporarily disable the ".log" when calling shellFakeSchema() because
+ ** shellFakeSchema() might generate failures for some ephemeral virtual
+ ** tables due to missing arguments. Example: fts4aux.
+ ** https://sqlite.org/forum/forumpost/42fe6520b803be51 */
+ p->pLog = 0;
+ zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0;
+ p->pLog = pSavedLog;
+
+ if( zFake ){
+ sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
+ -1, sqlite3_free);
+ free(zFake);
+ }
+}
+
/* Flags for open_db().
**
** The default behavior of open_db() is to exit(1) if the database fails to
@@ -23441,7 +26013,7 @@ static void open_db(ShellState *p, int openFlags){
}
}
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
- eputf("Error: unable to open database \"%s\": %s\n",
+ sqlite3_fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
zDbFilename, sqlite3_errmsg(p->db));
if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){
exit(1);
@@ -23449,10 +26021,12 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_close(p->db);
sqlite3_open(":memory:", &p->db);
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
- eputz("Also: unable to open substitute in-memory database.\n");
+ sqlite3_fputs("Also: unable to open substitute in-memory database.\n",
+ stderr);
exit(1);
}else{
- eputf("Notice: using substitute in-memory database instead of \"%s\"\n",
+ sqlite3_fprintf(stderr,
+ "Notice: using substitute in-memory database instead of \"%s\"\n",
zDbFilename);
}
}
@@ -23469,9 +26043,12 @@ static void open_db(ShellState *p, int openFlags){
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
+ sqlite3_sha_init(p->db, 0, 0);
sqlite3_shathree_init(p->db, 0, 0);
sqlite3_uint_init(p->db, 0, 0);
+ sqlite3_stmtrand_init(p->db, 0, 0);
sqlite3_decimal_init(p->db, 0, 0);
+ sqlite3_percentile_init(p->db, 0, 0);
sqlite3_base64_init(p->db, 0, 0);
sqlite3_base85_init(p->db, 0, 0);
sqlite3_regexp_init(p->db, 0, 0);
@@ -23523,7 +26100,7 @@ static void open_db(ShellState *p, int openFlags){
shellDtostr, 0, 0);
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,
+ sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, p,
shellModuleSchema, 0, 0);
sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
shellPutsFunc, 0, 0);
@@ -23561,7 +26138,7 @@ static void open_db(ShellState *p, int openFlags){
SQLITE_DESERIALIZE_RESIZEABLE |
SQLITE_DESERIALIZE_FREEONCLOSE);
if( rc ){
- eputf("Error: sqlite3_deserialize() returns %d\n", rc);
+ sqlite3_fprintf(stderr,"Error: sqlite3_deserialize() returns %d\n", rc);
}
if( p->szMax>0 ){
sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
@@ -23585,11 +26162,13 @@ static void open_db(ShellState *p, int openFlags){
void close_db(sqlite3 *db){
int rc = sqlite3_close(db);
if( rc ){
- eputf("Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,
+ "Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db));
}
}
-#if HAVE_READLINE || HAVE_EDITLINE
+#if (HAVE_READLINE || HAVE_EDITLINE) \
+ && !defined(SQLITE_OMIT_READLINE_COMPLETION)
/*
** Readline completion callbacks
*/
@@ -23624,18 +26203,28 @@ static char **readline_completion(const char *zText, int iStart, int iEnd){
#elif HAVE_LINENOISE
/*
-** Linenoise completion callback
+** Linenoise completion callback. Note that the 3rd argument is from
+** the "msteveb" version of linenoise, not the "antirez" version.
*/
-static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
+static void linenoise_completion(
+ const char *zLine,
+ linenoiseCompletions *lc
+#if HAVE_LINENOISE==2
+ ,void *pUserData
+#endif
+){
i64 nLine = strlen(zLine);
i64 i, iStart;
sqlite3_stmt *pStmt = 0;
char *zSql;
char zBuf[1000];
+#if HAVE_LINENOISE==2
+ UNUSED_PARAMETER(pUserData);
+#endif
if( nLine>(i64)sizeof(zBuf)-30 ) return;
if( zLine[0]=='.' || zLine[0]=='#') return;
- for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
+ for(i=nLine-1; i>=0 && (IsAlnum(zLine[i]) || zLine[i]=='_'); i--){}
if( i==nLine-1 ) return;
iStart = i+1;
memcpy(zBuf, zLine, iStart);
@@ -23746,7 +26335,8 @@ static int booleanValue(const char *zArg){
if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
return 0;
}
- eputf("ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg);
+ sqlite3_fprintf(stderr,
+ "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg);
return 0;
}
@@ -23773,7 +26363,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, int bTextMode){
+static FILE *output_file_open(const char *zFile){
FILE *f;
if( cli_strcmp(zFile,"stdout")==0 ){
f = stdout;
@@ -23782,9 +26372,9 @@ static FILE *output_file_open(const char *zFile, int bTextMode){
}else if( cli_strcmp(zFile, "off")==0 ){
f = 0;
}else{
- f = fopen(zFile, bTextMode ? "w" : "wb");
+ f = sqlite3_fopen(zFile, "w");
if( f==0 ){
- eputf("Error: cannot open \"%s\"\n", zFile);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zFile);
}
}
return f;
@@ -23837,12 +26427,13 @@ static int sql_trace_callback(
switch( mType ){
case SQLITE_TRACE_ROW:
case SQLITE_TRACE_STMT: {
- sputf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
+ sqlite3_fprintf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
break;
}
case SQLITE_TRACE_PROFILE: {
sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
- sputf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
+ sqlite3_fprintf(p->traceOut,
+ "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
break;
}
}
@@ -23949,10 +26540,11 @@ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
break;
}
if( pc==cQuote && c!='\r' ){
- eputf("%s:%d: unescaped %c character\n", p->zFile, p->nLine, cQuote);
+ sqlite3_fprintf(stderr,"%s:%d: unescaped %c character\n",
+ p->zFile, p->nLine, cQuote);
}
if( c==EOF ){
- eputf("%s:%d: unterminated %c-quoted field\n",
+ sqlite3_fprintf(stderr,"%s:%d: unterminated %c-quoted field\n",
p->zFile, startLine, cQuote);
p->cTerm = c;
break;
@@ -24051,7 +26643,7 @@ static void tryToCloneData(
shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
- eputf("Error %d: %s on [%s]\n",
+ sqlite3_fprintf(stderr,"Error %d: %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
goto end_data_xfer;
}
@@ -24068,7 +26660,7 @@ static void tryToCloneData(
memcpy(zInsert+i, ");", 3);
rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
if( rc ){
- eputf("Error %d: %s on [%s]\n",
+ sqlite3_fprintf(stderr,"Error %d: %s on [%s]\n",
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb), zInsert);
goto end_data_xfer;
}
@@ -24104,7 +26696,7 @@ static void tryToCloneData(
} /* End for */
rc = sqlite3_step(pInsert);
if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
- eputf("Error %d: %s\n",
+ sqlite3_fprintf(stderr,"Error %d: %s\n",
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb));
}
sqlite3_reset(pInsert);
@@ -24122,7 +26714,7 @@ static void tryToCloneData(
shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
- eputf("Warning: cannot step \"%s\" backwards", zTable);
+ sqlite3_fprintf(stderr,"Warning: cannot step \"%s\" backwards", zTable);
break;
}
} /* End for(k=0...) */
@@ -24159,7 +26751,8 @@ static void tryToCloneSchema(
shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
- eputf("Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db),
+ sqlite3_fprintf(stderr,
+ "Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db),
sqlite3_errmsg(p->db), zQuery);
goto end_schema_xfer;
}
@@ -24168,10 +26761,10 @@ static void tryToCloneSchema(
zSql = sqlite3_column_text(pQuery, 1);
if( zName==0 || zSql==0 ) continue;
if( sqlite3_stricmp((char*)zName, "sqlite_sequence")!=0 ){
- sputf(stdout, "%s... ", zName); fflush(stdout);
+ sqlite3_fprintf(stdout, "%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
- eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
+ sqlite3_fprintf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}
@@ -24189,7 +26782,7 @@ static void tryToCloneSchema(
shell_check_oom(zQuery);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
- eputf("Error: (%d) %s on [%s]\n",
+ sqlite3_fprintf(stderr,"Error: (%d) %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery);
goto end_schema_xfer;
}
@@ -24198,10 +26791,10 @@ static void tryToCloneSchema(
zSql = sqlite3_column_text(pQuery, 1);
if( zName==0 || zSql==0 ) continue;
if( sqlite3_stricmp((char*)zName, "sqlite_sequence")==0 ) continue;
- sputf(stdout, "%s... ", zName); fflush(stdout);
+ sqlite3_fprintf(stdout, "%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
- eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
+ sqlite3_fprintf(stderr,"Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}
@@ -24225,12 +26818,13 @@ static void tryToClone(ShellState *p, const char *zNewDb){
int rc;
sqlite3 *newDb = 0;
if( access(zNewDb,0)==0 ){
- eputf("File \"%s\" already exists.\n", zNewDb);
+ sqlite3_fprintf(stderr,"File \"%s\" already exists.\n", zNewDb);
return;
}
rc = sqlite3_open(zNewDb, &newDb);
if( rc ){
- eputf("Cannot create output database: %s\n", sqlite3_errmsg(newDb));
+ sqlite3_fprintf(stderr,
+ "Cannot create output database: %s\n", sqlite3_errmsg(newDb));
}else{
sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
@@ -24247,10 +26841,18 @@ static void tryToClone(ShellState *p, const char *zNewDb){
** Change the output stream (file or pipe or console) to something else.
*/
static void output_redir(ShellState *p, FILE *pfNew){
- if( p->out != stdout ) eputz("Output already redirected.\n");
- else{
+ if( p->out != stdout ){
+ sqlite3_fputs("Output already redirected.\n", stderr);
+ }else{
p->out = pfNew;
- setOutputStream(pfNew);
+ setCrlfMode(p);
+ if( p->mode==MODE_Www ){
+ sqlite3_fputs(
+ "<!DOCTYPE html>\n"
+ "<HTML><BODY><PRE>\n",
+ p->out
+ );
+ }
}
}
@@ -24267,6 +26869,9 @@ static void output_reset(ShellState *p){
pclose(p->out);
#endif
}else{
+ if( p->mode==MODE_Www ){
+ sqlite3_fputs("</PRE></BODY></HTML>\n", p->out);
+ }
output_file_close(p->out);
#ifndef SQLITE_NOHAVE_SYSTEM
if( p->doXdgOpen ){
@@ -24281,7 +26886,7 @@ static void output_reset(ShellState *p){
char *zCmd;
zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
if( system(zCmd) ){
- eputf("Failed: [%s]\n", zCmd);
+ sqlite3_fprintf(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
@@ -24296,7 +26901,7 @@ static void output_reset(ShellState *p){
}
p->outfile[0] = 0;
p->out = stdout;
- setOutputStream(stdout);
+ setCrlfMode(p);
}
#else
# define output_redir(SS,pfO)
@@ -24306,14 +26911,20 @@ static void output_reset(ShellState *p){
/*
** Run an SQL command and return the single integer result.
*/
-static int db_int(sqlite3 *db, const char *zSql){
+static int db_int(sqlite3 *db, const char *zSql, ...){
sqlite3_stmt *pStmt;
int res = 0;
- sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ char *z;
+ va_list ap;
+ va_start(ap, zSql);
+ z = sqlite3_vmprintf(zSql, ap);
+ va_end(ap);
+ sqlite3_prepare_v2(db, z, -1, &pStmt, 0);
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
res = sqlite3_column_int(pStmt,0);
}
sqlite3_finalize(pStmt);
+ sqlite3_free(z);
return res;
}
@@ -24372,7 +26983,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
-1, &pStmt, 0);
if( rc ){
- eputf("error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_fprintf(stderr,"error: %s\n", sqlite3_errmsg(p->db));
sqlite3_finalize(pStmt);
return 1;
}
@@ -24385,28 +26996,28 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
memcpy(aHdr, pb, 100);
sqlite3_finalize(pStmt);
}else{
- eputz("unable to read database header\n");
+ sqlite3_fputs("unable to read database header\n", stderr);
sqlite3_finalize(pStmt);
return 1;
}
i = get2byteInt(aHdr+16);
if( i==1 ) i = 65536;
- oputf("%-20s %d\n", "database page size:", i);
- oputf("%-20s %d\n", "write format:", aHdr[18]);
- oputf("%-20s %d\n", "read format:", aHdr[19]);
- oputf("%-20s %d\n", "reserved bytes:", aHdr[20]);
+ sqlite3_fprintf(p->out, "%-20s %d\n", "database page size:", i);
+ sqlite3_fprintf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
+ sqlite3_fprintf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
+ sqlite3_fprintf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
for(i=0; i<ArraySize(aField); i++){
int ofst = aField[i].ofst;
unsigned int val = get4byteInt(aHdr + ofst);
- oputf("%-20s %u", aField[i].zName, val);
+ sqlite3_fprintf(p->out, "%-20s %u", aField[i].zName, val);
switch( ofst ){
case 56: {
- if( val==1 ) oputz(" (utf8)");
- if( val==2 ) oputz(" (utf16le)");
- if( val==3 ) oputz(" (utf16be)");
+ if( val==1 ) sqlite3_fputs(" (utf8)", p->out);
+ if( val==2 ) sqlite3_fputs(" (utf16le)", p->out);
+ if( val==3 ) sqlite3_fputs(" (utf16be)", p->out);
}
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
if( zDb==0 ){
zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
@@ -24416,24 +27027,120 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
}
for(i=0; i<ArraySize(aQuery); i++){
- char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
- int val = db_int(p->db, zSql);
- sqlite3_free(zSql);
- oputf("%-20s %d\n", aQuery[i].zName, val);
+ int val = db_int(p->db, aQuery[i].zSql, zSchemaTab);
+ sqlite3_fprintf(p->out, "%-20s %d\n", aQuery[i].zName, val);
}
sqlite3_free(zSchemaTab);
sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
- oputf("%-20s %u\n", "data version", iDataVersion);
+ sqlite3_fprintf(p->out, "%-20s %u\n", "data version", iDataVersion);
return 0;
}
#endif /* SQLITE_SHELL_HAVE_RECOVER */
/*
+** Implementation of the ".dbtotxt" command.
+**
+** Return 1 on error, 2 to exit, and 0 otherwise.
+*/
+static int shell_dbtotxt_command(ShellState *p, int nArg, char **azArg){
+ sqlite3_stmt *pStmt = 0;
+ sqlite3_int64 nPage = 0;
+ int pgSz = 0;
+ const char *zTail;
+ char *zName = 0;
+ int rc, i, j;
+ unsigned char bShow[256]; /* Characters ok to display */
+
+ UNUSED_PARAMETER(nArg);
+ UNUSED_PARAMETER(azArg);
+ memset(bShow, '.', sizeof(bShow));
+ for(i=' '; i<='~'; i++){
+ if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = (unsigned char)i;
+ }
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA page_size", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ rc = 0;
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
+ pgSz = sqlite3_column_int(pStmt, 0);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( pgSz<512 || pgSz>65536 || (pgSz&(pgSz-1))!=0 ) goto dbtotxt_error;
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA page_count", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ rc = 0;
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
+ nPage = sqlite3_column_int64(pStmt, 0);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( nPage<1 ) goto dbtotxt_error;
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA databases", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ if( sqlite3_step(pStmt)!=SQLITE_ROW ){
+ zTail = "unk.db";
+ }else{
+ const char *zFilename = (const char*)sqlite3_column_text(pStmt, 2);
+ if( zFilename==0 || zFilename[0]==0 ) zFilename = "unk.db";
+ zTail = strrchr(zFilename, '/');
+#if defined(_WIN32)
+ if( zTail==0 ) zTail = strrchr(zFilename, '\\');
+#endif
+ }
+ zName = strdup(zTail);
+ shell_check_oom(zName);
+ sqlite3_fprintf(p->out, "| size %lld pagesize %d filename %s\n",
+ nPage*pgSz, pgSz, zName);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ rc = sqlite3_prepare_v2(p->db,
+ "SELECT pgno, data FROM sqlite_dbpage ORDER BY pgno", -1, &pStmt, 0);
+ if( rc ) goto dbtotxt_error;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ sqlite3_int64 pgno = sqlite3_column_int64(pStmt, 0);
+ const u8 *aData = sqlite3_column_blob(pStmt, 1);
+ int seenPageLabel = 0;
+ for(i=0; i<pgSz; i+=16){
+ const u8 *aLine = aData+i;
+ for(j=0; j<16 && aLine[j]==0; j++){}
+ if( j==16 ) continue;
+ if( !seenPageLabel ){
+ sqlite3_fprintf(p->out, "| page %lld offset %lld\n",pgno,(pgno-1)*pgSz);
+ seenPageLabel = 1;
+ }
+ sqlite3_fprintf(p->out, "| %5d:", i);
+ for(j=0; j<16; j++) sqlite3_fprintf(p->out, " %02x", aLine[j]);
+ sqlite3_fprintf(p->out, " ");
+ for(j=0; j<16; j++){
+ unsigned char c = (unsigned char)aLine[j];
+ sqlite3_fprintf(p->out, "%c", bShow[c]);
+ }
+ sqlite3_fprintf(p->out, "\n");
+ }
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_fprintf(p->out, "| end %s\n", zName);
+ free(zName);
+ return 0;
+
+dbtotxt_error:
+ if( rc ){
+ sqlite3_fprintf(stderr, "ERROR: %s\n", sqlite3_errmsg(p->db));
+ }
+ sqlite3_finalize(pStmt);
+ free(zName);
+ return 1;
+}
+
+/*
+** Print the given string as an error message.
+*/
+static void shellEmitError(const char *zErr){
+ sqlite3_fprintf(stderr,"Error: %s\n", zErr);
+}
+/*
** Print the current sqlite3_errmsg() value to stderr and return 1.
*/
static int shellDatabaseError(sqlite3 *db){
- const char *zErr = sqlite3_errmsg(db);
- eputf("Error: %s\n", zErr);
+ shellEmitError(sqlite3_errmsg(db));
return 1;
}
@@ -24674,6 +27381,7 @@ static int lintFkeyIndexes(
const char *zIndent = ""; /* How much to indent CREATE INDEX by */
int rc; /* Return code */
sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
+ FILE *out = pState->out; /* Send output here */
/*
** This SELECT statement returns one row for each foreign key constraint
@@ -24749,7 +27457,8 @@ static int lintFkeyIndexes(
zIndent = " ";
}
else{
- eputf("Usage: %s %s ?-verbose? ?-groupbyparent?\n", azArg[0], azArg[1]);
+ sqlite3_fprintf(stderr,
+ "Usage: %s %s ?-verbose? ?-groupbyparent?\n", azArg[0], azArg[1]);
return SQLITE_ERROR;
}
}
@@ -24793,22 +27502,23 @@ static int lintFkeyIndexes(
if( rc!=SQLITE_OK ) break;
if( res<0 ){
- eputz("Error: internal error");
+ sqlite3_fputs("Error: internal error", stderr);
break;
}else{
if( bGroupByParent
&& (bVerbose || res==0)
&& (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
){
- oputf("-- Parent table %s\n", zParent);
+ sqlite3_fprintf(out, "-- Parent table %s\n", zParent);
sqlite3_free(zPrev);
zPrev = sqlite3_mprintf("%s", zParent);
}
if( res==0 ){
- oputf("%s%s --> %s\n", zIndent, zCI, zTarget);
+ sqlite3_fprintf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
}else if( bVerbose ){
- oputf("%s/* no extra indexes required for %s -> %s */\n",
+ sqlite3_fprintf(out,
+ "%s/* no extra indexes required for %s -> %s */\n",
zIndent, zFrom, zTarget
);
}
@@ -24817,16 +27527,16 @@ static int lintFkeyIndexes(
sqlite3_free(zPrev);
if( rc!=SQLITE_OK ){
- eputf("%s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
}
rc2 = sqlite3_finalize(pSql);
if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
rc = rc2;
- eputf("%s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
}
}else{
- eputf("%s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"%s\n", sqlite3_errmsg(db));
}
return rc;
@@ -24846,9 +27556,9 @@ static int lintDotCommand(
return lintFkeyIndexes(pState, azArg, nArg);
usage:
- eputf("Usage %s sub-command ?switches...?\n", azArg[0]);
- eputz("Where sub-commands are:\n");
- eputz(" fkey-indexes\n");
+ sqlite3_fprintf(stderr,"Usage %s sub-command ?switches...?\n", azArg[0]);
+ sqlite3_fprintf(stderr, "Where sub-commands are:\n");
+ sqlite3_fprintf(stderr, " fkey-indexes\n");
return SQLITE_ERROR;
}
@@ -24862,7 +27572,8 @@ static void shellPrepare(
if( *pRc==SQLITE_OK ){
int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
if( rc!=SQLITE_OK ){
- eputf("sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
+ sqlite3_fprintf(stderr,
+ "sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
*pRc = rc;
}
}
@@ -24906,7 +27617,7 @@ static void shellFinalize(
int rc = sqlite3_finalize(pStmt);
if( *pRc==SQLITE_OK ){
if( rc!=SQLITE_OK ){
- eputf("SQL error: %s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
}
*pRc = rc;
}
@@ -24928,7 +27639,7 @@ void shellReset(
if( *pRc==SQLITE_OK ){
if( rc!=SQLITE_OK ){
sqlite3 *db = sqlite3_db_handle(pStmt);
- eputf("SQL error: %s\n", sqlite3_errmsg(db));
+ sqlite3_fprintf(stderr,"SQL error: %s\n", sqlite3_errmsg(db));
}
*pRc = rc;
}
@@ -24957,6 +27668,7 @@ struct ArCommand {
const char *zDir; /* --directory argument, or NULL */
char **azArg; /* Array of command arguments */
ShellState *p; /* Shell state */
+ FILE *out; /* Output to this stream */
sqlite3 *db; /* Database containing the archive */
};
@@ -24978,11 +27690,11 @@ static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){
va_start(ap, zFmt);
z = sqlite3_vmprintf(zFmt, ap);
va_end(ap);
- eputf("Error: %s\n", z);
+ shellEmitError(z);
if( pAr->fromCmdLine ){
- eputz("Use \"-A\" for more help\n");
+ sqlite3_fputs("Use \"-A\" for more help\n", stderr);
}else{
- eputz("Use \".archive --help\" for more help\n");
+ sqlite3_fputs("Use \".archive --help\" for more help\n", stderr);
}
sqlite3_free(z);
return SQLITE_ERROR;
@@ -25035,7 +27747,7 @@ static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
break;
case AR_SWITCH_APPEND:
pAr->bAppend = 1;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case AR_SWITCH_FILE:
pAr->zFile = zArg;
break;
@@ -25082,7 +27794,7 @@ static int arParseCommand(
struct ArSwitch *pEnd = &aSwitch[nSwitch];
if( nArg<=1 ){
- eputz("Wrong number of arguments. Usage:\n");
+ sqlite3_fprintf(stderr, "Wrong number of arguments. Usage:\n");
return arUsage(stderr);
}else{
char *z = azArg[1];
@@ -25188,7 +27900,7 @@ static int arParseCommand(
}
}
if( pAr->eCmd==0 ){
- eputz("Required argument missing. Usage:\n");
+ sqlite3_fprintf(stderr, "Required argument missing. Usage:\n");
return arUsage(stderr);
}
return SQLITE_OK;
@@ -25231,7 +27943,7 @@ static int arCheckEntries(ArCommand *pAr){
}
shellReset(&rc, pTest);
if( rc==SQLITE_OK && bOk==0 ){
- eputf("not found in archive: %s\n", z);
+ sqlite3_fprintf(stderr,"not found in archive: %s\n", z);
rc = SQLITE_ERROR;
}
}
@@ -25298,15 +28010,15 @@ static int arListCommand(ArCommand *pAr){
shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
pAr->zSrcTable, zWhere);
if( pAr->bDryRun ){
- oputf("%s\n", sqlite3_sql(pSql));
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_sql(pSql));
}else{
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
if( pAr->bVerbose ){
- oputf("%s % 10d %s %s\n",
+ sqlite3_fprintf(pAr->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{
- oputf("%s\n", sqlite3_column_text(pSql, 0));
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
}
}
}
@@ -25333,7 +28045,7 @@ static int arRemoveCommand(ArCommand *pAr){
zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;",
pAr->zSrcTable, zWhere);
if( pAr->bDryRun ){
- oputf("%s\n", zSql);
+ sqlite3_fprintf(pAr->out, "%s\n", zSql);
}else{
char *zErr = 0;
rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0);
@@ -25346,7 +28058,7 @@ static int arRemoveCommand(ArCommand *pAr){
}
}
if( zErr ){
- sputf(stdout, "ERROR: %s\n", zErr); /* stdout? */
+ sqlite3_fprintf(stdout, "ERROR: %s\n", zErr); /* stdout? */
sqlite3_free(zErr);
}
}
@@ -25410,11 +28122,11 @@ static int arExtractCommand(ArCommand *pAr){
j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
sqlite3_bind_int(pSql, j, i);
if( pAr->bDryRun ){
- oputf("%s\n", sqlite3_sql(pSql));
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_sql(pSql));
}else{
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
if( i==0 && pAr->bVerbose ){
- oputf("%s\n", sqlite3_column_text(pSql, 0));
+ sqlite3_fprintf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
}
}
}
@@ -25434,13 +28146,13 @@ static int arExtractCommand(ArCommand *pAr){
static int arExecSql(ArCommand *pAr, const char *zSql){
int rc;
if( pAr->bDryRun ){
- oputf("%s\n", zSql);
+ sqlite3_fprintf(pAr->out, "%s\n", zSql);
rc = SQLITE_OK;
}else{
char *zErr = 0;
rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
if( zErr ){
- sputf(stdout, "ERROR: %s\n", zErr);
+ sqlite3_fprintf(stdout, "ERROR: %s\n", zErr);
sqlite3_free(zErr);
}
}
@@ -25589,6 +28301,7 @@ static int arDotCommand(
if( rc==SQLITE_OK ){
int eDbType = SHELL_OPEN_UNSPEC;
cmd.p = pState;
+ cmd.out = pState->out;
cmd.db = pState->db;
if( cmd.zFile ){
eDbType = deduceDatabaseType(cmd.zFile, 1);
@@ -25615,13 +28328,14 @@ static int arDotCommand(
}
cmd.db = 0;
if( cmd.bDryRun ){
- oputf("-- open database '%s'%s\n", cmd.zFile,
+ sqlite3_fprintf(cmd.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 ){
- eputf("cannot open file: %s (%s)\n", cmd.zFile, sqlite3_errmsg(cmd.db));
+ sqlite3_fprintf(stderr, "cannot open file: %s (%s)\n",
+ cmd.zFile, sqlite3_errmsg(cmd.db));
goto end_ar_command;
}
sqlite3_fileio_init(cmd.db, 0, 0);
@@ -25634,7 +28348,7 @@ static int arDotCommand(
if( cmd.eCmd!=AR_CMD_CREATE
&& sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
){
- eputz("database does not contain an 'sqlar' table\n");
+ sqlite3_fprintf(stderr, "database does not contain an 'sqlar' table\n");
rc = SQLITE_ERROR;
goto end_ar_command;
}
@@ -25692,7 +28406,7 @@ end_ar_command:
*/
static int recoverSqlCb(void *pCtx, const char *zSql){
ShellState *pState = (ShellState*)pCtx;
- sputf(pState->out, "%s;\n", zSql);
+ sqlite3_fprintf(pState->out, "%s;\n", zSql);
return SQLITE_OK;
}
@@ -25735,7 +28449,7 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
bRowids = 0;
}
else{
- eputf("unexpected option: %s\n", azArg[i]);
+ sqlite3_fprintf(stderr,"unexpected option: %s\n", azArg[i]);
showHelp(pState->out, azArg[0]);
return 1;
}
@@ -25750,11 +28464,12 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids);
sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist);
+ sqlite3_fprintf(pState->out, ".dbconfig defensive off\n");
sqlite3_recover_run(p);
if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
const char *zErr = sqlite3_recover_errmsg(p);
int errCode = sqlite3_recover_errcode(p);
- eputf("sql error: %s (%d)\n", zErr, errCode);
+ sqlite3_fprintf(stderr,"sql error: %s (%d)\n", zErr, errCode);
}
rc = sqlite3_recover_finish(p);
return rc;
@@ -25776,7 +28491,7 @@ static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){
while( SQLITE_OK==sqlite3_intck_step(p) ){
const char *zMsg = sqlite3_intck_message(p);
if( zMsg ){
- oputf("%s\n", zMsg);
+ sqlite3_fprintf(pState->out, "%s\n", zMsg);
nError++;
}
nStep++;
@@ -25786,11 +28501,11 @@ static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){
}
rc = sqlite3_intck_error(p, &zErr);
if( zErr ){
- eputf("%s\n", zErr);
+ sqlite3_fprintf(stderr,"%s\n", zErr);
}
sqlite3_intck_close(p);
- oputf("%lld steps, %lld errors\n", nStep, nError);
+ sqlite3_fprintf(pState->out, "%lld steps, %lld errors\n", nStep, nError);
}
return rc;
@@ -25813,7 +28528,7 @@ static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){
#define rc_err_oom_die(rc) \
if( rc==SQLITE_NOMEM ) shell_check_oom(0); \
else if(!(rc==SQLITE_OK||rc==SQLITE_DONE)) \
- eputf("E:%d\n",rc), assert(0)
+ sqlite3_fprintf(stderr,"E:%d\n",rc), assert(0)
#else
static void rc_err_oom_die(int rc){
if( rc==SQLITE_NOMEM ) shell_check_oom(0);
@@ -25971,8 +28686,8 @@ FROM (\
}else{
/* Formulate the columns spec, close the DB, zero *pDb. */
char *zColsSpec = 0;
- int hasDupes = db_int(*pDb, zHasDupes);
- int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
+ int hasDupes = db_int(*pDb, "%s", zHasDupes);
+ int nDigits = (hasDupes)? db_int(*pDb, "%s", zColDigits) : 0;
if( hasDupes ){
#ifdef SHELL_COLUMN_RENAME_CLEAN
rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
@@ -25987,7 +28702,7 @@ FROM (\
sqlite3_finalize(pStmt);
if( rc!=SQLITE_DONE ) rc_err_oom_die(SQLITE_NOMEM);
}
- assert(db_int(*pDb, zHasDupes)==0); /* Consider: remove this */
+ assert(db_int(*pDb, "%s", zHasDupes)==0); /* Consider: remove this */
rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
rc_err_oom_die(rc);
rc = sqlite3_step(pStmt);
@@ -26030,8 +28745,9 @@ static int outputDumpWarning(ShellState *p, const char *zLike){
"sql LIKE 'CREATE VIRTUAL TABLE%%' AND %s", zLike ? zLike : "true"
);
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
- oputz("/* WARNING: "
- "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n"
+ sqlite3_fputs("/* WARNING: "
+ "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n",
+ p->out
);
}
shellFinalize(&rc, pStmt);
@@ -26062,12 +28778,14 @@ static int faultsim_callback(int iArg){
if( faultsim_state.iCnt ){
if( faultsim_state.iCnt>0 ) faultsim_state.iCnt--;
if( faultsim_state.eVerbose>=2 ){
- oputf("FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
+ sqlite3_fprintf(stdout,
+ "FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
}
return SQLITE_OK;
}
if( faultsim_state.eVerbose>=1 ){
- oputf("FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
+ sqlite3_fprintf(stdout,
+ "FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
}
faultsim_state.iCnt = faultsim_state.iInterval;
faultsim_state.nHit++;
@@ -26130,7 +28848,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifndef SQLITE_OMIT_AUTHORIZATION
if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
if( nArg!=2 ){
- eputz("Usage: .auth ON|OFF\n");
+ sqlite3_fprintf(stderr, "Usage: .auth ON|OFF\n");
rc = 1;
goto meta_command_exit;
}
@@ -26177,7 +28895,7 @@ static int do_meta_command(char *zLine, ShellState *p){
bAsync = 1;
}else
{
- eputf("unknown option: %s\n", azArg[j]);
+ sqlite3_fprintf(stderr,"unknown option: %s\n", azArg[j]);
return 1;
}
}else if( zDestFile==0 ){
@@ -26186,19 +28904,19 @@ static int do_meta_command(char *zLine, ShellState *p){
zDb = zDestFile;
zDestFile = azArg[j];
}else{
- eputz("Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
+ sqlite3_fprintf(stderr, "Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
return 1;
}
}
if( zDestFile==0 ){
- eputz("missing FILENAME argument on .backup\n");
+ sqlite3_fprintf(stderr, "missing FILENAME argument on .backup\n");
return 1;
}
if( zDb==0 ) zDb = "main";
rc = sqlite3_open_v2(zDestFile, &pDest,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
if( rc!=SQLITE_OK ){
- eputf("Error: cannot open \"%s\"\n", zDestFile);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zDestFile);
close_db(pDest);
return 1;
}
@@ -26209,7 +28927,7 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
if( pBackup==0 ){
- eputf("Error: %s\n", sqlite3_errmsg(pDest));
+ shellDatabaseError(pDest);
close_db(pDest);
return 1;
}
@@ -26218,7 +28936,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc==SQLITE_DONE ){
rc = 0;
}else{
- eputf("Error: %s\n", sqlite3_errmsg(pDest));
+ shellDatabaseError(pDest);
rc = 1;
}
close_db(pDest);
@@ -26234,19 +28952,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- /* Undocumented. Legacy only. See "crnl" below */
+ /* Undocumented. Legacy only. See "crlf" below */
if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
- if( nArg==2 ){
- if( booleanValue(azArg[1]) ){
- setBinaryMode(p->out, 1);
- }else{
- setTextMode(p->out, 1);
- }
- }else{
- eputz("The \".binary\" command is deprecated. Use \".crnl\" instead.\n"
- "Usage: .binary on|off\n");
- rc = 1;
- }
+ eputz("The \".binary\" command is deprecated.\n");
+ rc = 1;
}else
/* The undocumented ".breakpoint" command causes a call to the no-op
@@ -26268,7 +28977,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = chdir(azArg[1]);
#endif
if( rc ){
- eputf("Cannot change to directory \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Cannot change to directory \"%s\"\n", azArg[1]);
rc = 1;
}
}else{
@@ -26301,11 +29010,12 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
rc = 2;
}else if( testcase_glob(azArg[1],zRes)==0 ){
- eputf("testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
+ sqlite3_fprintf(stderr,
+ "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
p->zTestcase, azArg[1], zRes);
rc = 1;
}else{
- oputf("testcase-%s ok\n", p->zTestcase);
+ sqlite3_fprintf(p->out, "testcase-%s ok\n", p->zTestcase);
p->nCheck++;
}
sqlite3_free(zRes);
@@ -26338,9 +29048,9 @@ static int do_meta_command(char *zLine, ShellState *p){
zFile = "(temporary-file)";
}
if( p->pAuxDb == &p->aAuxDb[i] ){
- sputf(stdout, "ACTIVE %d: %s\n", i, zFile);
+ sqlite3_fprintf(stdout, "ACTIVE %d: %s\n", i, zFile);
}else if( p->aAuxDb[i].db!=0 ){
- sputf(stdout, " %d: %s\n", i, zFile);
+ sqlite3_fprintf(stdout, " %d: %s\n", i, zFile);
}
}
}else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){
@@ -26370,20 +29080,18 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='c' && n==4 && cli_strncmp(azArg[0], "crnl", n)==0 ){
+ if( c=='c' && n==4
+ && (cli_strncmp(azArg[0], "crlf", n)==0
+ || cli_strncmp(azArg[0], "crnl",n)==0)
+ ){
if( nArg==2 ){
- if( booleanValue(azArg[1]) ){
- setTextMode(p->out, 1);
- }else{
- setBinaryMode(p->out, 1);
- }
- }else{
-#if !defined(_WIN32) && !defined(WIN32)
- eputz("The \".crnl\" is a no-op on non-Windows machines.\n");
+#ifdef _WIN32
+ p->crlfMode = booleanValue(azArg[1]);
+#else
+ p->crlfMode = 0;
#endif
- eputz("Usage: .crnl on|off\n");
- rc = 1;
}
+ sqlite3_fprintf(stderr, "crlf is %s\n", p->crlfMode ? "ON" : "OFF");
}else
if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
@@ -26394,7 +29102,7 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ){
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
rc = 1;
}else{
while( sqlite3_step(pStmt)==SQLITE_ROW ){
@@ -26413,7 +29121,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int eTxn = sqlite3_txn_state(p->db, azName[i*2]);
int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]);
const char *z = azName[i*2+1];
- oputf("%s: %s %s%s\n",
+ sqlite3_fprintf(p->out, "%s: %s %s%s\n",
azName[i*2], z && z[0] ? z : "\"\"", bRdonly ? "r/o" : "r/w",
eTxn==SQLITE_TXN_NONE ? "" :
eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
@@ -26428,6 +29136,9 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zName;
int op;
} aDbConfig[] = {
+ { "attach_create", SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE },
+ { "attach_write", SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE },
+ { "comments", SQLITE_DBCONFIG_ENABLE_COMMENTS },
{ "defensive", SQLITE_DBCONFIG_DEFENSIVE },
{ "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
{ "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
@@ -26455,11 +29166,12 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
}
sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
- oputf("%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
+ sqlite3_fprintf(p->out, "%19s %s\n",
+ aDbConfig[ii].zName, v ? "on" : "off");
if( nArg>1 ) break;
}
if( nArg>1 && ii==ArraySize(aDbConfig) ){
- eputf("Error: unknown dbconfig \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Error: unknown dbconfig \"%s\"\n", azArg[1]);
eputz("Enter \".dbconfig\" with no arguments for a list\n");
}
}else
@@ -26509,7 +29221,8 @@ static int do_meta_command(char *zLine, ShellState *p){
ShellSetFlag(p, SHFLG_DumpNoSys);
}else
{
- eputf("Unknown option \"%s\" on \".dump\"\n", azArg[i]);
+ sqlite3_fprintf(stderr,
+ "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
rc = 1;
sqlite3_free(zLike);
goto meta_command_exit;
@@ -26544,8 +29257,8 @@ static int do_meta_command(char *zLine, ShellState *p){
/* 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. */
- oputz("PRAGMA foreign_keys=OFF;\n");
- oputz("BEGIN TRANSACTION;\n");
+ sqlite3_fputs("PRAGMA foreign_keys=OFF;\n", p->out);
+ sqlite3_fputs("BEGIN TRANSACTION;\n", p->out);
}
p->writableSchema = 0;
p->showHeader = 0;
@@ -26577,13 +29290,13 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_free(zLike);
if( p->writableSchema ){
- oputz("PRAGMA writable_schema=OFF;\n");
+ sqlite3_fputs("PRAGMA writable_schema=OFF;\n", p->out);
p->writableSchema = 0;
}
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
- oputz(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
+ sqlite3_fputs(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n", p->out);
}
p->showHeader = savedShowHeader;
p->shellFlgs = savedShellFlags;
@@ -26598,6 +29311,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){
+ rc = shell_dbtotxt_command(p, nArg, azArg);
+ }else
+
if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
if( nArg==2 ){
p->autoEQPtest = 0;
@@ -26663,7 +29380,8 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){
if( p->bSafeMode ){
- eputf("Cannot run experimental commands such as \"%s\" in safe mode\n",
+ sqlite3_fprintf(stderr,
+ "Cannot run experimental commands such as \"%s\" in safe mode\n",
azArg[0]);
rc = 1;
}else{
@@ -26720,9 +29438,10 @@ static int do_meta_command(char *zLine, ShellState *p){
/* --help lists all file-controls */
if( cli_strcmp(zCmd,"help")==0 ){
- oputz("Available file-controls:\n");
+ sqlite3_fputs("Available file-controls:\n", p->out);
for(i=0; i<ArraySize(aCtrl); i++){
- oputf(" .filectrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage);
+ sqlite3_fprintf(p->out,
+ " .filectrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
rc = 1;
goto meta_command_exit;
@@ -26737,7 +29456,7 @@ static int do_meta_command(char *zLine, ShellState *p){
filectrl = aCtrl[i].ctrlCode;
iCtrl = i;
}else{
- eputf("Error: ambiguous file-control: \"%s\"\n"
+ sqlite3_fprintf(stderr,"Error: ambiguous file-control: \"%s\"\n"
"Use \".filectrl --help\" for help\n", zCmd);
rc = 1;
goto meta_command_exit;
@@ -26745,7 +29464,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( filectrl<0 ){
- eputf("Error: unknown file-control: %s\n"
+ sqlite3_fprintf(stderr,"Error: unknown file-control: %s\n"
"Use \".filectrl --help\" for help\n", zCmd);
}else{
switch(filectrl){
@@ -26789,7 +29508,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nArg!=2 ) break;
sqlite3_file_control(p->db, zSchema, filectrl, &z);
if( z ){
- oputf("%s\n", z);
+ sqlite3_fprintf(p->out, "%s\n", z);
sqlite3_free(z);
}
isOk = 2;
@@ -26803,19 +29522,20 @@ static int do_meta_command(char *zLine, ShellState *p){
}
x = -1;
sqlite3_file_control(p->db, zSchema, filectrl, &x);
- oputf("%d\n", x);
+ sqlite3_fprintf(p->out, "%d\n", x);
isOk = 2;
break;
}
}
}
if( isOk==0 && iCtrl>=0 ){
- oputf("Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
+ sqlite3_fprintf(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);
- oputf("%s\n", zBuf);
+ sqlite3_fprintf(p->out, "%s\n", zBuf);
}
}else
@@ -26856,15 +29576,15 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( doStats==0 ){
- oputz("/* No STAT tables available */\n");
+ sqlite3_fputs("/* No STAT tables available */\n", p->out);
}else{
- oputz("ANALYZE sqlite_schema;\n");
+ sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
data.cMode = data.mode = MODE_Insert;
data.zDestTable = "sqlite_stat1";
shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
data.zDestTable = "sqlite_stat4";
shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
- oputz("ANALYZE sqlite_schema;\n");
+ sqlite3_fputs("ANALYZE sqlite_schema;\n", p->out);
}
}else
@@ -26882,7 +29602,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nArg>=2 ){
n = showHelp(p->out, azArg[1]);
if( n==0 ){
- oputf("Nothing matches '%s'\n", azArg[1]);
+ sqlite3_fprintf(p->out, "Nothing matches '%s'\n", azArg[1]);
}
}else{
showHelp(p->out, 0);
@@ -26925,7 +29645,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( zTable==0 ){
zTable = z;
}else{
- oputf("ERROR: extra argument: \"%s\". Usage:\n", z);
+ sqlite3_fprintf(p->out, "ERROR: extra argument: \"%s\". Usage:\n",z);
showHelp(p->out, "import");
goto meta_command_exit;
}
@@ -26946,13 +29666,13 @@ static int do_meta_command(char *zLine, ShellState *p){
xRead = csv_read_one_field;
useOutputMode = 0;
}else{
- oputf("ERROR: unknown option: \"%s\". Usage:\n", z);
+ sqlite3_fprintf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
showHelp(p->out, "import");
goto meta_command_exit;
}
}
if( zTable==0 ){
- oputf("ERROR: missing %s argument. Usage:\n",
+ sqlite3_fprintf(p->out, "ERROR: missing %s argument. Usage:\n",
zFile==0 ? "FILE" : "TABLE");
showHelp(p->out, "import");
goto meta_command_exit;
@@ -27002,28 +29722,28 @@ static int do_meta_command(char *zLine, ShellState *p){
eputz("Error: pipes are not supported in this OS\n");
goto meta_command_exit;
#else
- sCtx.in = popen(sCtx.zFile+1, "r");
+ sCtx.in = sqlite3_popen(sCtx.zFile+1, "r");
sCtx.zFile = "<pipe>";
sCtx.xCloser = pclose;
#endif
}else{
- sCtx.in = fopen(sCtx.zFile, "rb");
+ sCtx.in = sqlite3_fopen(sCtx.zFile, "rb");
sCtx.xCloser = fclose;
}
if( sCtx.in==0 ){
- eputf("Error: cannot open \"%s\"\n", zFile);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zFile);
goto meta_command_exit;
}
if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
char zSep[2];
zSep[1] = 0;
zSep[0] = sCtx.cColSep;
- oputz("Column separator ");
- output_c_string(zSep);
- oputz(", row separator ");
+ sqlite3_fputs("Column separator ", p->out);
+ output_c_string(p->out, zSep);
+ sqlite3_fputs(", row separator ", p->out);
zSep[0] = sCtx.cRowSep;
- output_c_string(zSep);
- oputz("\n");
+ output_c_string(p->out, zSep);
+ sqlite3_fputs("\n", p->out);
}
sCtx.z = sqlite3_malloc64(120);
if( sCtx.z==0 ){
@@ -27035,7 +29755,11 @@ static int do_meta_command(char *zLine, ShellState *p){
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
}
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
- if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0) ){
+ if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0)
+ && 0==db_int(p->db, "SELECT count(*) FROM \"%w\".sqlite_schema"
+ " WHERE name=%Q AND type='view'",
+ zSchema ? zSchema : "main", zTable)
+ ){
/* Table does not exist. Create it. */
sqlite3 *dbCols = 0;
char *zRenames = 0;
@@ -27048,16 +29772,17 @@ static int do_meta_command(char *zLine, ShellState *p){
}
zColDefs = zAutoColumn(0, &dbCols, &zRenames);
if( zRenames!=0 ){
- sputf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
+ sqlite3_fprintf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
"Columns renamed during .import %s due to duplicates:\n"
"%s\n", sCtx.zFile, zRenames);
sqlite3_free(zRenames);
}
assert(dbCols==0);
if( zColDefs==0 ){
- eputf("%s: empty file\n", sCtx.zFile);
+ sqlite3_fprintf(stderr,"%s: empty file\n", sCtx.zFile);
import_cleanup(&sCtx);
rc = 1;
+ sqlite3_free(zCreate);
goto meta_command_exit;
}
zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs);
@@ -27066,13 +29791,16 @@ static int do_meta_command(char *zLine, ShellState *p){
shell_out_of_memory();
}
if( eVerbose>=1 ){
- oputf("%s\n", zCreate);
+ sqlite3_fprintf(p->out, "%s\n", zCreate);
}
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
+ if( rc ){
+ sqlite3_fprintf(stderr,
+ "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
+ }
sqlite3_free(zCreate);
zCreate = 0;
if( rc ){
- eputf("%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
@@ -27089,7 +29817,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zSql = 0;
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
import_cleanup(&sCtx);
rc = 1;
goto meta_command_exit;
@@ -27127,13 +29855,13 @@ static int do_meta_command(char *zLine, ShellState *p){
zSql[j] = 0;
assert( j<nByte );
if( eVerbose>=2 ){
- oputf("Insert using: %s\n", zSql);
+ sqlite3_fprintf(p->out, "Insert using: %s\n", zSql);
}
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
zSql = 0;
if( rc ){
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
if (pStmt) sqlite3_finalize(pStmt);
import_cleanup(&sCtx);
rc = 1;
@@ -27166,7 +29894,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
- eputf("%s:%d: expected %d columns but found %d"
+ sqlite3_fprintf(stderr,"%s:%d: expected %d columns but found %d"
" - filling the rest with NULL\n",
sCtx.zFile, startLine, nCol, i+1);
i += 2;
@@ -27178,14 +29906,15 @@ static int do_meta_command(char *zLine, ShellState *p){
xRead(&sCtx);
i++;
}while( sCtx.cTerm==sCtx.cColSep );
- eputf("%s:%d: expected %d columns but found %d - extras ignored\n",
+ sqlite3_fprintf(stderr,
+ "%s:%d: expected %d columns but found %d - extras ignored\n",
sCtx.zFile, startLine, nCol, i);
}
if( i>=nCol ){
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
if( rc!=SQLITE_OK ){
- eputf("%s:%d: INSERT failed: %s\n",
+ sqlite3_fprintf(stderr,"%s:%d: INSERT failed: %s\n",
sCtx.zFile, startLine, sqlite3_errmsg(p->db));
sCtx.nErr++;
}else{
@@ -27198,7 +29927,8 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
if( eVerbose>0 ){
- oputf("Added %d rows with %d errors using %d lines of input\n",
+ sqlite3_fprintf(p->out,
+ "Added %d rows with %d errors using %d lines of input\n",
sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
}
}else
@@ -27214,7 +29944,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
int i;
if( !ShellHasFlag(p,SHFLG_TestingMode) ){
- eputf(".%s unavailable without --unsafe-testing\n",
+ sqlite3_fprintf(stderr,".%s unavailable without --unsafe-testing\n",
"imposter");
rc = 1;
goto meta_command_exit;
@@ -27280,7 +30010,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_finalize(pStmt);
if( i==0 || tnum==0 ){
- eputf("no such index: \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"no such index: \"%s\"\n", azArg[1]);
rc = 1;
sqlite3_free(zCollist);
goto meta_command_exit;
@@ -27295,14 +30025,16 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
if( rc ){
- eputf("Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
+ sqlite3_fprintf(stderr,
+ "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
}else{
- sputf(stdout, "%s;\n", zSql);
- sputf(stdout, "WARNING: writing to an imposter table will corrupt"
+ sqlite3_fprintf(stdout, "%s;\n", zSql);
+ sqlite3_fprintf(stdout,
+ "WARNING: writing to an imposter table will corrupt"
" the \"%s\" %s!\n", azArg[1], isWO ? "table" : "index");
}
}else{
- eputf("SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
+ sqlite3_fprintf(stderr,"SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
rc = 1;
}
sqlite3_free(zSql);
@@ -27316,7 +30048,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( iArg==0 ) iArg = -1;
}
if( (nArg!=1 && nArg!=2) || iArg<0 ){
- eputf("%s","Usage: .intck STEPS_PER_UNLOCK\n");
+ sqlite3_fprintf(stderr,"%s","Usage: .intck STEPS_PER_UNLOCK\n");
rc = 1;
goto meta_command_exit;
}
@@ -27335,9 +30067,9 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3IoTrace = iotracePrintf;
iotrace = stdout;
}else{
- iotrace = fopen(azArg[1], "w");
+ iotrace = sqlite3_fopen(azArg[1], "w");
if( iotrace==0 ){
- eputf("Error: cannot open \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
sqlite3IoTrace = 0;
rc = 1;
}else{
@@ -27369,7 +30101,7 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
if( nArg==1 ){
for(i=0; i<ArraySize(aLimit); i++){
- sputf(stdout, "%20s %d\n", aLimit[i].zLimitName,
+ sqlite3_fprintf(stdout, "%20s %d\n", aLimit[i].zLimitName,
sqlite3_limit(p->db, aLimit[i].limitCode, -1));
}
}else if( nArg>3 ){
@@ -27384,14 +30116,14 @@ static int do_meta_command(char *zLine, ShellState *p){
if( iLimit<0 ){
iLimit = i;
}else{
- eputf("ambiguous limit: \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"ambiguous limit: \"%s\"\n", azArg[1]);
rc = 1;
goto meta_command_exit;
}
}
}
if( iLimit<0 ){
- eputf("unknown limit: \"%s\"\n"
+ sqlite3_fprintf(stderr,"unknown limit: \"%s\"\n"
"enter \".limits\" with no arguments for a list.\n",
azArg[1]);
rc = 1;
@@ -27401,7 +30133,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_limit(p->db, aLimit[iLimit].limitCode,
(int)integerValue(azArg[2]));
}
- sputf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName,
+ sqlite3_fprintf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName,
sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
}
}else
@@ -27427,7 +30159,7 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
if( rc!=SQLITE_OK ){
- eputf("Error: %s\n", zErrMsg);
+ shellEmitError(zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}
@@ -27450,7 +30182,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
output_file_close(p->pLog);
if( cli_strcmp(zFile,"on")==0 ) zFile = "stdout";
- p->pLog = output_file_open(zFile, 0);
+ p->pLog = output_file_open(zFile);
}
}else
@@ -27458,24 +30190,52 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zMode = 0;
const char *zTabname = 0;
int i, n2;
+ int chng = 0; /* 0x01: change to cmopts. 0x02: Any other change */
ColModeOpts cmOpts = ColModeOpts_default;
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( optionMatch(z,"wrap") && i+1<nArg ){
cmOpts.iWrap = integerValue(azArg[++i]);
+ chng |= 1;
}else if( optionMatch(z,"ww") ){
cmOpts.bWordWrap = 1;
+ chng |= 1;
}else if( optionMatch(z,"wordwrap") && i+1<nArg ){
cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
+ chng |= 1;
}else if( optionMatch(z,"quote") ){
cmOpts.bQuote = 1;
+ chng |= 1;
}else if( optionMatch(z,"noquote") ){
cmOpts.bQuote = 0;
+ chng |= 1;
+ }else if( optionMatch(z,"escape") && i+1<nArg ){
+ /* See similar code at tag-20250224-1 */
+ const char *zEsc = azArg[++i];
+ int k;
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
+ if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
+ p->eEscMode = k;
+ chng |= 2;
+ break;
+ }
+ }
+ if( k>=ArraySize(shell_EscModeNames) ){
+ sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
+ " - choices:", zEsc);
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
+ sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
+ }
+ sqlite3_fprintf(stderr, "\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
}else if( zMode==0 ){
zMode = z;
/* Apply defaults for qbox pseudo-mode. If that
* overwrites already-set values, user was informed of this.
*/
+ chng |= 1;
if( cli_strcmp(z, "qbox")==0 ){
ColModeOpts cmo = ColModeOpts_default_qbox;
zMode = "box";
@@ -27484,8 +30244,9 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( zTabname==0 ){
zTabname = z;
}else if( z[0]=='-' ){
- eputf("unknown option: %s\n", z);
+ sqlite3_fprintf(stderr,"unknown option: %s\n", z);
eputz("options:\n"
+ " --escape MODE\n"
" --noquote\n"
" --quote\n"
" --wordwrap on/off\n"
@@ -27494,23 +30255,34 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
goto meta_command_exit;
}else{
- eputf("extra argument: \"%s\"\n", z);
+ sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
rc = 1;
goto meta_command_exit;
}
}
- if( zMode==0 ){
+ if( !chng ){
if( p->mode==MODE_Column
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
){
- oputf("current output mode: %s --wrap %d --wordwrap %s --%squote\n",
+ sqlite3_fprintf(p->out,
+ "current output mode: %s --wrap %d --wordwrap %s "
+ "--%squote --escape %s\n",
modeDescr[p->mode], p->cmOpts.iWrap,
p->cmOpts.bWordWrap ? "on" : "off",
- p->cmOpts.bQuote ? "" : "no");
+ p->cmOpts.bQuote ? "" : "no",
+ shell_EscModeNames[p->eEscMode]
+ );
}else{
- oputf("current output mode: %s\n", modeDescr[p->mode]);
+ sqlite3_fprintf(p->out,
+ "current output mode: %s --escape %s\n",
+ modeDescr[p->mode],
+ shell_EscModeNames[p->eEscMode]
+ );
}
+ }
+ if( zMode==0 ){
zMode = modeDescr[p->mode];
+ if( (chng&1)==0 ) cmOpts = p->cmOpts;
}
n2 = strlen30(zMode);
if( cli_strncmp(zMode,"lines",n2)==0 ){
@@ -27543,6 +30315,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( cli_strncmp(zMode,"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, zTabname ? zTabname : "table");
+ if( p->eEscMode==SHELL_ESC_OFF ){
+ ShellSetFlag(p, SHFLG_Newlines);
+ }else{
+ ShellClearFlag(p, SHFLG_Newlines);
+ }
}else if( cli_strncmp(zMode,"quote",n2)==0 ){
p->mode = MODE_Quote;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
@@ -27581,7 +30358,7 @@ static int do_meta_command(char *zLine, ShellState *p){
eputz("Usage: .nonce NONCE\n");
rc = 1;
}else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
- eputf("line %d: incorrect nonce: \"%s\"\n",
+ sqlite3_fprintf(stderr,"line %d: incorrect nonce: \"%s\"\n",
p->lineno, azArg[1]);
exit(1);
}else{
@@ -27636,11 +30413,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif /* !SQLITE_SHELL_FIDDLE */
if( z[0]=='-' ){
- eputf("unknown option: %s\n", z);
+ sqlite3_fprintf(stderr,"unknown option: %s\n", z);
rc = 1;
goto meta_command_exit;
}else if( zFN ){
- eputf("extra argument: \"%s\"\n", z);
+ sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
rc = 1;
goto meta_command_exit;
}else{
@@ -27682,7 +30459,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->pAuxDb->zDbFilename = zNewFilename;
open_db(p, OPEN_DB_KEEPALIVE);
if( p->db==0 ){
- eputf("Error: cannot open '%s'\n", zNewFilename);
+ sqlite3_fprintf(stderr,"Error: cannot open '%s'\n", zNewFilename);
sqlite3_free(zNewFilename);
}else{
p->pAuxDb->zFreeOnClose = zNewFilename;
@@ -27700,19 +30477,23 @@ static int do_meta_command(char *zLine, ShellState *p){
&& (cli_strncmp(azArg[0], "output", n)==0
|| cli_strncmp(azArg[0], "once", n)==0))
|| (c=='e' && n==5 && cli_strcmp(azArg[0],"excel")==0)
+ || (c=='w' && n==3 && cli_strcmp(azArg[0],"www")==0)
){
char *zFile = 0;
- int bTxtMode = 0;
int i;
- int eMode = 0;
- int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
- static const char *zBomUtf8 = "\xef\xbb\xbf";
+ int eMode = 0; /* 0: .outout/.once, 'x'=.excel, 'w'=.www */
+ int bOnce = 0; /* 0: .output, 1: .once, 2: .excel/.www */
+ int bPlain = 0; /* --plain option */
+ static const char *zBomUtf8 = "\357\273\277";
const char *zBom = 0;
failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
if( c=='e' ){
eMode = 'x';
bOnce = 2;
+ }else if( c=='w' ){
+ eMode = 'w';
+ bOnce = 2;
}else if( cli_strncmp(azArg[0],"once",n)==0 ){
bOnce = 1;
}
@@ -27722,24 +30503,38 @@ static int do_meta_command(char *zLine, ShellState *p){
if( z[1]=='-' ) z++;
if( cli_strcmp(z,"-bom")==0 ){
zBom = zBomUtf8;
- }else if( c!='e' && cli_strcmp(z,"-x")==0 ){
+ }else if( cli_strcmp(z,"-plain")==0 ){
+ bPlain = 1;
+ }else if( c=='o' && cli_strcmp(z,"-x")==0 ){
eMode = 'x'; /* spreadsheet */
- }else if( c!='e' && cli_strcmp(z,"-e")==0 ){
+ }else if( c=='o' && cli_strcmp(z,"-e")==0 ){
eMode = 'e'; /* text editor */
+ }else if( c=='o' && cli_strcmp(z,"-w")==0 ){
+ eMode = 'w'; /* Web browser */
}else{
- oputf("ERROR: unknown option: \"%s\". Usage:\n", azArg[i]);
+ sqlite3_fprintf(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 && eMode!='e' && eMode!='x' ){
- zFile = sqlite3_mprintf("%s", z);
+ }else if( zFile==0 && eMode==0 ){
+ if( cli_strcmp(z, "off")==0 ){
+#ifdef _WIN32
+ zFile = sqlite3_mprintf("nul");
+#else
+ zFile = sqlite3_mprintf("/dev/null");
+#endif
+ }else{
+ zFile = sqlite3_mprintf("%s", z);
+ }
if( zFile && zFile[0]=='|' ){
while( i+1<nArg ) zFile = sqlite3_mprintf("%z %s", zFile, azArg[++i]);
break;
}
}else{
- oputf("ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]);
+ sqlite3_fprintf(p->out,
+ "ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]);
showHelp(p->out, azArg[0]);
rc = 1;
sqlite3_free(zFile);
@@ -27749,6 +30544,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( zFile==0 ){
zFile = sqlite3_mprintf("stdout");
}
+ shell_check_oom(zFile);
if( bOnce ){
p->outCount = 2;
}else{
@@ -27756,7 +30552,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
output_reset(p);
#ifndef SQLITE_NOHAVE_SYSTEM
- if( eMode=='e' || eMode=='x' ){
+ if( eMode=='e' || eMode=='x' || eMode=='w' ){
p->doXdgOpen = 1;
outputModePush(p);
if( eMode=='x' ){
@@ -27766,10 +30562,17 @@ static int do_meta_command(char *zLine, ShellState *p){
p->mode = MODE_Csv;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
+#ifdef _WIN32
+ zBom = zBomUtf8; /* Always include the BOM on Windows, as Excel does
+ ** not work without it. */
+#endif
+ }else if( eMode=='w' ){
+ /* web-browser mode. */
+ newTempFile(p, "html");
+ if( !bPlain ) p->mode = MODE_Www;
}else{
/* text editor mode */
newTempFile(p, "txt");
- bTxtMode = 1;
}
sqlite3_free(zFile);
zFile = sqlite3_mprintf("%s", p->zTempFile);
@@ -27782,26 +30585,34 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
output_redir(p, stdout);
#else
- FILE *pfPipe = popen(zFile + 1, "w");
+ FILE *pfPipe = sqlite3_popen(zFile + 1, "w");
if( pfPipe==0 ){
- eputf("Error: cannot open pipe \"%s\"\n", zFile + 1);
+ assert( stderr!=NULL );
+ sqlite3_fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
rc = 1;
}else{
output_redir(p, pfPipe);
- if( zBom ) oputz(zBom);
+ if( zBom ) sqlite3_fputs(zBom, pfPipe);
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
#endif
}else{
- FILE *pfFile = output_file_open(zFile, bTxtMode);
+ FILE *pfFile = output_file_open(zFile);
if( pfFile==0 ){
if( cli_strcmp(zFile,"off")!=0 ){
- eputf("Error: cannot write to \"%s\"\n", zFile);
+ assert( stderr!=NULL );
+ sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
}
rc = 1;
} else {
output_redir(p, pfFile);
- if( zBom ) oputz(zBom);
+ if( zBom ) sqlite3_fputs(zBom, pfFile);
+ if( bPlain && eMode=='w' ){
+ sqlite3_fputs(
+ "<!DOCTYPE html>\n<BODY>\n<PLAINTEXT>\n",
+ pfFile
+ );
+ }
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
}
@@ -27842,7 +30653,8 @@ static int do_meta_command(char *zLine, ShellState *p){
"SELECT key, quote(value) "
"FROM temp.sqlite_parameters;", -1, &pStmt, 0);
while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
- oputf("%-*s %s\n", len, sqlite3_column_text(pStmt,0),
+ sqlite3_fprintf(p->out,
+ "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
sqlite3_column_text(pStmt,1));
}
sqlite3_finalize(pStmt);
@@ -27887,12 +30699,13 @@ static int do_meta_command(char *zLine, ShellState *p){
rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rx!=SQLITE_OK ){
- oputf("Error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_fprintf(p->out, "Error: %s\n", sqlite3_errmsg(p->db));
sqlite3_finalize(pStmt);
pStmt = 0;
rc = 1;
}
}
+ bind_prepared_stmt(p, pStmt);
sqlite3_step(pStmt);
sqlite3_finalize(pStmt);
}else
@@ -27916,10 +30729,10 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){
int i;
for(i=1; i<nArg; i++){
- if( i>1 ) oputz(" ");
- oputz(azArg[i]);
+ if( i>1 ) sqlite3_fputs(" ", p->out);
+ sqlite3_fputs(azArg[i], p->out);
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}else
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
@@ -27956,7 +30769,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
continue;
}
- eputf("Error: unknown option: \"%s\"\n", azArg[i]);
+ sqlite3_fprintf(stderr,"Error: unknown option: \"%s\"\n", azArg[i]);
rc = 1;
goto meta_command_exit;
}else{
@@ -27997,11 +30810,10 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifdef SQLITE_OMIT_POPEN
eputz("Error: pipes are not supported in this OS\n");
rc = 1;
- p->out = stdout;
#else
- p->in = popen(azArg[1]+1, "r");
+ p->in = sqlite3_popen(azArg[1]+1, "r");
if( p->in==0 ){
- eputf("Error: cannot open \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
rc = process_input(p);
@@ -28009,7 +30821,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
#endif
}else if( (p->in = openChrSource(azArg[1]))==0 ){
- eputf("Error: cannot open \"%s\"\n", azArg[1]);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
rc = process_input(p);
@@ -28042,14 +30854,14 @@ static int do_meta_command(char *zLine, ShellState *p){
}
rc = sqlite3_open(zSrcFile, &pSrc);
if( rc!=SQLITE_OK ){
- eputf("Error: cannot open \"%s\"\n", zSrcFile);
+ sqlite3_fprintf(stderr,"Error: cannot open \"%s\"\n", zSrcFile);
close_db(pSrc);
return 1;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
if( pBackup==0 ){
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
close_db(pSrc);
return 1;
}
@@ -28067,14 +30879,17 @@ static int do_meta_command(char *zLine, ShellState *p){
eputz("Error: source database is busy\n");
rc = 1;
}else{
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
rc = 1;
}
close_db(pSrc);
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
- if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
+ if( c=='s' &&
+ (cli_strncmp(azArg[0], "scanstats", n)==0 ||
+ cli_strncmp(azArg[0], "scanstatus", n)==0)
+ ){
if( nArg==2 ){
if( cli_strcmp(azArg[1], "vm")==0 ){
p->scanstatsOn = 3;
@@ -28125,7 +30940,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( optionMatch(azArg[ii],"nosys") ){
bNoSystemTabs = 1;
}else if( azArg[ii][0]=='-' ){
- eputf("Unknown option: \"%s\"\n", azArg[ii]);
+ sqlite3_fprintf(stderr,"Unknown option: \"%s\"\n", azArg[ii]);
rc = 1;
goto meta_command_exit;
}else if( zName==0 ){
@@ -28164,7 +30979,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
-1, &pStmt, 0);
if( rc ){
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
+ shellDatabaseError(p->db);
sqlite3_finalize(pStmt);
rc = 1;
goto meta_command_exit;
@@ -28226,14 +31041,14 @@ static int do_meta_command(char *zLine, ShellState *p){
appendText(&sSelect, "sql IS NOT NULL"
" ORDER BY snum, rowid", 0);
if( bDebug ){
- oputf("SQL: %s;\n", sSelect.z);
+ sqlite3_fprintf(p->out, "SQL: %s;\n", sSelect.z);
}else{
rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
}
freeText(&sSelect);
}
if( zErrMsg ){
- eputf("Error: %s\n", zErrMsg);
+ shellEmitError(zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}else if( rc != SQLITE_OK ){
@@ -28287,7 +31102,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
rc = sqlite3session_attach(pSession->p, azCmd[1]);
if( rc ){
- eputf("ERROR: sqlite3session_attach() returns %d\n",rc);
+ sqlite3_fprintf(stderr,
+ "ERROR: sqlite3session_attach() returns %d\n",rc);
rc = 0;
}
}
@@ -28304,9 +31120,9 @@ static int do_meta_command(char *zLine, ShellState *p){
failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
if( nCmd!=2 ) goto session_syntax_error;
if( pSession->p==0 ) goto session_not_open;
- out = fopen(azCmd[1], "wb");
+ out = sqlite3_fopen(azCmd[1], "wb");
if( out==0 ){
- eputf("ERROR: cannot open \"%s\" for writing\n",
+ sqlite3_fprintf(stderr,"ERROR: cannot open \"%s\" for writing\n",
azCmd[1]);
}else{
int szChng;
@@ -28317,12 +31133,13 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
}
if( rc ){
- sputf(stdout, "Error: error code %d\n", rc);
+ sqlite3_fprintf(stdout, "Error: error code %d\n", rc);
rc = 0;
}
if( pChng
&& fwrite(pChng, szChng, 1, out)!=1 ){
- eputf("ERROR: Failed to write entire %d-byte output\n", szChng);
+ sqlite3_fprintf(stderr,
+ "ERROR: Failed to write entire %d-byte output\n", szChng);
}
sqlite3_free(pChng);
fclose(out);
@@ -28349,7 +31166,8 @@ static int do_meta_command(char *zLine, ShellState *p){
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
if( pAuxDb->nSession ){
ii = sqlite3session_enable(pSession->p, ii);
- oputf("session %s enable flag = %d\n", pSession->zName, ii);
+ sqlite3_fprintf(p->out,
+ "session %s enable flag = %d\n", pSession->zName, ii);
}
}else
@@ -28384,7 +31202,8 @@ static int do_meta_command(char *zLine, ShellState *p){
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
if( pAuxDb->nSession ){
ii = sqlite3session_indirect(pSession->p, ii);
- oputf("session %s indirect flag = %d\n", pSession->zName, ii);
+ sqlite3_fprintf(p->out,
+ "session %s indirect flag = %d\n", pSession->zName, ii);
}
}else
@@ -28396,7 +31215,8 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nCmd!=1 ) goto session_syntax_error;
if( pAuxDb->nSession ){
ii = sqlite3session_isempty(pSession->p);
- oputf("session %s isempty flag = %d\n", pSession->zName, ii);
+ sqlite3_fprintf(p->out,
+ "session %s isempty flag = %d\n", pSession->zName, ii);
}
}else
@@ -28405,7 +31225,7 @@ static int do_meta_command(char *zLine, ShellState *p){
*/
if( cli_strcmp(azCmd[0],"list")==0 ){
for(i=0; i<pAuxDb->nSession; i++){
- oputf("%d %s\n", i, pAuxDb->aSession[i].zName);
+ sqlite3_fprintf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName);
}
}else
@@ -28420,18 +31240,19 @@ static int do_meta_command(char *zLine, ShellState *p){
if( zName[0]==0 ) goto session_syntax_error;
for(i=0; i<pAuxDb->nSession; i++){
if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
- eputf("Session \"%s\" already exists\n", zName);
+ sqlite3_fprintf(stderr,"Session \"%s\" already exists\n", zName);
goto meta_command_exit;
}
}
if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){
- eputf("Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
+ sqlite3_fprintf(stderr,
+ "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
goto meta_command_exit;
}
pSession = &pAuxDb->aSession[pAuxDb->nSession];
rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
if( rc ){
- eputf("Cannot open session: error code=%d\n", rc);
+ sqlite3_fprintf(stderr,"Cannot open session: error code=%d\n", rc);
rc = 0;
goto meta_command_exit;
}
@@ -28455,7 +31276,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int i, v;
for(i=1; i<nArg; i++){
v = booleanValue(azArg[i]);
- oputf("%s: %d 0x%x\n", azArg[i], v, v);
+ sqlite3_fprintf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
}
}
if( cli_strncmp(azArg[0]+9, "integer", n-9)==0 ){
@@ -28464,7 +31285,7 @@ static int do_meta_command(char *zLine, ShellState *p){
char zBuf[200];
v = integerValue(azArg[i]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
- oputz(zBuf);
+ sqlite3_fputs(zBuf, p->out);
}
}
}else
@@ -28491,8 +31312,9 @@ static int do_meta_command(char *zLine, ShellState *p){
bVerbose++;
}else
{
- eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
- eputz("Should be one of: --init -v\n");
+ sqlite3_fprintf(stderr,
+ "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
+ sqlite3_fputs("Should be one of: --init -v\n", stderr);
rc = 1;
goto meta_command_exit;
}
@@ -28537,10 +31359,10 @@ static int do_meta_command(char *zLine, ShellState *p){
if( zAns==0 ) continue;
k = 0;
if( bVerbose>0 ){
- sputf(stdout, "%d: %s %s\n", tno, zOp, zSql);
+ sqlite3_fprintf(stdout, "%d: %s %s\n", tno, zOp, zSql);
}
if( cli_strcmp(zOp,"memo")==0 ){
- oputf("%s\n", zSql);
+ sqlite3_fprintf(p->out, "%s\n", zSql);
}else
if( cli_strcmp(zOp,"run")==0 ){
char *zErrMsg = 0;
@@ -28549,22 +31371,23 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
nTest++;
if( bVerbose ){
- oputf("Result: %s\n", str.z);
+ sqlite3_fprintf(p->out, "Result: %s\n", str.z);
}
if( rc || zErrMsg ){
nErr++;
rc = 1;
- oputf("%d: error-code-%d: %s\n", tno, rc, zErrMsg);
+ sqlite3_fprintf(p->out, "%d: error-code-%d: %s\n", tno, rc,zErrMsg);
sqlite3_free(zErrMsg);
}else if( cli_strcmp(zAns,str.z)!=0 ){
nErr++;
rc = 1;
- oputf("%d: Expected: [%s]\n", tno, zAns);
- oputf("%d: Got: [%s]\n", tno, str.z);
+ sqlite3_fprintf(p->out, "%d: Expected: [%s]\n", tno, zAns);
+ sqlite3_fprintf(p->out, "%d: Got: [%s]\n", tno, str.z);
}
}
else{
- eputf("Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
+ sqlite3_fprintf(stderr,
+ "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
rc = 1;
break;
}
@@ -28572,7 +31395,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_finalize(pStmt);
} /* End loop over k */
freeText(&str);
- oputf("%d errors out of %d tests\n", nErr, nTest);
+ sqlite3_fprintf(p->out, "%d errors out of %d tests\n", nErr, nTest);
}else
if( c=='s' && cli_strncmp(azArg[0], "separator", n)==0 ){
@@ -28620,7 +31443,8 @@ static int do_meta_command(char *zLine, ShellState *p){
bDebug = 1;
}else
{
- eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
+ sqlite3_fprintf(stderr,
+ "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]);
showHelp(p->out, azArg[0]);
rc = 1;
goto meta_command_exit;
@@ -28698,7 +31522,7 @@ static int do_meta_command(char *zLine, ShellState *p){
freeText(&sQuery);
freeText(&sSql);
if( bDebug ){
- oputf("%s\n", zSql);
+ sqlite3_fprintf(p->out, "%s\n", zSql);
}else{
shell_exec(p, zSql, 0);
}
@@ -28728,7 +31552,7 @@ static int do_meta_command(char *zLine, ShellState *p){
"' OR ') as query, tname from tabcols group by tname)"
, zRevText);
shell_check_oom(zRevText);
- if( bDebug ) oputf("%s\n", zRevText);
+ if( bDebug ) sqlite3_fprintf(p->out, "%s\n", zRevText);
lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0);
if( lrc!=SQLITE_OK ){
/* assert(lrc==SQLITE_NOMEM); // might also be SQLITE_ERROR if the
@@ -28741,7 +31565,7 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0);
sqlite3_stmt *pCheckStmt;
lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0);
- if( bDebug ) oputf("%s\n", zGenQuery);
+ if( bDebug ) sqlite3_fprintf(p->out, "%s\n", zGenQuery);
if( lrc!=SQLITE_OK ){
rc = 1;
}else{
@@ -28749,7 +31573,8 @@ static int do_meta_command(char *zLine, ShellState *p){
double countIrreversible = sqlite3_column_double(pCheckStmt, 0);
if( countIrreversible>0 ){
int sz = (int)(countIrreversible + 0.5);
- eputf("Digest includes %d invalidly encoded text field%s.\n",
+ sqlite3_fprintf(stderr,
+ "Digest includes %d invalidly encoded text field%s.\n",
sz, (sz>1)? "s": "");
}
}
@@ -28783,11 +31608,11 @@ static int do_meta_command(char *zLine, ShellState *p){
zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
zCmd, azArg[i]);
}
- consoleRestore();
+ /*consoleRestore();*/
x = zCmd!=0 ? system(zCmd) : 1;
- consoleRenewSetup();
+ /*consoleRenewSetup();*/
sqlite3_free(zCmd);
- if( x ) eputf("System command returns %d\n", x);
+ if( x ) sqlite3_fprintf(stderr,"System command returns %d\n", x);
}else
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
@@ -28800,46 +31625,48 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
goto meta_command_exit;
}
- oputf("%12.12s: %s\n","echo",
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","echo",
azBool[ShellHasFlag(p, SHFLG_Echo)]);
- oputf("%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
- oputf("%12.12s: %s\n","explain",
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","explain",
p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
- oputf("%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","headers",
+ azBool[p->showHeader!=0]);
if( p->mode==MODE_Column
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
){
- oputf("%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
+ sqlite3_fprintf(p->out,
+ "%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
modeDescr[p->mode], p->cmOpts.iWrap,
p->cmOpts.bWordWrap ? "on" : "off",
p->cmOpts.bQuote ? "" : "no");
}else{
- oputf("%12.12s: %s\n","mode", modeDescr[p->mode]);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
}
- oputf("%12.12s: ", "nullvalue");
- output_c_string(p->nullValue);
- oputz("\n");
- oputf("%12.12s: %s\n","output",
+ sqlite3_fprintf(p->out, "%12.12s: ", "nullvalue");
+ output_c_string(p->out, p->nullValue);
+ sqlite3_fputs("\n", p->out);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","output",
strlen30(p->outfile) ? p->outfile : "stdout");
- oputf("%12.12s: ", "colseparator");
- output_c_string(p->colSeparator);
- oputz("\n");
- oputf("%12.12s: ", "rowseparator");
- output_c_string(p->rowSeparator);
- oputz("\n");
+ sqlite3_fprintf(p->out, "%12.12s: ", "colseparator");
+ output_c_string(p->out, p->colSeparator);
+ sqlite3_fputs("\n", p->out);
+ sqlite3_fprintf(p->out, "%12.12s: ", "rowseparator");
+ output_c_string(p->out, p->rowSeparator);
+ sqlite3_fputs("\n", p->out);
switch( p->statsOn ){
case 0: zOut = "off"; break;
default: zOut = "on"; break;
case 2: zOut = "stmt"; break;
case 3: zOut = "vmstep"; break;
}
- oputf("%12.12s: %s\n","stats", zOut);
- oputf("%12.12s: ", "width");
+ sqlite3_fprintf(p->out, "%12.12s: %s\n","stats", zOut);
+ sqlite3_fprintf(p->out, "%12.12s: ", "width");
for (i=0;i<p->nWidth;i++) {
- oputf("%d ", p->colWidth[i]);
+ sqlite3_fprintf(p->out, "%d ", p->colWidth[i]);
}
- oputz("\n");
- oputf("%12.12s: %s\n", "filename",
+ sqlite3_fputs("\n", p->out);
+ sqlite3_fprintf(p->out, "%12.12s: %s\n", "filename",
p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
}else
@@ -28957,9 +31784,10 @@ static int do_meta_command(char *zLine, ShellState *p){
for(i=0; i<nPrintRow; i++){
for(j=i; j<nRow; j+=nPrintRow){
char *zSp = j<nPrintRow ? "" : " ";
- oputf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
+ sqlite3_fprintf(p->out,
+ "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
}
- oputz("\n");
+ sqlite3_fputs("\n", p->out);
}
}
@@ -28971,7 +31799,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* Begin redirecting output to the file "testcase-out.txt" */
if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
output_reset(p);
- p->out = output_file_open("testcase-out.txt", 0);
+ p->out = output_file_open("testcase-out.txt");
if( p->out==0 ){
eputz("Error: cannot open 'testcase-out.txt'\n");
}
@@ -29004,18 +31832,17 @@ static int do_meta_command(char *zLine, ShellState *p){
{"json_selfcheck", SQLITE_TESTCTRL_JSON_SELFCHECK ,0,"BOOLEAN" },
{"localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" },
{"never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" },
- {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" },
+ {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK ..."},
#ifdef YYCOVERAGE
{"parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" },
#endif
- {"pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,0, "OFFSET " },
+ {"pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,1, "OFFSET " },
{"prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" },
{"prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" },
{"prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" },
{"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" },
{"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" },
{"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" },
- {"uselongdouble", SQLITE_TESTCTRL_USELONGDOUBLE,0,"?BOOLEAN|\"default\"?"},
};
int testctrl = -1;
int iCtrl = -1;
@@ -29035,10 +31862,10 @@ static int do_meta_command(char *zLine, ShellState *p){
/* --help lists all test-controls */
if( cli_strcmp(zCmd,"help")==0 ){
- oputz("Available test-controls:\n");
+ sqlite3_fputs("Available test-controls:\n", p->out);
for(i=0; i<ArraySize(aCtrl); i++){
if( aCtrl[i].unSafe && !ShellHasFlag(p,SHFLG_TestingMode) ) continue;
- oputf(" .testctrl %s %s\n",
+ sqlite3_fprintf(p->out, " .testctrl %s %s\n",
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
rc = 1;
@@ -29055,7 +31882,7 @@ static int do_meta_command(char *zLine, ShellState *p){
testctrl = aCtrl[i].ctrlCode;
iCtrl = i;
}else{
- eputf("Error: ambiguous test-control: \"%s\"\n"
+ sqlite3_fprintf(stderr,"Error: ambiguous test-control: \"%s\"\n"
"Use \".testctrl --help\" for help\n", zCmd);
rc = 1;
goto meta_command_exit;
@@ -29063,13 +31890,131 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( testctrl<0 ){
- eputf("Error: unknown test-control: %s\n"
+ sqlite3_fprintf(stderr,"Error: unknown test-control: %s\n"
"Use \".testctrl --help\" for help\n", zCmd);
}else{
switch(testctrl){
+ /* Special processing for .testctrl opt MASK ...
+ ** Each MASK argument can be one of:
+ **
+ ** +LABEL Enable the named optimization
+ **
+ ** -LABEL Disable the named optimization
+ **
+ ** INTEGER Mask of optimizations to disable
+ */
+ case SQLITE_TESTCTRL_OPTIMIZATIONS: {
+ static const struct {
+ unsigned int mask; /* Mask for this optimization */
+ unsigned int bDsply; /* Display this on output */
+ const char *zLabel; /* Name of optimization */
+ } aLabel[] = {
+ { 0x00000001, 1, "QueryFlattener" },
+ { 0x00000001, 0, "Flatten" },
+ { 0x00000002, 1, "WindowFunc" },
+ { 0x00000004, 1, "GroupByOrder" },
+ { 0x00000008, 1, "FactorOutConst" },
+ { 0x00000010, 1, "DistinctOpt" },
+ { 0x00000020, 1, "CoverIdxScan" },
+ { 0x00000040, 1, "OrderByIdxJoin" },
+ { 0x00000080, 1, "Transitive" },
+ { 0x00000100, 1, "OmitNoopJoin" },
+ { 0x00000200, 1, "CountOfView" },
+ { 0x00000400, 1, "CurosrHints" },
+ { 0x00000800, 1, "Stat4" },
+ { 0x00001000, 1, "PushDown" },
+ { 0x00002000, 1, "SimplifyJoin" },
+ { 0x00004000, 1, "SkipScan" },
+ { 0x00008000, 1, "PropagateConst" },
+ { 0x00010000, 1, "MinMaxOpt" },
+ { 0x00020000, 1, "SeekScan" },
+ { 0x00040000, 1, "OmitOrderBy" },
+ { 0x00080000, 1, "BloomFilter" },
+ { 0x00100000, 1, "BloomPulldown" },
+ { 0x00200000, 1, "BalancedMerge" },
+ { 0x00400000, 1, "ReleaseReg" },
+ { 0x00800000, 1, "FlttnUnionAll" },
+ { 0x01000000, 1, "IndexedEXpr" },
+ { 0x02000000, 1, "Coroutines" },
+ { 0x04000000, 1, "NullUnusedCols" },
+ { 0x08000000, 1, "OnePass" },
+ { 0x10000000, 1, "OrderBySubq" },
+ { 0x20000000, 1, "StarQuery" },
+ { 0xffffffff, 0, "All" },
+ };
+ unsigned int curOpt;
+ unsigned int newOpt;
+ unsigned int m;
+ int ii;
+ int nOff;
+ sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, p->db, &curOpt);
+ newOpt = curOpt;
+ for(ii=2; ii<nArg; ii++){
+ const char *z = azArg[ii];
+ int useLabel = 0;
+ const char *zLabel = 0;
+ if( (z[0]=='+'|| z[0]=='-') && !IsDigit(z[1]) ){
+ useLabel = z[0];
+ zLabel = &z[1];
+ }else if( !IsDigit(z[0]) && z[0]!=0 && !IsDigit(z[1]) ){
+ useLabel = '+';
+ zLabel = z;
+ }else{
+ newOpt = (unsigned int)strtol(z,0,0);
+ }
+ if( useLabel ){
+ int jj;
+ for(jj=0; jj<ArraySize(aLabel); jj++){
+ if( sqlite3_stricmp(zLabel, aLabel[jj].zLabel)==0 ) break;
+ }
+ if( jj>=ArraySize(aLabel) ){
+ sqlite3_fprintf(stderr,
+ "Error: no such optimization: \"%s\"\n", zLabel);
+ sqlite3_fputs("Should be one of:", stderr);
+ for(jj=0; jj<ArraySize(aLabel); jj++){
+ sqlite3_fprintf(stderr," %s", aLabel[jj].zLabel);
+ }
+ sqlite3_fputs("\n", stderr);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( useLabel=='+' ){
+ newOpt &= ~aLabel[jj].mask;
+ }else{
+ newOpt |= aLabel[jj].mask;
+ }
+ }
+ }
+ if( curOpt!=newOpt ){
+ sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,p->db,newOpt);
+ }
+ for(ii=nOff=0, m=1; ii<32; ii++, m <<= 1){
+ if( m & newOpt ) nOff++;
+ }
+ if( nOff<12 ){
+ sqlite3_fputs("+All", p->out);
+ for(ii=0; ii<ArraySize(aLabel); ii++){
+ if( !aLabel[ii].bDsply ) continue;
+ if( (newOpt & aLabel[ii].mask)!=0 ){
+ sqlite3_fprintf(p->out, " -%s", aLabel[ii].zLabel);
+ }
+ }
+ }else{
+ sqlite3_fputs("-All", p->out);
+ for(ii=0; ii<ArraySize(aLabel); ii++){
+ if( !aLabel[ii].bDsply ) continue;
+ if( (newOpt & aLabel[ii].mask)==0 ){
+ sqlite3_fprintf(p->out, " +%s", aLabel[ii].zLabel);
+ }
+ }
+ }
+ sqlite3_fputs("\n", p->out);
+ rc2 = isOk = 3;
+ break;
+ }
+
/* sqlite3_test_control(int, db, int) */
- case SQLITE_TESTCTRL_OPTIMIZATIONS:
case SQLITE_TESTCTRL_FK_NO_ACTION:
if( nArg==3 ){
unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0);
@@ -29104,7 +32049,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3 *db;
if( ii==0 && cli_strcmp(azArg[2],"random")==0 ){
sqlite3_randomness(sizeof(ii),&ii);
- sputf(stdout, "-- random seed: %d\n", ii);
+ sqlite3_fprintf(stdout, "-- random seed: %d\n", ii);
}
if( nArg==3 ){
db = 0;
@@ -29138,21 +32083,6 @@ static int do_meta_command(char *zLine, ShellState *p){
}
break;
- /* sqlite3_test_control(int, int) */
- case SQLITE_TESTCTRL_USELONGDOUBLE: {
- int opt = -1;
- if( nArg==3 ){
- if( cli_strcmp(azArg[2],"default")==0 ){
- opt = 2;
- }else{
- opt = booleanValue(azArg[2]);
- }
- }
- rc2 = sqlite3_test_control(testctrl, opt);
- isOk = 1;
- break;
- }
-
/* sqlite3_test_control(sqlite3*) */
case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
rc2 = sqlite3_test_control(testctrl, p->db);
@@ -29172,7 +32102,7 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_TESTCTRL_SEEK_COUNT: {
u64 x = 0;
rc2 = sqlite3_test_control(testctrl, p->db, &x);
- oputf("%llu\n", x);
+ sqlite3_fprintf(p->out, "%llu\n", x);
isOk = 3;
break;
}
@@ -29203,11 +32133,11 @@ static int do_meta_command(char *zLine, ShellState *p){
int val = 0;
rc2 = sqlite3_test_control(testctrl, -id, &val);
if( rc2!=SQLITE_OK ) break;
- if( id>1 ) oputz(" ");
- oputf("%d: %d", id, val);
+ if( id>1 ) sqlite3_fputs(" ", p->out);
+ sqlite3_fprintf(p->out, "%d: %d", id, val);
id++;
}
- if( id>1 ) oputz("\n");
+ if( id>1 ) sqlite3_fputs("\n", p->out);
isOk = 3;
}
break;
@@ -29249,14 +32179,22 @@ static int do_meta_command(char *zLine, ShellState *p){
faultsim_state.nHit = 0;
sqlite3_test_control(testctrl, faultsim_callback);
}else if( cli_strcmp(z,"status")==0 ){
- oputf("faultsim.iId: %d\n", faultsim_state.iId);
- oputf("faultsim.iErr: %d\n", faultsim_state.iErr);
- oputf("faultsim.iCnt: %d\n", faultsim_state.iCnt);
- oputf("faultsim.nHit: %d\n", faultsim_state.nHit);
- oputf("faultsim.iInterval: %d\n", faultsim_state.iInterval);
- oputf("faultsim.eVerbose: %d\n", faultsim_state.eVerbose);
- oputf("faultsim.nRepeat: %d\n", faultsim_state.nRepeat);
- oputf("faultsim.nSkip: %d\n", faultsim_state.nSkip);
+ sqlite3_fprintf(p->out, "faultsim.iId: %d\n",
+ faultsim_state.iId);
+ sqlite3_fprintf(p->out, "faultsim.iErr: %d\n",
+ faultsim_state.iErr);
+ sqlite3_fprintf(p->out, "faultsim.iCnt: %d\n",
+ faultsim_state.iCnt);
+ sqlite3_fprintf(p->out, "faultsim.nHit: %d\n",
+ faultsim_state.nHit);
+ sqlite3_fprintf(p->out, "faultsim.iInterval: %d\n",
+ faultsim_state.iInterval);
+ sqlite3_fprintf(p->out, "faultsim.eVerbose: %d\n",
+ faultsim_state.eVerbose);
+ sqlite3_fprintf(p->out, "faultsim.nRepeat: %d\n",
+ faultsim_state.nRepeat);
+ sqlite3_fprintf(p->out, "faultsim.nSkip: %d\n",
+ faultsim_state.nSkip);
}else if( cli_strcmp(z,"-v")==0 ){
if( faultsim_state.eVerbose<2 ) faultsim_state.eVerbose++;
}else if( cli_strcmp(z,"-q")==0 ){
@@ -29274,7 +32212,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( cli_strcmp(z,"-?")==0 || sqlite3_strglob("*help*",z)==0){
bShowHelp = 1;
}else{
- eputf("Unrecognized fault_install argument: \"%s\"\n",
+ sqlite3_fprintf(stderr,
+ "Unrecognized fault_install argument: \"%s\"\n",
azArg[kk]);
rc = 1;
bShowHelp = 1;
@@ -29282,7 +32221,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( bShowHelp ){
- oputz(
+ sqlite3_fputs(
"Usage: .testctrl fault_install ARGS\n"
"Possible arguments:\n"
" off Disable faultsim\n"
@@ -29296,6 +32235,7 @@ static int do_meta_command(char *zLine, ShellState *p){
" --interval N Trigger only after every N-th call\n"
" --repeat N Turn off after N hits. 0 means never\n"
" --skip N Skip the first N encounters\n"
+ ,p->out
);
}
break;
@@ -29303,12 +32243,13 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}
if( isOk==0 && iCtrl>=0 ){
- oputf("Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
+ sqlite3_fprintf(p->out,
+ "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
rc = 1;
}else if( isOk==1 ){
- oputf("%d\n", rc2);
+ sqlite3_fprintf(p->out, "%d\n", rc2);
}else if( isOk==2 ){
- oputf("0x%08x\n", rc2);
+ sqlite3_fprintf(p->out, "0x%08x\n", rc2);
}
}else
#endif /* !defined(SQLITE_UNTESTABLE) */
@@ -29363,13 +32304,13 @@ static int do_meta_command(char *zLine, ShellState *p){
mType |= SQLITE_TRACE_CLOSE;
}
else {
- eputf("Unknown option \"%s\" on \".trace\"\n", z);
+ sqlite3_fprintf(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(z, 0);
+ p->traceOut = output_file_open(z);
}
}
if( p->traceOut==0 ){
@@ -29406,86 +32347,23 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
-#if SQLITE_USER_AUTHENTICATION
- if( c=='u' && cli_strncmp(azArg[0], "user", n)==0 ){
- if( nArg<2 ){
- eputz("Usage: .user SUBCOMMAND ...\n");
- rc = 1;
- goto meta_command_exit;
- }
- open_db(p, 0);
- if( cli_strcmp(azArg[1],"login")==0 ){
- if( nArg!=4 ){
- eputz("Usage: .user login USER PASSWORD\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
- strlen30(azArg[3]));
- if( rc ){
- eputf("Authentication failed for user %s\n", azArg[2]);
- rc = 1;
- }
- }else if( cli_strcmp(azArg[1],"add")==0 ){
- if( nArg!=5 ){
- eputz("Usage: .user add USER PASSWORD ISADMIN\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
- booleanValue(azArg[4]));
- if( rc ){
- eputf("User-Add failed: %d\n", rc);
- rc = 1;
- }
- }else if( cli_strcmp(azArg[1],"edit")==0 ){
- if( nArg!=5 ){
- eputz("Usage: .user edit USER PASSWORD ISADMIN\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
- booleanValue(azArg[4]));
- if( rc ){
- eputf("User-Edit failed: %d\n", rc);
- rc = 1;
- }
- }else if( cli_strcmp(azArg[1],"delete")==0 ){
- if( nArg!=3 ){
- eputz("Usage: .user delete USER\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_delete(p->db, azArg[2]);
- if( rc ){
- eputf("User-Delete failed: %d\n", rc);
- rc = 1;
- }
- }else{
- eputz("Usage: .user login|add|edit|delete ...\n");
- rc = 1;
- goto meta_command_exit;
- }
- }else
-#endif /* SQLITE_USER_AUTHENTICATION */
-
if( c=='v' && cli_strncmp(azArg[0], "version", n)==0 ){
char *zPtrSz = sizeof(void*)==8 ? "64-bit" : "32-bit";
- oputf("SQLite %s %s\n" /*extra-version-info*/,
+ sqlite3_fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
sqlite3_libversion(), sqlite3_sourceid());
#if SQLITE_HAVE_ZLIB
- oputf("zlib version %s\n", zlibVersion());
+ sqlite3_fprintf(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__)
- oputf("clang-" CTIMEOPT_VAL(__clang_major__) "."
+ sqlite3_fprintf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
CTIMEOPT_VAL(__clang_minor__) "."
CTIMEOPT_VAL(__clang_patchlevel__) " (%s)\n", zPtrSz);
#elif defined(_MSC_VER)
- oputf("msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz);
+ sqlite3_fprintf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz);
#elif defined(__GNUC__) && defined(__VERSION__)
- oputf("gcc-" __VERSION__ " (%s)\n", zPtrSz);
+ sqlite3_fprintf(p->out, "gcc-" __VERSION__ " (%s)\n", zPtrSz);
#endif
}else
@@ -29495,10 +32373,10 @@ static int do_meta_command(char *zLine, ShellState *p){
if( p->db ){
sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
if( pVfs ){
- oputf("vfs.zName = \"%s\"\n", pVfs->zName);
- oputf("vfs.iVersion = %d\n", pVfs->iVersion);
- oputf("vfs.szOsFile = %d\n", pVfs->szOsFile);
- oputf("vfs.mxPathname = %d\n", pVfs->mxPathname);
+ sqlite3_fprintf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
+ sqlite3_fprintf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
+ sqlite3_fprintf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
+ sqlite3_fprintf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
}
}
}else
@@ -29510,13 +32388,13 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
}
for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
- oputf("vfs.zName = \"%s\"%s\n", pVfs->zName,
+ sqlite3_fprintf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
pVfs==pCurrent ? " <--- CURRENT" : "");
- oputf("vfs.iVersion = %d\n", pVfs->iVersion);
- oputf("vfs.szOsFile = %d\n", pVfs->szOsFile);
- oputf("vfs.mxPathname = %d\n", pVfs->mxPathname);
+ sqlite3_fprintf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
+ sqlite3_fprintf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
+ sqlite3_fprintf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
if( pVfs->pNext ){
- oputz("-----------------------------------\n");
+ sqlite3_fputs("-----------------------------------\n", p->out);
}
}
}else
@@ -29527,7 +32405,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( p->db ){
sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
if( zVfsName ){
- oputf("%s\n", zVfsName);
+ sqlite3_fprintf(p->out, "%s\n", zVfsName);
sqlite3_free(zVfsName);
}
}
@@ -29551,7 +32429,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
{
- eputf("Error: unknown command or invalid arguments: "
+ sqlite3_fprintf(stderr,"Error: unknown command or invalid arguments: "
" \"%s\". Enter \".help\" for help\n", azArg[0]);
rc = 1;
}
@@ -29592,7 +32470,6 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
char cWait = (char)qss; /* intentional narrowing loss */
if( cWait==0 ){
PlainScan:
- assert( cWait==0 );
while( (cin = *zLine++)!=0 ){
if( IsSpace(cin) )
continue;
@@ -29618,7 +32495,7 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
break;
case '[':
cin = ']';
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case '`': case '\'': case '"':
cWait = cin;
qss = QSS_HasDark | cWait;
@@ -29644,7 +32521,6 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
if( *zLine != '/' )
continue;
++zLine;
- cWait = 0;
CONTINUE_PROMPT_AWAITC(pst, 0);
qss = QSS_SETV(qss, 0);
goto PlainScan;
@@ -29654,9 +32530,8 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss,
++zLine;
continue;
}
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case ']':
- cWait = 0;
CONTINUE_PROMPT_AWAITC(pst, 0);
qss = QSS_SETV(qss, 0);
goto PlainScan;
@@ -29689,7 +32564,7 @@ static int line_is_command_terminator(char *zLine){
** out of the build if compiling with SQLITE_OMIT_COMPLETE.
*/
#ifdef SQLITE_OMIT_COMPLETE
-# error the CLI application is imcompatable with SQLITE_OMIT_COMPLETE.
+# error the CLI application is incompatible with SQLITE_OMIT_COMPLETE.
#endif
/*
@@ -29732,7 +32607,10 @@ static int doAutoDetectRestore(ShellState *p, const char *zSql){
case 0: {
const char *zExpect = "PRAGMA foreign_keys=OFF;";
assert( strlen(zExpect)==24 );
- if( p->bSafeMode==0 && memcmp(zSql, zExpect, 25)==0 ){
+ if( p->bSafeMode==0
+ && strlen(zSql)>=24
+ && memcmp(zSql, zExpect, 25)==0
+ ){
p->eRestoreState = 1;
}else{
p->eRestoreState = 7;
@@ -29800,7 +32678,7 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
BEGIN_TIMER;
rc = shell_exec(p, zSql, &zErrMsg);
- END_TIMER;
+ END_TIMER(p->out);
if( rc || zErrMsg ){
char zPrefix[100];
const char *zErrorTail;
@@ -29824,7 +32702,7 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
}else{
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType);
}
- eputf("%s %s\n", zPrefix, zErrorTail);
+ sqlite3_fprintf(stderr,"%s %s\n", zPrefix, zErrorTail);
sqlite3_free(zErrMsg);
zErrMsg = 0;
return 1;
@@ -29833,7 +32711,7 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
"changes: %lld total_changes: %lld",
sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
- oputf("%s\n", zLineBuf);
+ sqlite3_fprintf(p->out, "%s\n", zLineBuf);
}
if( doAutoDetectRestore(p, zSql) ) return 1;
@@ -29841,7 +32719,10 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
}
static void echo_group_input(ShellState *p, const char *zDo){
- if( ShellHasFlag(p, SHFLG_Echo) ) oputf("%s\n", zDo);
+ if( ShellHasFlag(p, SHFLG_Echo) ){
+ sqlite3_fprintf(p->out, "%s\n", zDo);
+ fflush(p->out);
+ }
}
#ifdef SQLITE_SHELL_FIDDLE
@@ -29862,7 +32743,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
if(!z || !*z){
return 0;
}
- while(*z && isspace(*z)) ++z;
+ while(*z && IsSpace(*z)) ++z;
zBegin = z;
for(; *z && '\n'!=*z; ++nZ, ++z){}
if(nZ>0 && '\r'==zBegin[nZ-1]){
@@ -29899,7 +32780,7 @@ static int process_input(ShellState *p){
if( p->inputNesting==MAX_INPUT_NESTING ){
/* This will be more informative in a later version. */
- eputf("Input nesting limit (%d) reached at line %d."
+ sqlite3_fprintf(stderr,"Input nesting limit (%d) reached at line %d."
" Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
return 1;
}
@@ -29911,7 +32792,7 @@ static int process_input(ShellState *p){
zLine = one_input_line(p->in, zLine, nSql>0);
if( zLine==0 ){
/* End of input */
- if( p->in==0 && stdin_is_interactive ) oputz("\n");
+ if( p->in==0 && stdin_is_interactive ) sqlite3_fputs("\n", p->out);
break;
}
if( seenInterrupt ){
@@ -30068,27 +32949,29 @@ static char *find_home_dir(int clearFlag){
/*
** On non-Windows platforms, look for $XDG_CONFIG_HOME.
** If ${XDG_CONFIG_HOME}/sqlite3/sqliterc is found, return
-** the path to it, else return 0. The result is cached for
-** subsequent calls.
+** the path to it. If there is no $(XDG_CONFIG_HOME) then
+** look for $(HOME)/.config/sqlite3/sqliterc and if found
+** return that. If none of these are found, return 0.
+**
+** The string returned is obtained from sqlite3_malloc() and
+** should be freed by the caller.
*/
-static const char *find_xdg_config(void){
+static char *find_xdg_config(void){
#if defined(_WIN32) || defined(WIN32) || defined(_WIN32_WCE) \
|| defined(__RTP__) || defined(_WRS_KERNEL)
return 0;
#else
- static int alreadyTried = 0;
- static char *zConfig = 0;
+ char *zConfig = 0;
const char *zXdgHome;
- if( alreadyTried!=0 ){
- return zConfig;
- }
- alreadyTried = 1;
zXdgHome = getenv("XDG_CONFIG_HOME");
if( zXdgHome==0 ){
- return 0;
+ const char *zHome = getenv("HOME");
+ if( zHome==0 ) return 0;
+ zConfig = sqlite3_mprintf("%s/.config/sqlite3/sqliterc", zHome);
+ }else{
+ zConfig = sqlite3_mprintf("%s/sqlite3/sqliterc", zXdgHome);
}
- zConfig = sqlite3_mprintf("%s/sqlite3/sqliterc", zXdgHome);
shell_check_oom(zConfig);
if( access(zConfig,0)!=0 ){
sqlite3_free(zConfig);
@@ -30116,7 +32999,7 @@ static void process_sqliterc(
int savedLineno = p->lineno;
if( sqliterc == NULL ){
- sqliterc = find_xdg_config();
+ sqliterc = zBuf = find_xdg_config();
}
if( sqliterc == NULL ){
home_dir = find_home_dir(0);
@@ -30129,15 +33012,15 @@ static void process_sqliterc(
shell_check_oom(zBuf);
sqliterc = zBuf;
}
- p->in = fopen(sqliterc,"rb");
+ p->in = sqlite3_fopen(sqliterc,"rb");
if( p->in ){
if( stdin_is_interactive ){
- eputf("-- Loading resources from %s\n", sqliterc);
+ sqlite3_fprintf(stderr,"-- Loading resources from %s\n", sqliterc);
}
if( process_input(p) && bail_on_error ) exit(1);
fclose(p->in);
}else if( sqliterc_override!=0 ){
- eputf("cannot open: \"%s\"\n", sqliterc);
+ sqlite3_fprintf(stderr,"cannot open: \"%s\"\n", sqliterc);
if( bail_on_error ) exit(1);
}
p->in = inSaved;
@@ -30165,6 +33048,7 @@ static const char zOptions[] =
" -deserialize open the database using sqlite3_deserialize()\n"
#endif
" -echo print inputs before execution\n"
+ " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n"
" -init FILENAME read/process named file\n"
" -[no]header turn headers on or off\n"
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
@@ -30206,19 +33090,17 @@ static const char zOptions[] =
" -unsafe-testing allow unsafe commands and modes for testing\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){
- eputf("Usage: %s [OPTIONS] [FILENAME [SQL]]\n"
+ sqlite3_fprintf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL...]]\n"
"FILENAME is the name of an SQLite database. A new database is created\n"
"if the file does not previously exist. Defaults to :memory:.\n", Argv0);
if( showDetail ){
- eputf("OPTIONS include:\n%s", zOptions);
+ sqlite3_fprintf(stderr,"OPTIONS include:\n%s", zOptions);
}else{
eputz("Use the -help option for additional information\n");
}
@@ -30243,6 +33125,9 @@ static void main_init(ShellState *data) {
memset(data, 0, sizeof(*data));
data->normalMode = data->cMode = data->mode = MODE_List;
data->autoExplain = 1;
+#ifdef _WIN32
+ data->crlfMode = 1;
+#endif
data->pAuxDb = &data->aAuxDb[0];
memcpy(data->colSeparator,SEP_Column, 2);
memcpy(data->rowSeparator,SEP_Row, 2);
@@ -30278,7 +33163,7 @@ static void printBold(const char *zText){
}
#else
static void printBold(const char *zText){
- sputf(stdout, "\033[1m%s\033[0m", zText);
+ sqlite3_fprintf(stdout, "\033[1m%s\033[0m", zText);
}
#endif
@@ -30288,7 +33173,8 @@ static void printBold(const char *zText){
*/
static char *cmdline_option_value(int argc, char **argv, int i){
if( i==argc ){
- eputf("%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
+ sqlite3_fprintf(stderr,
+ "%s: Error: missing argument to %s\n", argv[0], argv[argc-1]);
exit(1);
}
return argv[i];
@@ -30298,6 +33184,15 @@ static void sayAbnormalExit(void){
if( seenInterrupt ) eputz("Program interrupted.\n");
}
+/* Routine to output from vfstrace
+*/
+static int vfstraceOut(const char *z, void *pArg){
+ ShellState *p = (ShellState*)pArg;
+ sqlite3_fputs(z, p->out);
+ fflush(p->out);
+ return 1;
+}
+
#ifndef SQLITE_SHELL_IS_UTF8
# if (defined(_WIN32) || defined(WIN32)) \
&& (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
@@ -30325,7 +33220,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
# define data shellState
#else
ShellState data;
- StreamsAreConsole consStreams = SAC_NoConsole;
#endif
const char *zInitFile = 0;
int i;
@@ -30334,6 +33228,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
int readStdin = 1;
int nCmd = 0;
int nOptsEnd = argc;
+ int bEnableVfstrace = 0;
char **azCmd = 0;
const char *zVfs = 0; /* Value of -vfs command-line option */
#if !SQLITE_SHELL_IS_UTF8
@@ -30347,10 +33242,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
stdout_is_console = 1;
data.wasm.zDefaultDbName = "/fiddle.sqlite3";
#else
- consStreams = consoleClassifySetup(stdin, stdout, stderr);
- stdin_is_interactive = (consStreams & SAC_InConsole)!=0;
- stdout_is_console = (consStreams & SAC_OutConsole)!=0;
- atexit(consoleRestore);
+ stdin_is_interactive = isatty(0);
+ stdout_is_console = isatty(1);
#endif
atexit(sayAbnormalExit);
#ifdef SQLITE_DEBUG
@@ -30359,9 +33252,15 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#if !defined(_WIN32_WCE)
if( getenv("SQLITE_DEBUG_BREAK") ){
if( isatty(0) && isatty(2) ){
- eputf("attach debugger to process %d and press any key to continue.\n",
+ char zLine[100];
+ sqlite3_fprintf(stderr,
+ "attach debugger to process %d and press ENTER to continue...",
GETPID());
- fgetc(stdin);
+ if( sqlite3_fgets(zLine, sizeof(zLine), stdin)!=0
+ && cli_strcmp(zLine,"stop")==0
+ ){
+ exit(1);
+ }
}else{
#if defined(_WIN32) || defined(WIN32)
#if SQLITE_OS_WINRT
@@ -30386,7 +33285,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#if USE_SYSTEM_SQLITE+0!=1
if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
- eputf("SQLite header and source version mismatch\n%s\n%s\n",
+ sqlite3_fprintf(stderr,
+ "SQLite header and source version mismatch\n%s\n%s\n",
sqlite3_sourceid(), SQLITE_SOURCE_ID);
exit(1);
}
@@ -30528,17 +33428,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break;
default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break;
}
-#ifdef SQLITE_ENABLE_VFSTRACE
}else if( cli_strcmp(z,"-vfstrace")==0 ){
- extern int vfstrace_register(
- const char *zTraceName,
- const char *zOldVfsName,
- int (*xOut)(const char*,void*),
- void *pOutArg,
- int makeDefault
- );
- vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
-#endif
+ bEnableVfstrace = 1;
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( cli_strcmp(z,"-multiplex")==0 ){
extern int sqlite3_multiplex_initialize(const char*,int);
@@ -30591,10 +33482,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
ShellSetFlag(&data,SHFLG_TestingMode);
}else if( cli_strcmp(z,"-safe")==0 ){
/* no-op - catch this on the second pass */
+ }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
+ /* skip over the argument */
+ i++;
}
}
#ifndef SQLITE_SHELL_FIDDLE
- verify_uninitialized();
+ if( !bEnableVfstrace ) verify_uninitialized();
#endif
@@ -30618,7 +33512,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
if( pVfs ){
sqlite3_vfs_register(pVfs, 1);
}else{
- eputf("no such VFS: \"%s\"\n", zVfs);
+ sqlite3_fprintf(stderr,"no such VFS: \"%s\"\n", zVfs);
exit(1);
}
}
@@ -30628,11 +33522,15 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
data.pAuxDb->zDbFilename = ":memory:";
warnInmemoryDb = argc==1;
#else
- eputf("%s: Error: no database filename specified\n", Argv0);
+ sqlite3_fprintf(stderr,
+ "%s: Error: no database filename specified\n", Argv0);
return 1;
#endif
}
data.out = stdout;
+ if( bEnableVfstrace ){
+ vfstrace_register("trace",0,vfstraceOut, &data, 1);
+ }
#ifndef SQLITE_SHELL_FIDDLE
sqlite3_appendvfs_init(0,0,0);
#endif
@@ -30686,6 +33584,25 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( cli_strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);
+ }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
+ /* See similar code at tag-20250224-1 */
+ const char *zEsc = argv[++i];
+ int k;
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
+ if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
+ data.eEscMode = k;
+ break;
+ }
+ }
+ if( k>=ArraySize(shell_EscModeNames) ){
+ sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
+ " - choices:", zEsc);
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
+ sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
+ }
+ sqlite3_fprintf(stderr, "\n");
+ exit(1);
+ }
#ifdef SQLITE_HAVE_ZLIB
}else if( cli_strcmp(z,"-zip")==0 ){
data.openMode = SHELL_OPEN_ZIPFILE;
@@ -30745,7 +33662,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( cli_strcmp(z,"-bail")==0 ){
/* No-op. The bail_on_error flag should already be set. */
}else if( cli_strcmp(z,"-version")==0 ){
- sputf(stdout, "%s %s (%d-bit)\n",
+ sqlite3_fprintf(stdout, "%s %s (%d-bit)\n",
sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*));
return 0;
}else if( cli_strcmp(z,"-interactive")==0 ){
@@ -30783,10 +33700,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( cli_strcmp(z,"-vfs")==0 ){
i++;
-#ifdef SQLITE_ENABLE_VFSTRACE
}else if( cli_strcmp(z,"-vfstrace")==0 ){
i++;
-#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( cli_strcmp(z,"-multiplex")==0 ){
i++;
@@ -30807,17 +33722,17 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
open_db(&data, 0);
rc = shell_exec(&data, z, &zErrMsg);
if( zErrMsg!=0 ){
- eputf("Error: %s\n", zErrMsg);
+ shellEmitError(zErrMsg);
if( bail_on_error ) return rc!=0 ? rc : 1;
}else if( rc!=0 ){
- eputf("Error: unable to process SQL \"%s\"\n", z);
+ sqlite3_fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
if( bail_on_error ) return rc;
}
}
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
}else if( cli_strncmp(z, "-A", 2)==0 ){
if( nCmd>0 ){
- eputf("Error: cannot mix regular SQL or dot-commands"
+ sqlite3_fprintf(stderr,"Error: cannot mix regular SQL or dot-commands"
" with \"%s\"\n", z);
return 1;
}
@@ -30836,7 +33751,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( cli_strcmp(z,"-unsafe-testing")==0 ){
/* Acted upon in first pass. */
}else{
- eputf("%s: Error: unknown option: %s\n", Argv0, z);
+ sqlite3_fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
eputz("Use -help for a list of options.\n");
return 1;
}
@@ -30849,25 +33764,26 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
** the database filename.
*/
for(i=0; i<nCmd; i++){
+ echo_group_input(&data, azCmd[i]);
if( azCmd[i][0]=='.' ){
rc = do_meta_command(azCmd[i], &data);
if( rc ){
- free(azCmd);
- return rc==2 ? 0 : rc;
+ if( rc==2 ) rc = 0;
+ goto shell_main_exit;
}
}else{
open_db(&data, 0);
- echo_group_input(&data, azCmd[i]);
rc = shell_exec(&data, azCmd[i], &zErrMsg);
if( zErrMsg || rc ){
if( zErrMsg!=0 ){
- eputf("Error: %s\n", zErrMsg);
+ shellEmitError(zErrMsg);
}else{
- eputf("Error: unable to process SQL: %s\n", azCmd[i]);
+ sqlite3_fprintf(stderr,
+ "Error: unable to process SQL: %s\n", azCmd[i]);
}
sqlite3_free(zErrMsg);
- free(azCmd);
- return rc!=0 ? rc : 1;
+ if( rc==0 ) rc = 1;
+ goto shell_main_exit;
}
}
}
@@ -30878,14 +33794,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
char *zHome;
char *zHistory;
int nHistory;
-#if CIO_WIN_WC_XLATE
-# define SHELL_CIO_CHAR_SET (stdout_is_console? " (UTF-16 console I/O)" : "")
-#else
-# define SHELL_CIO_CHAR_SET ""
-#endif
- sputf(stdout, "SQLite version %s %.19s%s\n" /*extra-version-info*/
+ sqlite3_fprintf(stdout,
+ "SQLite version %s %.19s\n" /*extra-version-info*/
"Enter \".help\" for usage hints.\n",
- sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET);
+ sqlite3_libversion(), sqlite3_sourceid());
if( warnInmemoryDb ){
sputz(stdout, "Connected to a ");
printBold("transient in-memory database");
@@ -30902,10 +33814,12 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
}
if( zHistory ){ shell_read_history(zHistory); }
-#if HAVE_READLINE || HAVE_EDITLINE
+#if (HAVE_READLINE || HAVE_EDITLINE) && !defined(SQLITE_OMIT_READLINE_COMPLETION)
rl_attempted_completion_function = readline_completion;
-#elif HAVE_LINENOISE
+#elif HAVE_LINENOISE==1
linenoiseSetCompletionCallback(linenoise_completion);
+#elif HAVE_LINENOISE==2
+ linenoiseSetCompletionCallback(linenoise_completion, NULL);
#endif
data.in = 0;
rc = process_input(&data);
@@ -30927,6 +33841,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
expertFinish(&data, 1, 0);
}
#endif
+ shell_main_exit:
free(azCmd);
set_table_name(&data, 0);
if( data.db ){
@@ -30953,13 +33868,18 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
/* Clear the global data structure so that valgrind will detect memory
** leaks */
memset(&data, 0, sizeof(data));
+ if( bEnableVfstrace ){
+ vfstrace_unregister("trace");
+ }
#ifdef SQLITE_DEBUG
if( sqlite3_memory_used()>mem_main_enter ){
- eputf("Memory leaked: %u bytes\n",
+ sqlite3_fprintf(stderr,"Memory leaked: %u bytes\n",
(unsigned int)(sqlite3_memory_used()-mem_main_enter));
}
#endif
-#endif /* !SQLITE_SHELL_FIDDLE */
+#else /* SQLITE_SHELL_FIDDLE... */
+ shell_main_exit:
+#endif
return rc;
}
@@ -30993,7 +33913,7 @@ sqlite3_vfs * fiddle_db_vfs(const char *zDbName){
/* Only for emcc experimentation purposes. */
sqlite3 * fiddle_db_arg(sqlite3 *arg){
- oputf("fiddle_db_arg(%p)\n", (const void*)arg);
+ sqlite3_fprintf(stdout, "fiddle_db_arg(%p)\n", (const void*)arg);
return arg;
}
@@ -31030,7 +33950,7 @@ void fiddle_reset_db(void){
** Resolve problem reported in
** https://sqlite.org/forum/forumpost/0b41a25d65
*/
- oputz("Rolling back in-progress transaction.\n");
+ sqlite3_fputs("Rolling back in-progress transaction.\n", stdout);
sqlite3_exec(globalDb,"ROLLBACK", 0, 0, 0);
}
rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
diff --git a/contrib/sqlite3/sqlite3.c b/contrib/sqlite3/sqlite3.c
index 946815f13ec8..0b071b2b6cc2 100644
--- a/contrib/sqlite3/sqlite3.c
+++ b/contrib/sqlite3/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.46.1. By combining all the individual C code files into this
+** version 3.50.2. 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
@@ -18,8 +18,11 @@
** separate file. This file contains only code for the core SQLite library.
**
** The content in this amalgamation comes from Fossil check-in
-** c9c2ab54ba1f5f46360f1b4f35d849cd3f08.
+** 2af157d77fb1304a74176eaee7fbc7c7e932 with changes in files:
+**
+**
*/
+#ifndef SQLITE_AMALGAMATION
#define SQLITE_CORE 1
#define SQLITE_AMALGAMATION 1
#ifndef SQLITE_PRIVATE
@@ -256,10 +259,13 @@
/*
** 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
+#if defined(__has_attribute)
+# if __has_attribute(fallthrough)
+# define deliberate_fall_through __attribute__((fallthrough));
+# endif
+#endif
+#if !defined(deliberate_fall_through)
+# define deliberate_fall_through
#endif
/*
@@ -446,7 +452,7 @@ extern "C" {
**
** 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
+** <a href="http://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
@@ -459,9 +465,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.46.1"
-#define SQLITE_VERSION_NUMBER 3046001
-#define SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33"
+#define SQLITE_VERSION "3.50.2"
+#define SQLITE_VERSION_NUMBER 3050002
+#define SQLITE_SOURCE_ID "2025-06-28 14:00:48 2af157d77fb1304a74176eaee7fbc7c7e932d946bf25325e9c26c91db19e3079"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -965,6 +971,13 @@ SQLITE_API int sqlite3_exec(
** 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].
+**
+** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
+** from the database file in amounts that are not a multiple of the
+** page size and that do not begin at a page boundary. Without this
+** property, SQLite is careful to only do full-page reads and write
+** on aligned pages, with the one exception that it will do a sub-page
+** read of the first page to access the database header.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -981,6 +994,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
+#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
/*
** CAPI3REF: File Locking Levels
@@ -1085,8 +1099,8 @@ struct sqlite3_file {
** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
-** PENDING, or EXCLUSIVE lock on the file. It returns true
-** if such a lock exists and false otherwise.
+** PENDING, or EXCLUSIVE lock on the file. It returns, via its output
+** pointer parameter, true if such a lock exists and false otherwise.
**
** The xFileControl() method is a generic interface that allows custom
** VFS implementations to directly control an open file using the
@@ -1127,6 +1141,7 @@ struct sqlite3_file {
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE]
** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
+** <li> [SQLITE_IOCAP_SUBPAGE_READ]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -1404,6 +1419,11 @@ struct sqlite3_io_methods {
** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
+** <li>[[SQLITE_FCNTL_NULL_IO]]
+** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor
+** or file handle for the [sqlite3_file] object such that it will no longer
+** read or write to the database file.
+**
** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
** be advantageous to block on the next WAL lock if the lock is not immediately
@@ -1462,6 +1482,12 @@ struct sqlite3_io_methods {
** 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_BLOCK_ON_CONNECT]]
+** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the
+** VFS to block when taking a SHARED lock to connect to a wal mode database.
+** This is used to implement the functionality associated with
+** SQLITE_SETLK_BLOCK_ON_CONNECT.
+**
** <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.
@@ -1557,6 +1583,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_EXTERNAL_READER 40
#define SQLITE_FCNTL_CKSM_FILE 41
#define SQLITE_FCNTL_RESET_CACHE 42
+#define SQLITE_FCNTL_NULL_IO 43
+#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -2287,13 +2315,16 @@ struct sqlite3_mem_methods {
**
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
-** the default size of lookaside memory on each [database connection].
+** the default size of [lookaside memory] on each [database connection].
** The first argument is the
-** size of each lookaside buffer slot and the second is the number of
-** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
-** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
-** option to [sqlite3_db_config()] can be used to change the lookaside
-** configuration on individual connections.)^ </dd>
+** size of each lookaside buffer slot ("sz") and the second is the number of
+** slots allocated to each database connection ("cnt").)^
+** ^(SQLITE_CONFIG_LOOKASIDE sets the <i>default</i> lookaside size.
+** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can
+** be used to change the lookaside configuration on individual connections.)^
+** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the
+** default lookaside configuration at compile-time.
+** </dd>
**
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
@@ -2509,7 +2540,15 @@ struct sqlite3_mem_methods {
** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
-** can be passed as the second argument to the [sqlite3_db_config()] interface.
+** can be passed as the second parameter to the [sqlite3_db_config()] interface.
+**
+** The [sqlite3_db_config()] interface is a var-args functions. It takes a
+** variable number of parameters, though always at least two. The number of
+** parameters passed into sqlite3_db_config() depends on which of these
+** constants is given as the second parameter. This documentation page
+** refers to parameters beyond the second as "arguments". Thus, when this
+** page says "the N-th argument" it means "the N-th parameter past the
+** configuration option" or "the (N+2)-th parameter to sqlite3_db_config()".
**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
@@ -2521,31 +2560,57 @@ struct sqlite3_mem_methods {
** <dl>
** [[SQLITE_DBCONFIG_LOOKASIDE]]
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
-** <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
+** <dd> The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the
+** configuration of the [lookaside memory allocator] within a database
+** connection.
+** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are <i>not</i>
+** in the [DBCONFIG arguments|usual format].
+** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two,
+** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE
+** should have a total of five parameters.
+** <ol>
+** <li><p>The first argument ("buf") is a
** pointer to a memory buffer to use for lookaside memory.
-** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
-** may be NULL in which case SQLite will allocate the
-** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the
-** size of each lookaside buffer slot. ^The third argument is the number of
-** slots. The size of the buffer in the first argument must be greater than
-** or equal to the product of the second and third arguments. The buffer
-** must be aligned to an 8-byte boundary. ^If the second argument to
-** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
-** rounded down to the next smaller multiple of 8. ^(The lookaside memory
+** The first argument may be NULL in which case SQLite will allocate the
+** lookaside buffer itself using [sqlite3_malloc()].
+** <li><P>The second argument ("sz") is the
+** size of each lookaside buffer slot. Lookaside is disabled if "sz"
+** is less than 8. The "sz" argument should be a multiple of 8 less than
+** 65536. If "sz" does not meet this constraint, it is reduced in size until
+** it does.
+** <li><p>The third argument ("cnt") is the number of slots. Lookaside is disabled
+** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so
+** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt"
+** parameter is usually chosen so that the product of "sz" and "cnt" is less
+** than 1,000,000.
+** </ol>
+** <p>If the "buf" argument is not NULL, then it must
+** point to a memory buffer with a size that is greater than
+** or equal to the product of "sz" and "cnt".
+** The buffer must be aligned to an 8-byte boundary.
+** The lookaside memory
** configuration for a database connection can only be changed when that
** connection is not currently using lookaside memory, or in other words
-** when the "current value" returned by
-** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
+** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero.
** Any attempt to change the lookaside memory configuration when lookaside
** memory is in use leaves the configuration unchanged and returns
-** [SQLITE_BUSY].)^</dd>
+** [SQLITE_BUSY].
+** If the "buf" argument is NULL and an attempt
+** to allocate memory based on "sz" and "cnt" fails, then
+** lookaside is silently disabled.
+** <p>
+** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the
+** default lookaside configuration at initialization. The
+** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside
+** configuration at compile-time. Typical values for lookaside are 1200 for
+** "sz" and 40 to 100 for "cnt".
+** </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.
+** [foreign key constraints]. This is the same setting that is
+** enabled or disabled by the [PRAGMA foreign_keys] statement.
** The first argument is an integer which is 0 to disable FK enforcement,
** positive to enable FK enforcement or negative to leave FK enforcement
** unchanged. The second parameter is a pointer to an integer into which
@@ -2567,13 +2632,13 @@ struct sqlite3_mem_methods {
** <p>Originally this option disabled all triggers. ^(However, since
** SQLite version 3.35.0, TEMP triggers are still allowed even if
** this option is off. So, in other words, this option now only disables
-** triggers in the main database schema or in the schemas of ATTACH-ed
+** triggers in the main database schema or in the schemas of [ATTACH]-ed
** databases.)^ </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.
+** There must 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
@@ -2592,7 +2657,7 @@ struct sqlite3_mem_methods {
** <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.
+** There must be two additional arguments.
** The first argument is an integer which is 0 to disable fts3_tokenizer() or
** positive to enable fts3_tokenizer() or negative to leave the setting
** unchanged.
@@ -2607,7 +2672,7 @@ struct sqlite3_mem_methods {
** interface independently of the [load_extension()] SQL function.
** The [sqlite3_enable_load_extension()] API enables or disables both the
** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
-** There should be two additional arguments.
+** There must be two additional arguments.
** When the first argument to this interface is 1, then only the C-API is
** enabled and the SQL function remains disabled. If the first argument to
** this interface is 0, then both the C-API and the SQL function are disabled.
@@ -2621,23 +2686,30 @@ struct sqlite3_mem_methods {
**
** [[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
-** does not make a copy of the new main schema name string, so the application
-** must ensure that the argument passed into this DBCONFIG option is unchanged
-** until after the database connection closes.
+** schema. This option does not follow the
+** [DBCONFIG arguments|usual SQLITE_DBCONFIG argument format].
+** This option takes exactly one additional argument so that the
+** [sqlite3_db_config()] call has a total of three parameters. The
+** extra argument must be a pointer to a constant UTF8 string which
+** will become the new schema name in place of "main". ^SQLite does
+** not make a copy of the new main schema name string, so the application
+** must ensure that the argument passed into SQLITE_DBCONFIG MAINDBNAME
+** is unchanged 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 behavior. 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
+** <dd> Usually, when a database in [WAL mode] is closed or detached from a
+** database handle, SQLite checks if if there are other connections to the
+** same database, and if there are no other database connection (if the
+** connection being closed is the last open connection to the database),
+** then SQLite performs a [checkpoint] before closing the connection and
+** deletes the WAL file. The SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE option can
+** be used to override that behavior. The first argument passed to this
+** operation (the third parameter to [sqlite3_db_config()]) is an integer
+** which is positive to disable checkpoints-on-close, or zero (the default)
+** to enable them, and negative to leave the setting unchanged.
+** The second argument (the fourth 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>
@@ -2798,7 +2870,7 @@ struct sqlite3_mem_methods {
** statistics. For statistics to be collected, the flag must be set on
** the database handle both when the SQL statement is prepared and when it
** is stepped. The flag is set (collection of statistics is enabled)
-** by default. This option takes two arguments: an integer and a pointer to
+** by default. <p>This option takes two arguments: an integer and a pointer to
** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
** leave unchanged the statement scanstatus option. If the second argument
** is not NULL, then the value of the statement scanstatus setting after
@@ -2812,7 +2884,7 @@ struct sqlite3_mem_methods {
** in which tables and indexes are scanned so that the scans start at the end
** and work toward the beginning rather than starting at the beginning and
** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
-** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** same as setting [PRAGMA reverse_unordered_selects]. <p>This option takes
** two arguments which are an integer and a pointer to an integer. The first
** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
** reverse scan order flag, respectively. If the second argument is not NULL,
@@ -2821,7 +2893,76 @@ struct sqlite3_mem_methods {
** first argument.
** </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]]
+** <dt>SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE option enables or disables
+** the ability of the [ATTACH DATABASE] SQL command to create a new database
+** file if the database filed named in the ATTACH command does not already
+** exist. This ability of ATTACH to create a new database is enabled by
+** default. Applications can disable or reenable the ability for ATTACH to
+** create new database files using this DBCONFIG option.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the attach-create flag, respectively. If the second
+** argument is not NULL, then 0 or 1 is written into the integer that the
+** second argument points to depending on if the attach-create flag is set
+** after processing the first argument.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE]]
+** <dt>SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE option enables or disables the
+** ability of the [ATTACH DATABASE] SQL command to open a database for writing.
+** This capability is enabled by default. Applications can disable or
+** reenable this capability using the current DBCONFIG option. If the
+** the this capability is disabled, the [ATTACH] command will still work,
+** but the database will be opened read-only. If this option is disabled,
+** then the ability to create a new database using [ATTACH] is also disabled,
+** regardless of the value of the [SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]
+** option.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the ability to ATTACH another database for writing,
+** respectively. If the second argument is not NULL, then 0 or 1 is written
+** into the integer to which the second argument points, depending on whether
+** the ability to ATTACH a read/write database is enabled or disabled
+** after processing the first argument.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_COMMENTS]]
+** <dt>SQLITE_DBCONFIG_ENABLE_COMMENTS</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_COMMENTS option enables or disables the
+** ability to include comments in SQL text. Comments are enabled by default.
+** An application can disable or reenable comments in SQL text using this
+** DBCONFIG option.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the ability to use comments in SQL text,
+** respectively. If the second argument is not NULL, then 0 or 1 is written
+** into the integer that the second argument points to depending on if
+** comments are allowed in SQL text after processing the first argument.
+** </dd>
+**
** </dl>
+**
+** [[DBCONFIG arguments]] <h3>Arguments To SQLITE_DBCONFIG Options</h3>
+**
+** <p>Most of the SQLITE_DBCONFIG options take two arguments, so that the
+** overall call to [sqlite3_db_config()] has a total of four parameters.
+** The first argument (the third parameter to sqlite3_db_config()) is a integer.
+** The second argument is a pointer to an integer. If the first argument is 1,
+** then the option becomes enabled. If the first integer argument is 0, then the
+** option is disabled. If the first argument is -1, then the option setting
+** is unchanged. The second argument, the pointer to an integer, may be NULL.
+** If the second argument is not NULL, then a value of 0 or 1 is written into
+** the integer to which the second argument points, depending on whether the
+** setting is disabled or enabled after applying any changes specified by
+** the first argument.
+**
+** <p>While most SQLITE_DBCONFIG options use the argument format
+** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME]
+** and [SQLITE_DBCONFIG_LOOKASIDE] options are different. See the
+** documentation of those exceptional options for details.
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
@@ -2843,7 +2984,10 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1022 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2935,10 +3079,14 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
** deleted by the most recently completed INSERT, UPDATE or DELETE
** statement on the database connection specified by the only parameter.
** The two functions are identical except for the type of the return value
-** and that if the number of rows modified by the most recent INSERT, UPDATE
+** and that if the number of rows modified by the most recent INSERT, UPDATE,
** or DELETE is greater than the maximum value supported by type "int", then
** the return value of sqlite3_changes() is undefined. ^Executing any other
** type of SQL statement does not modify the value returned by these functions.
+** For the purposes of this interface, a CREATE TABLE AS SELECT statement
+** does not count as an INSERT, UPDATE or DELETE statement and hence the rows
+** added to the new table by the CREATE TABLE AS SELECT statement are not
+** counted.
**
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
@@ -3194,6 +3342,44 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
/*
+** CAPI3REF: Set the Setlk Timeout
+** METHOD: sqlite3
+**
+** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If
+** the VFS supports blocking locks, it sets the timeout in ms used by
+** eligible locks taken on wal mode databases by the specified database
+** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does
+** not support blocking locks, this function is a no-op.
+**
+** Passing 0 to this function disables blocking locks altogether. Passing
+** -1 to this function requests that the VFS blocks for a long time -
+** indefinitely if possible. The results of passing any other negative value
+** are undefined.
+**
+** Internally, each SQLite database handle store two timeout values - the
+** busy-timeout (used for rollback mode databases, or if the VFS does not
+** support blocking locks) and the setlk-timeout (used for blocking locks
+** on wal-mode databases). The sqlite3_busy_timeout() method sets both
+** values, this function sets only the setlk-timeout value. Therefore,
+** to configure separate busy-timeout and setlk-timeout values for a single
+** database handle, call sqlite3_busy_timeout() followed by this function.
+**
+** Whenever the number of connections to a wal mode database falls from
+** 1 to 0, the last connection takes an exclusive lock on the database,
+** then checkpoints and deletes the wal file. While it is doing this, any
+** new connection that tries to read from the database fails with an
+** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is
+** passed to this API, the new connection blocks until the exclusive lock
+** has been released.
+*/
+SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags);
+
+/*
+** CAPI3REF: Flags for sqlite3_setlk_timeout()
+*/
+#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01
+
+/*
** CAPI3REF: Convenience Routines For Running Queries
** METHOD: sqlite3
**
@@ -3883,8 +4069,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
** <dd>The database connection comes up in "extended result code mode".
-** In other words, the database behaves has if
-** [sqlite3_extended_result_codes(db,1)] where called on the database
+** In other words, the database behaves as if
+** [sqlite3_extended_result_codes(db,1)] were called on the database
** connection as soon as the connection is created. In addition to setting
** the extended result code mode, this flag also causes [sqlite3_open_v2()]
** to return an extended result code.</dd>
@@ -4212,7 +4398,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
**
** 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
+** an array P of N URI Key/Value pairs. 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>
@@ -4498,11 +4684,22 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <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.
+**
+** [[SQLITE_PREPARE_DONT_LOG]] <dt>SQLITE_PREPARE_DONT_LOG</dt>
+** <dd>The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler
+** errors from being sent to the error log defined by
+** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test
+** compiles to see if some SQL syntax is well-formed, without generating
+** messages on the global error log when it is not. If the test compile
+** fails, the sqlite3_prepare_v3() call returns the same error indications
+** with or without this flag; it just omits the call to [sqlite3_log()] that
+** logs the error.
** </dl>
*/
#define SQLITE_PREPARE_PERSISTENT 0x01
#define SQLITE_PREPARE_NORMALIZE 0x02
#define SQLITE_PREPARE_NO_VTAB 0x04
+#define SQLITE_PREPARE_DONT_LOG 0x10
/*
** CAPI3REF: Compiling An SQL Statement
@@ -4535,13 +4732,17 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** 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
-** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** first zero terminator. ^If nByte is positive, then it is the maximum
+** number of bytes read from zSql. When nByte is positive, zSql is read
+** up to the first zero terminator or until the nByte bytes have been read,
+** whichever comes first. ^If nByte is zero, then no prepared
** statement is generated.
** If the caller knows that the supplied string is nul-terminated, then
** there is a small performance advantage to passing an nByte parameter that
** is the number of bytes in the input string <i>including</i>
** the nul-terminator.
+** Note that nByte measure the length of the input in bytes, not
+** characters, even for the UTF-16 interfaces.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -4878,7 +5079,7 @@ typedef struct sqlite3_context sqlite3_context;
** METHOD: sqlite3_stmt
**
** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
-** literals may be replaced by a [parameter] that matches one of following
+** literals may be replaced by a [parameter] that matches one of the following
** templates:
**
** <ul>
@@ -4923,7 +5124,7 @@ typedef struct sqlite3_context sqlite3_context;
**
** [[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
+** found in the 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().)^
@@ -4943,7 +5144,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 occurs at byte offsets less than
+** terminated. If any NUL characters occur 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.
@@ -5155,7 +5356,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** METHOD: sqlite3_stmt
**
** ^These routines provide a means to determine the database, table, and
-** table column that is the origin of a particular result column in
+** table column that is the origin of a particular result column in a
** [SELECT] statement.
** ^The name of the database or table or column can be returned as
** either a UTF-8 or UTF-16 string. ^The _database_ routines return
@@ -5293,7 +5494,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** other than [SQLITE_ROW] before any subsequent invocation of
** 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(). But after [version 3.6.23.1] ([dateof:3.6.23.1]),
** sqlite3_step() began
** calling [sqlite3_reset()] automatically in this circumstance rather
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
@@ -5724,8 +5925,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
**
** 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
+** used inside of triggers, views, CHECK constraints, or other elements of
+** the database schema. This flag 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
@@ -5756,7 +5957,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** [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
+** sqlite3_create_window_function() is not NULL, then it is the 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
@@ -5912,7 +6113,7 @@ SQLITE_API int sqlite3_create_window_function(
** This flag instructs SQLite to omit some corner-case optimizations that
** might disrupt the operation of the [sqlite3_value_subtype()] function,
** causing it to return zero rather than the correct subtype().
-** SQL functions that invokes [sqlite3_value_subtype()] should have this
+** All SQL functions that invoke [sqlite3_value_subtype()] should have this
** property. If the SQLITE_SUBTYPE property is omitted, then the return
** value from [sqlite3_value_subtype()] might sometimes be zero even though
** a non-zero subtype was specified by the function argument expression.
@@ -5928,6 +6129,15 @@ SQLITE_API int sqlite3_create_window_function(
** [sqlite3_result_subtype()] should avoid setting this property, as the
** purpose of this property is to disable certain optimizations that are
** incompatible with subtypes.
+**
+** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
+** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
+** that internally orders the values provided to the first argument. The
+** ordered-set aggregate SQL notation with a single ORDER BY term can be
+** used to invoke this function. If the ordered-set aggregate notation is
+** used on a function that lacks this flag, then an error is raised. Note
+** that the ordered-set aggregate syntax is only available if SQLite is
+** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
** </dd>
** </dl>
*/
@@ -5936,6 +6146,7 @@ SQLITE_API int sqlite3_create_window_function(
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
#define SQLITE_RESULT_SUBTYPE 0x001000000
+#define SQLITE_SELFORDER1 0x002000000
/*
** CAPI3REF: Deprecated Functions
@@ -6133,7 +6344,7 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
** one SQL function to another. Use the [sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
**
-** Every [application-defined SQL function] that invoke this interface
+** Every [application-defined SQL function] that invokes this interface
** should include the [SQLITE_SUBTYPE] property in the text
** encoding argument when the function is [sqlite3_create_function|registered].
** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype()
@@ -6146,7 +6357,7 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
** METHOD: sqlite3_value
**
** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value]
-** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
+** object V and returns a pointer to that copy. ^The [sqlite3_value] returned
** is a [protected sqlite3_value] object even if the input is not.
** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
** memory allocation fails. ^If V is a [pointer value], then the result
@@ -6184,7 +6395,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
** allocation 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
+** determined by the N parameter on the first successful call. Changing the
** 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
@@ -6346,7 +6557,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi
**
** Security Warning: These interfaces should not be exposed in scripting
** languages or in other circumstances where it might be possible for an
-** an attacker to invoke them. Any agent that can invoke these interfaces
+** attacker to invoke them. Any agent that can invoke these interfaces
** can probably also take control of the process.
**
** Database connection client data is only available for SQLite
@@ -6460,7 +6671,7 @@ typedef void (*sqlite3_destructor_type)(void*);
** pointed to by the 2nd parameter are taken as the application-defined
** function result. If the 3rd parameter is non-negative, then it
** must be the byte offset into the string where the NUL terminator would
-** appear if the string where NUL terminated. If any NUL characters occur
+** appear if the string were NUL terminated. If any NUL characters occur
** in the string at a byte offset that is less than the value of the 3rd
** parameter, then the resulting string will contain embedded NULs and the
** result of expressions operating on strings with embedded NULs is undefined.
@@ -6518,7 +6729,7 @@ typedef void (*sqlite3_destructor_type)(void*);
** 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
+** If these routines are called from within a different thread
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
@@ -6924,7 +7135,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
** METHOD: sqlite3
**
** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
-** for the N-th database on database connection D, or a NULL pointer of N is
+** for the N-th database on database connection D, or a NULL pointer if N is
** out of range. An N value of 0 means the main database file. An N of 1 is
** the "temp" schema. Larger values of N correspond to various ATTACH-ed
** databases.
@@ -7019,7 +7230,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
** <dd>The SQLITE_TXN_READ state means that the database is currently
** in a read transaction. Content has been read from the database file
** but nothing in the database file has changed. The transaction state
-** will advanced to SQLITE_TXN_WRITE if any changes occur and there are
+** will be advanced to SQLITE_TXN_WRITE if any changes occur and there are
** no other conflicting concurrent write transactions. The transaction
** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or
** [COMMIT].</dd>
@@ -7028,7 +7239,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
** <dd>The SQLITE_TXN_WRITE state means that the database is currently
** in a write transaction. Content has been written to the database file
** but has not yet committed. The transaction state will change to
-** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
+** SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
*/
#define SQLITE_TXN_NONE 0
#define SQLITE_TXN_READ 1
@@ -7179,6 +7390,8 @@ SQLITE_API int sqlite3_autovacuum_pages(
**
** ^The second argument is a pointer to the function to invoke when a
** row is updated, inserted or deleted in a rowid table.
+** ^The update hook is disabled by invoking sqlite3_update_hook()
+** with a NULL pointer as the second parameter.
** ^The first argument to the callback is a copy of the third argument
** to sqlite3_update_hook().
** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE],
@@ -7307,7 +7520,7 @@ 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.
+** used 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.
@@ -7365,7 +7578,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** </ul>)^
**
** The circumstances under which SQLite will enforce the heap limits may
-** changes in future releases of SQLite.
+** change 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);
@@ -7480,8 +7693,8 @@ SQLITE_API int sqlite3_table_column_metadata(
** ^The entry point is zProc.
** ^(zProc may be 0, in which case SQLite will try to come up with an
** entry point name on its own. It first tries "sqlite3_extension_init".
-** If that does not work, it constructs a name "sqlite3_X_init" where the
-** X is consists of the lower-case equivalent of all ASCII alphabetic
+** If that does not work, it constructs a name "sqlite3_X_init" where
+** X consists of the lower-case equivalent of all ASCII alphabetic
** characters in the filename from the last "/" to the first following
** "." and omitting any initial "lib".)^
** ^The sqlite3_load_extension() interface returns
@@ -7552,7 +7765,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
** ^(Even though the function prototype shows that xEntryPoint() takes
** no arguments and returns void, SQLite invokes xEntryPoint() with three
** arguments and expects an integer result as if the signature of the
-** entry point where as follows:
+** entry point were as follows:
**
** <blockquote><pre>
** &nbsp; int xEntryPoint(
@@ -7716,7 +7929,7 @@ struct sqlite3_module {
** 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
+** checked separately in byte code. If the omit flag is changed 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.)^
@@ -7740,9 +7953,11 @@ struct sqlite3_module {
** will be returned by the strategy.
**
** 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.
+** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
+** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
+** output to show the idxNum as hex instead of as decimal. Another flag is
+** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
+** return 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
@@ -7806,7 +8021,9 @@ struct sqlite3_index_info {
** [sqlite3_index_info].idxFlags field to some combination of
** these bits.
*/
-#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
+ /* in EXPLAIN QUERY PLAN */
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
@@ -7879,7 +8096,7 @@ struct sqlite3_index_info {
** the implementation of the [virtual table module]. ^The fourth
** parameter is an arbitrary client data pointer that is passed through
** into the [xCreate] and [xConnect] methods of the virtual table module
-** when a new virtual table is be being created or reinitialized.
+** when a new virtual table is being created or reinitialized.
**
** ^The sqlite3_create_module_v2() interface has a fifth parameter which
** is a pointer to a destructor for the pClientData. ^SQLite will
@@ -8044,7 +8261,7 @@ typedef struct sqlite3_blob sqlite3_blob;
** 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()]
-** on *ppBlob after this function it returns.
+** on *ppBlob after this function returns.
**
** This function fails with SQLITE_ERROR if any of the following are true:
** <ul>
@@ -8164,7 +8381,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
**
** ^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
+** incremental blob I/O routines can only read or overwrite existing
** blob content; they cannot change the size of a blob.
**
** This routine only works on a [BLOB handle] which has been created
@@ -8314,7 +8531,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** ^The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
** routine returns NULL if it is unable to allocate the requested
-** mutex. The argument to sqlite3_mutex_alloc() must one of these
+** mutex. The argument to sqlite3_mutex_alloc() must be one of these
** integer constants:
**
** <ul>
@@ -8547,7 +8764,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
** 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 to 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
@@ -8643,6 +8860,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
+#define SQLITE_TESTCTRL_GETOPT 16
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
@@ -8662,14 +8880,14 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_USELONGDOUBLE 34
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
#define SQLITE_TESTCTRL_LAST 34 /* 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
+** recognized by SQLite. Applications can use 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.
**
@@ -8837,7 +9055,7 @@ SQLITE_API void sqlite3_str_reset(sqlite3_str*);
** 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] object. Applications must not use the pointer returned by
** [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
@@ -8923,7 +9141,7 @@ SQLITE_API int sqlite3_status64(
** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
** buffer and where forced to overflow to [sqlite3_malloc()]. The
** returned value includes allocations that overflowed because they
-** where too large (they were larger than the "sz" parameter to
+** were too large (they were larger than the "sz" parameter to
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
** no space was left in the page cache.</dd>)^
**
@@ -9007,28 +9225,29 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
** <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.)^
+** the current value is always zero.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
-** <dd>This parameter returns the number malloc attempts that might have
+** <dd>This parameter returns the number of malloc attempts that might have
** been satisfied using lookaside memory but failed due to the amount of
** memory requested being larger than the lookaside slot size.
** Only the high-water value is meaningful;
-** the current value is always zero.)^
+** the current value is always zero.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]]
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
-** <dd>This parameter returns the number malloc attempts that might have
+** <dd>This parameter returns the number of malloc attempts that might have
** been satisfied using lookaside memory but failed due to all lookaside
** memory already being in use.
** Only the high-water value is meaningful;
-** the current value is always zero.)^
+** the current value is always zero.</dd>)^
**
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
+** </dd>
**
** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
@@ -9037,10 +9256,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** memory used by that pager cache is divided evenly between the attached
** connections.)^ In other words, if none of the pager caches associated
** with the database connection are shared, this request returns the same
-** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
+** value as DBSTATUS_CACHE_USED. Or, if one or more of the pager caches are
** shared, the value returned by this call will be smaller than that returned
** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
-** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
+** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.</dd>
**
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
@@ -9050,6 +9269,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** schema memory is shared with other database connections due to
** [shared cache mode] being enabled.
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
+** </dd>
**
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
@@ -9086,7 +9306,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** 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
+** additional overhead. This parameter can be used to help identify
** inefficiencies that can be resolved by increasing the cache size.
** </dd>
**
@@ -9566,7 +9786,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** 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
-** database is modified by the using the same database connection as is used
+** database is modified by using the same database connection as is used
** by the backup operation, then the backup database is automatically
** updated at the same time.
**
@@ -9583,7 +9803,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** and may not be used following a call to sqlite3_backup_finish().
**
** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no
-** sqlite3_backup_step() errors occurred, regardless or whether or not
+** sqlite3_backup_step() errors occurred, regardless of whether or not
** sqlite3_backup_step() completed.
** ^If an out-of-memory condition or IO error occurred during any prior
** sqlite3_backup_step() call on the same [sqlite3_backup] object, then
@@ -9638,6 +9858,16 @@ typedef struct sqlite3_backup sqlite3_backup;
** APIs are not strictly speaking threadsafe. If they are invoked at the
** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values.
+**
+** <b>Alternatives To Using The Backup API</b>
+**
+** Other techniques for safely creating a consistent backup of an SQLite
+** database include:
+**
+** <ul>
+** <li> The [VACUUM INTO] command.
+** <li> The [sqlite3_rsync] utility program.
+** </ul>
*/
SQLITE_API sqlite3_backup *sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */
@@ -10643,7 +10873,7 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
** METHOD: sqlite3
**
** ^If a write-transaction is open on [database connection] D when the
-** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
+** [sqlite3_db_cacheflush(D)] interface is invoked, any dirty
** 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
@@ -10837,6 +11067,14 @@ typedef struct sqlite3_snapshot {
** If there is not already a read-transaction open on schema S when
** this function is called, one is opened automatically.
**
+** If a read-transaction is opened by this function, then it is guaranteed
+** that the returned snapshot object may not be invalidated by a database
+** writer or checkpointer until after the read-transaction is closed. This
+** is not guaranteed if a read-transaction is already open when this
+** function is called. In that case, any subsequent write or checkpoint
+** operation on the database may invalidate the returned snapshot handle,
+** even while the read-transaction remains open.
+**
** 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
@@ -10994,8 +11232,9 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
/*
** 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.
+** 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 S is a NULL pointer, the main database is used.
** If P is not a NULL pointer, then the size of the database in bytes
** is written into *P.
**
@@ -11145,8 +11384,6 @@ SQLITE_API int sqlite3_deserialize(
#if defined(__wasi__)
# undef SQLITE_WASI
# define SQLITE_WASI 1
-# undef SQLITE_OMIT_WAL
-# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
# ifndef SQLITE_OMIT_LOAD_EXTENSION
# define SQLITE_OMIT_LOAD_EXTENSION
# endif
@@ -11158,7 +11395,7 @@ SQLITE_API int sqlite3_deserialize(
#if 0
} /* End of the 'extern "C"' block */
#endif
-#endif /* SQLITE3_H */
+/* #endif for SQLITE3_H will be added by mksqlite3.tcl */
/******** Begin file sqlite3rtree.h *********/
/*
@@ -11639,9 +11876,10 @@ SQLITE_API void sqlite3session_table_filter(
** 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
-** 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.
+** Or, if one field of a row is updated while a session is enabled, and
+** then another field of the same row is updated while the session is disabled,
+** the resulting changeset will contain an UPDATE change that updates both
+** fields.
*/
SQLITE_API int sqlite3session_changeset(
sqlite3_session *pSession, /* Session object */
@@ -11713,8 +11951,9 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession
** 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.
+** Unless the call to this function is a no-op as described above, it is an
+** error if database zFrom does not exist or does not contain the required
+** compatible table.
**
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
@@ -11849,7 +12088,7 @@ SQLITE_API int 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>
+** <dt>SQLITE_CHANGESETSTART_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.
@@ -12164,19 +12403,6 @@ SQLITE_API int sqlite3changeset_concat(
void **ppOut /* OUT: Buffer containing output changeset */
);
-
-/*
-** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
-*/
-SQLITE_API int sqlite3changeset_upgrade(
- sqlite3 *db,
- const char *zDb,
- int nIn, const void *pIn, /* Input changeset */
- int *pnOut, void **ppOut /* OUT: Inverse of input */
-);
-
-
-
/*
** CAPI3REF: Changegroup Handle
**
@@ -13349,6 +13575,10 @@ struct Fts5PhraseIter {
** (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).
**
+** In all cases, matches are visited in (column ASC, offset ASC) order.
+** i.e. all those in column 0, sorted by offset, followed by those in
+** column 1, etc.
+**
** xPhraseNext()
** See xPhraseFirst above.
**
@@ -13405,19 +13635,57 @@ struct Fts5PhraseIter {
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
** output variable (*ppToken) is set to point to a buffer containing the
** matching document token, and (*pnToken) to the size of that buffer in
-** bytes. This API is not available if the specified token matches a
-** prefix query term. In that case both output variables are always set
-** to 0.
+** bytes.
**
** The output text is not a copy of the document text that was tokenized.
** It is the output of the tokenizer module. For tokendata=1 tables, this
** includes any embedded 0x00 and trailing data.
**
+** This API may be slow in some cases if the token identified by parameters
+** iIdx and iToken matched a prefix token in the query. In most cases, the
+** first call to this API for each prefix token in the query is forced
+** to scan the portion of the full-text index that matches the prefix
+** token to collect the extra data required by this API. If the prefix
+** token matches a large number of token instances in the document set,
+** this may be a performance problem.
+**
+** If the user knows in advance that a query may use this API for a
+** prefix token, FTS5 may be configured to collect all required data as part
+** of the initial querying of the full-text index, avoiding the second scan
+** entirely. This also causes prefix queries that do not use this API to
+** run more slowly and use more memory. FTS5 may be configured in this way
+** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
+** option, or on a per-query basis using the
+** [fts5_insttoken | fts5_insttoken()] user function.
+**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
+**
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the locale associated
+** with column iCol of the current row. Usually, there is no associated
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
+** to NULL and 0, respectively. However, if the fts5_locale() function
+** was used to associate a locale with the value when it was inserted
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
+** is set to the size in bytes of the buffer, not including the
+** nul-terminator.
+**
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
+** SQLite error code is returned. The final value of the output parameters
+** is undefined in this case.
+**
+** xTokenize_v2:
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
+** API is the same as the xTokenize() API, except that it allows a tokenizer
+** locale to be specified.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
+ int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*);
@@ -13459,6 +13727,15 @@ struct Fts5ExtensionApi {
const char **ppToken, int *pnToken
);
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
+
+ /* Below this point are iVersion>=4 only */
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
+ int (*xTokenize_v2)(Fts5Context*,
+ const char *pText, int nText, /* Text to tokenize */
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
+ void *pCtx, /* Context passed to xToken() */
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
+ );
};
/*
@@ -13479,7 +13756,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
+** pointer provided by the application when the fts5_tokenizer_v2 object
** 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
@@ -13503,7 +13780,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
-** The second argument indicates the reason that FTS5 is requesting
+** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
@@ -13527,6 +13804,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database.
** </ul>
**
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
+** nLocale - are a pointer to a buffer containing the locale to use for
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
+** which case nLocale is always 0) to indicate that the tokenizer should
+** use its default locale.
+**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
@@ -13550,6 +13834,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
+** then the xTokenize() method has two additional arguments - pLocale
+** and nLocale. These specify the locale that the tokenizer should use
+** for the current request. If pLocale and nLocale are both 0, then the
+** tokenizer should use its default locale. Otherwise, pLocale points to
+** an nLocale byte buffer containing the name of the locale to use as utf-8
+** text. pLocale is not nul-terminated.
+**
+** FTS5_TOKENIZER
+**
+** There is also an fts5_tokenizer object. This is an older, deprecated,
+** version of fts5_tokenizer_v2. It is similar except that:
+**
+** <ul>
+** <li> There is no "iVersion" field, and
+** <li> The xTokenize() method does not take a locale argument.
+** </ul>
+**
+** Legacy fts5_tokenizer tokenizers must be registered using the
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
+**
+** Tokenizer implementations registered using either API may be retrieved
+** using both xFindTokenizer() and xFindTokenizer_v2().
+**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -13658,6 +13966,33 @@ struct Fts5ExtensionApi {
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
+struct fts5_tokenizer_v2 {
+ int iVersion; /* Currently always 2 */
+
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+ void (*xDelete)(Fts5Tokenizer*);
+ int (*xTokenize)(Fts5Tokenizer*,
+ void *pCtx,
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Pointer to buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStart, /* Byte offset of token within input text */
+ int iEnd /* Byte offset of end of token within input text */
+ )
+ );
+};
+
+/*
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
+** implementations. The following type is included for legacy applications
+** that still use it.
+*/
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -13677,6 +14012,7 @@ struct fts5_tokenizer {
);
};
+
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
@@ -13696,7 +14032,7 @@ struct fts5_tokenizer {
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
@@ -13723,6 +14059,25 @@ struct fts5_api {
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
+
+ /* APIs below this point are only available if iVersion>=3 */
+
+ /* Create a new tokenizer */
+ int (*xCreateTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void *pUserData,
+ fts5_tokenizer_v2 *pTokenizer,
+ void (*xDestroy)(void*)
+ );
+
+ /* Find an existing tokenizer */
+ int (*xFindTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer
+ );
};
/*
@@ -13736,6 +14091,7 @@ struct fts5_api {
#endif /* _FTS5_H */
/******** End of fts5.h *********/
+#endif /* SQLITE3_H */
/************** End of sqlite3.h *********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -13781,6 +14137,7 @@ struct fts5_api {
#ifndef SQLITE_MAX_LENGTH
# define SQLITE_MAX_LENGTH 1000000000
#endif
+#define SQLITE_MIN_LENGTH 30 /* Minimum value for the length limit */
/*
** This is the maximum number of
@@ -13793,14 +14150,22 @@ struct fts5_api {
** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
** * Terms in the VALUES clause of an INSERT statement
**
-** The hard upper limit here is 32676. Most database people will
+** The hard upper limit here is 32767. Most database people will
** tell you that in a well-normalized database, you usually should
** not have more than a dozen or so columns in any table. And if
** that is the case, there is no point in having more than a few
** dozen values in any of the other situations described above.
+**
+** An index can only have SQLITE_MAX_COLUMN columns from the user
+** point of view, but the underlying b-tree that implements the index
+** might have up to twice as many columns in a WITHOUT ROWID table,
+** since must also store the primary key at the end. Hence the
+** column count for Index is u16 instead of i16.
*/
-#ifndef SQLITE_MAX_COLUMN
+#if !defined(SQLITE_MAX_COLUMN)
# define SQLITE_MAX_COLUMN 2000
+#elif SQLITE_MAX_COLUMN>32767
+# error SQLITE_MAX_COLUMN may not exceed 32767
#endif
/*
@@ -13846,9 +14211,13 @@ struct fts5_api {
/*
** The maximum number of arguments to an SQL function.
+**
+** This value has a hard upper limit of 32767 due to storage
+** constraints (it needs to fit inside a i16). We keep it
+** lower than that to prevent abuse.
*/
#ifndef SQLITE_MAX_FUNCTION_ARG
-# define SQLITE_MAX_FUNCTION_ARG 127
+# define SQLITE_MAX_FUNCTION_ARG 1000
#endif
/*
@@ -14448,6 +14817,7 @@ struct HashElem {
HashElem *next, *prev; /* Next and previous elements in the table */
void *data; /* Data associated with this element */
const char *pKey; /* Key associated with this element */
+ unsigned int h; /* hash for pKey */
};
/*
@@ -14532,132 +14902,132 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#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_MATERIALIZED 97
-#define TK_REINDEX 98
-#define TK_RENAME 99
-#define TK_CTIME_KW 100
-#define TK_ANY 101
-#define TK_BITAND 102
-#define TK_BITOR 103
-#define TK_LSHIFT 104
-#define TK_RSHIFT 105
-#define TK_PLUS 106
-#define TK_MINUS 107
-#define TK_STAR 108
-#define TK_SLASH 109
-#define TK_REM 110
-#define TK_CONCAT 111
-#define TK_PTR 112
-#define TK_COLLATE 113
-#define TK_BITNOT 114
-#define TK_ON 115
-#define TK_INDEXED 116
-#define TK_STRING 117
-#define TK_JOIN_KW 118
-#define TK_CONSTRAINT 119
-#define TK_DEFAULT 120
-#define TK_NULL 121
-#define TK_PRIMARY 122
-#define TK_UNIQUE 123
-#define TK_CHECK 124
-#define TK_REFERENCES 125
-#define TK_AUTOINCR 126
-#define TK_INSERT 127
-#define TK_DELETE 128
-#define TK_UPDATE 129
-#define TK_SET 130
-#define TK_DEFERRABLE 131
-#define TK_FOREIGN 132
-#define TK_DROP 133
-#define TK_UNION 134
-#define TK_ALL 135
-#define TK_EXCEPT 136
-#define TK_INTERSECT 137
-#define TK_SELECT 138
-#define TK_VALUES 139
-#define TK_DISTINCT 140
-#define TK_DOT 141
-#define TK_FROM 142
-#define TK_JOIN 143
-#define TK_USING 144
-#define TK_ORDER 145
-#define TK_GROUP 146
-#define TK_HAVING 147
-#define TK_LIMIT 148
-#define TK_WHERE 149
-#define TK_RETURNING 150
-#define TK_INTO 151
-#define TK_NOTHING 152
-#define TK_FLOAT 153
-#define TK_BLOB 154
-#define TK_INTEGER 155
-#define TK_VARIABLE 156
-#define TK_CASE 157
-#define TK_WHEN 158
-#define TK_THEN 159
-#define TK_ELSE 160
-#define TK_INDEX 161
-#define TK_ALTER 162
-#define TK_ADD 163
-#define TK_WINDOW 164
-#define TK_OVER 165
-#define TK_FILTER 166
-#define TK_COLUMN 167
-#define TK_AGG_FUNCTION 168
-#define TK_AGG_COLUMN 169
-#define TK_TRUEFALSE 170
-#define TK_ISNOT 171
+#define TK_ISNOT 46
+#define TK_MATCH 47
+#define TK_LIKE_KW 48
+#define TK_BETWEEN 49
+#define TK_IN 50
+#define TK_ISNULL 51
+#define TK_NOTNULL 52
+#define TK_NE 53
+#define TK_EQ 54
+#define TK_GT 55
+#define TK_LE 56
+#define TK_LT 57
+#define TK_GE 58
+#define TK_ESCAPE 59
+#define TK_ID 60
+#define TK_COLUMNKW 61
+#define TK_DO 62
+#define TK_FOR 63
+#define TK_IGNORE 64
+#define TK_INITIALLY 65
+#define TK_INSTEAD 66
+#define TK_NO 67
+#define TK_KEY 68
+#define TK_OF 69
+#define TK_OFFSET 70
+#define TK_PRAGMA 71
+#define TK_RAISE 72
+#define TK_RECURSIVE 73
+#define TK_REPLACE 74
+#define TK_RESTRICT 75
+#define TK_ROW 76
+#define TK_ROWS 77
+#define TK_TRIGGER 78
+#define TK_VACUUM 79
+#define TK_VIEW 80
+#define TK_VIRTUAL 81
+#define TK_WITH 82
+#define TK_NULLS 83
+#define TK_FIRST 84
+#define TK_LAST 85
+#define TK_CURRENT 86
+#define TK_FOLLOWING 87
+#define TK_PARTITION 88
+#define TK_PRECEDING 89
+#define TK_RANGE 90
+#define TK_UNBOUNDED 91
+#define TK_EXCLUDE 92
+#define TK_GROUPS 93
+#define TK_OTHERS 94
+#define TK_TIES 95
+#define TK_GENERATED 96
+#define TK_ALWAYS 97
+#define TK_MATERIALIZED 98
+#define TK_REINDEX 99
+#define TK_RENAME 100
+#define TK_CTIME_KW 101
+#define TK_ANY 102
+#define TK_BITAND 103
+#define TK_BITOR 104
+#define TK_LSHIFT 105
+#define TK_RSHIFT 106
+#define TK_PLUS 107
+#define TK_MINUS 108
+#define TK_STAR 109
+#define TK_SLASH 110
+#define TK_REM 111
+#define TK_CONCAT 112
+#define TK_PTR 113
+#define TK_COLLATE 114
+#define TK_BITNOT 115
+#define TK_ON 116
+#define TK_INDEXED 117
+#define TK_STRING 118
+#define TK_JOIN_KW 119
+#define TK_CONSTRAINT 120
+#define TK_DEFAULT 121
+#define TK_NULL 122
+#define TK_PRIMARY 123
+#define TK_UNIQUE 124
+#define TK_CHECK 125
+#define TK_REFERENCES 126
+#define TK_AUTOINCR 127
+#define TK_INSERT 128
+#define TK_DELETE 129
+#define TK_UPDATE 130
+#define TK_SET 131
+#define TK_DEFERRABLE 132
+#define TK_FOREIGN 133
+#define TK_DROP 134
+#define TK_UNION 135
+#define TK_ALL 136
+#define TK_EXCEPT 137
+#define TK_INTERSECT 138
+#define TK_SELECT 139
+#define TK_VALUES 140
+#define TK_DISTINCT 141
+#define TK_DOT 142
+#define TK_FROM 143
+#define TK_JOIN 144
+#define TK_USING 145
+#define TK_ORDER 146
+#define TK_GROUP 147
+#define TK_HAVING 148
+#define TK_LIMIT 149
+#define TK_WHERE 150
+#define TK_RETURNING 151
+#define TK_INTO 152
+#define TK_NOTHING 153
+#define TK_FLOAT 154
+#define TK_BLOB 155
+#define TK_INTEGER 156
+#define TK_VARIABLE 157
+#define TK_CASE 158
+#define TK_WHEN 159
+#define TK_THEN 160
+#define TK_ELSE 161
+#define TK_INDEX 162
+#define TK_ALTER 163
+#define TK_ADD 164
+#define TK_WINDOW 165
+#define TK_OVER 166
+#define TK_FILTER 167
+#define TK_COLUMN 168
+#define TK_AGG_FUNCTION 169
+#define TK_AGG_COLUMN 170
+#define TK_TRUEFALSE 171
#define TK_FUNCTION 172
#define TK_UPLUS 173
#define TK_UMINUS 174
@@ -14671,7 +15041,8 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_ERROR 182
#define TK_QNUMBER 183
#define TK_SPACE 184
-#define TK_ILLEGAL 185
+#define TK_COMMENT 185
+#define TK_ILLEGAL 186
/************** End of parse.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -14680,6 +15051,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#include <string.h>
#include <assert.h>
#include <stddef.h>
+#include <ctype.h>
/*
** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
@@ -14700,7 +15072,8 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#ifdef SQLITE_OMIT_FLOATING_POINT
# define double sqlite_int64
# define float sqlite_int64
-# define LONGDOUBLE_TYPE sqlite_int64
+# define fabs(X) ((X)<0?-(X):(X))
+# define sqlite3IsOverflow(X) 0
# ifndef SQLITE_BIG_DBL
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
# endif
@@ -14805,7 +15178,17 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
** ourselves.
*/
#ifndef offsetof
-#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
+#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+#endif
+
+/*
+** Work around C99 "flex-array" syntax for pre-C99 compilers, so as
+** to avoid complaints from -fsanitize=strict-bounds.
+*/
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
#endif
/*
@@ -14875,9 +15258,6 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
# define INT8_TYPE signed char
# endif
#endif
-#ifndef LONGDOUBLE_TYPE
-# define LONGDOUBLE_TYPE long double
-#endif
typedef sqlite_int64 i64; /* 8-byte signed integer */
typedef sqlite_uint64 u64; /* 8-byte unsigned integer */
typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
@@ -14886,6 +15266,11 @@ typedef INT16_TYPE i16; /* 2-byte signed integer */
typedef UINT8_TYPE u8; /* 1-byte unsigned integer */
typedef INT8_TYPE i8; /* 1-byte signed integer */
+/* A bitfield type for use inside of structures. Always follow with :N where
+** N is the number of bits.
+*/
+typedef unsigned bft; /* Bit Field Type */
+
/*
** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value
** that can be stored in a u32 without loss of data. The value
@@ -14924,6 +15309,8 @@ typedef u64 tRowcnt;
** 0.5 -> -10 0.1 -> -33 0.0625 -> -40
*/
typedef INT16_TYPE LogEst;
+#define LOGEST_MIN (-32768)
+#define LOGEST_MAX (32767)
/*
** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer
@@ -15053,6 +15440,14 @@ typedef INT16_TYPE LogEst;
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
/*
+** Macro SMXV(n) return the maximum value that can be held in variable n,
+** assuming n is a signed integer type. UMXV(n) is similar for unsigned
+** integer types.
+*/
+#define SMXV(n) ((((i64)1)<<(sizeof(n)*8-1))-1)
+#define UMXV(n) ((((i64)1)<<(sizeof(n)*8))-1)
+
+/*
** Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
**
@@ -15194,7 +15589,7 @@ SQLITE_PRIVATE u32 sqlite3WhereTrace;
** 0xFFFF---- Low-level debug messages
**
** 0x00000001 Code generation
-** 0x00000002 Solver
+** 0x00000002 Solver (Use 0x40000 for less detail)
** 0x00000004 Solver costs
** 0x00000008 WhereLoop inserts
**
@@ -15213,6 +15608,8 @@ SQLITE_PRIVATE u32 sqlite3WhereTrace;
**
** 0x00010000 Show more detail when printing WHERE terms
** 0x00020000 Show WHERE terms returned from whereScanNext()
+** 0x00040000 Solver overview messages
+** 0x00080000 Star-query heuristic
*/
@@ -15377,6 +15774,7 @@ typedef struct Savepoint Savepoint;
typedef struct Select Select;
typedef struct SQLiteThread SQLiteThread;
typedef struct SelectDest SelectDest;
+typedef struct Subquery Subquery;
typedef struct SrcItem SrcItem;
typedef struct SrcList SrcList;
typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */
@@ -15850,6 +16248,22 @@ typedef struct PgHdr DbPage;
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
+#define isWalMode(x) ((x)==PAGER_JOURNALMODE_WAL)
+
+/*
+** 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.
+**
+** This is so that expressions can be written as:
+**
+** if( isOpen(pPager->jfd) ){ ...
+**
+** instead of
+**
+** if( pPager->jfd->pMethods ){ ...
+*/
+#define isOpen(pFd) ((pFd)->pMethods!=0)
+
/*
** Flags that make up the mask passed to sqlite3PagerGet().
*/
@@ -16259,6 +16673,9 @@ SQLITE_PRIVATE int sqlite3BtreeCursor(
);
SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor(Btree*,BtCursor*);
+#endif
SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
@@ -16477,6 +16894,20 @@ typedef struct Vdbe Vdbe;
*/
typedef struct sqlite3_value Mem;
typedef struct SubProgram SubProgram;
+typedef struct SubrtnSig SubrtnSig;
+
+/*
+** A signature for a reusable subroutine that materializes the RHS of
+** an IN operator.
+*/
+struct SubrtnSig {
+ int selId; /* SELECT-id for the SELECT statement on the RHS */
+ u8 bComplete; /* True if fully coded and available for reusable */
+ char *zAff; /* Affinity of the overall IN expression */
+ int iTable; /* Ephemeral table generated by the subroutine */
+ int iAddr; /* Subroutine entry address */
+ int regReturn; /* Register used to hold return address */
+};
/*
** A single instruction of the virtual machine has an opcode
@@ -16505,6 +16936,7 @@ struct VdbeOp {
u32 *ai; /* Used when p4type is P4_INTARRAY */
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
Table *pTab; /* Used when p4type is P4_TABLE */
+ SubrtnSig *pSubrtnSig; /* Used when p4type is P4_SUBRTNSIG */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
@@ -16572,6 +17004,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */
#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */
+#define P4_SUBRTNSIG (-17) /* P4 is a SubrtnSig pointer */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
@@ -16663,16 +17096,16 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
#define OP_Program 48 /* jump0 */
#define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 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_ElseEq 58 /* jump, same as TK_ESCAPE */
-#define OP_IfPos 59 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IfPos 50 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IsNull 51 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
+#define OP_NotNull 52 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
+#define OP_Ne 53 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
+#define OP_Eq 54 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
+#define OP_Gt 55 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
+#define OP_Le 56 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
+#define OP_Lt 57 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
+#define OP_Ge 58 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
+#define OP_ElseEq 59 /* jump, same as TK_ESCAPE */
#define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */
#define OP_IncrVacuum 62 /* jump */
@@ -16715,23 +17148,23 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_ReadCookie 99
#define OP_SetCookie 100
#define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */
-#define OP_BitAnd 102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
-#define OP_BitOr 103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
-#define OP_ShiftLeft 104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
-#define OP_ShiftRight 105 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
-#define OP_Add 106 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
-#define OP_Subtract 107 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
-#define OP_Multiply 108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
-#define OP_Divide 109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
-#define OP_Remainder 110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
-#define OP_Concat 111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_OpenRead 112 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenRead 102 /* synopsis: root=P2 iDb=P3 */
+#define OP_BitAnd 103 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
+#define OP_BitOr 104 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
+#define OP_ShiftLeft 105 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
+#define OP_ShiftRight 106 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
+#define OP_Add 107 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
+#define OP_Subtract 108 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
+#define OP_Multiply 109 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
+#define OP_Divide 110 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
+#define OP_Remainder 111 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
+#define OP_Concat 112 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_OpenWrite 113 /* synopsis: root=P2 iDb=P3 */
-#define OP_BitNot 114 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
-#define OP_OpenDup 115
+#define OP_OpenDup 114
+#define OP_BitNot 115 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
#define OP_OpenAutoindex 116 /* synopsis: nColumn=P2 */
-#define OP_String8 117 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_OpenEphemeral 118 /* synopsis: nColumn=P2 */
+#define OP_OpenEphemeral 117 /* synopsis: nColumn=P2 */
+#define OP_String8 118 /* same as TK_STRING, synopsis: r[P2]='P4' */
#define OP_SorterOpen 119
#define OP_SequenceTest 120 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
#define OP_OpenPseudo 121 /* synopsis: P3 columns in r[P2] */
@@ -16766,8 +17199,8 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_LoadAnalysis 150
#define OP_DropTable 151
#define OP_DropIndex 152
-#define OP_Real 153 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_DropTrigger 154
+#define OP_DropTrigger 153
+#define OP_Real 154 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
#define OP_IntegrityCk 155
#define OP_RowSetAdd 156 /* synopsis: rowset(P1)=r[P2] */
#define OP_Param 157
@@ -16823,20 +17256,20 @@ typedef struct VdbeOpList VdbeOpList;
/* 24 */ 0xc9, 0x01, 0x49, 0x49, 0x49, 0x49, 0xc9, 0x49,\
/* 32 */ 0xc1, 0x01, 0x41, 0x41, 0xc1, 0x01, 0x41, 0x41,\
/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x23, 0x0b,\
-/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
-/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x41,\
+/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\
+/* 56 */ 0x0b, 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x01, 0x41,\
/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\
/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\
/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\
/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\
-/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x26, 0x26,\
+/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
-/* 112 */ 0x40, 0x00, 0x12, 0x40, 0x40, 0x10, 0x40, 0x00,\
+/* 112 */ 0x26, 0x00, 0x40, 0x12, 0x40, 0x40, 0x10, 0x00,\
/* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\
/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50,\
/* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\
/* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
-/* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\
+/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x06, 0x10, 0x00, 0x04,\
/* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\
/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\
@@ -16857,7 +17290,7 @@ typedef struct VdbeOpList VdbeOpList;
** Additional non-public SQLITE_PREPARE_* flags
*/
#define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */
-#define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */
+#define SQLITE_PREPARE_MASK 0x1f /* Mask of public flags */
/*
** Prototypes for the VDBE interface. See comments on the implementation
@@ -16990,8 +17423,8 @@ SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*);
SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*);
#endif
-/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
-** each VDBE opcode.
+/* Use SQLITE_ENABLE_EXPLAIN_COMMENTS to enable generation of extra
+** comments on each VDBE opcode.
**
** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op
** comments in VDBE programs that show key decision points in the code
@@ -17572,47 +18005,11 @@ struct FuncDefHash {
};
#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ)
-#if defined(SQLITE_USER_AUTHENTICATION)
-# warning "The SQLITE_USER_AUTHENTICATION extension is deprecated. \
- See ext/userauth/user-auth.txt for details."
-#endif
-#ifdef SQLITE_USER_AUTHENTICATION
-/*
-** Information held in the "sqlite3" database connection object and used
-** to manage user authentication.
-*/
-typedef struct sqlite3_userauth sqlite3_userauth;
-struct sqlite3_userauth {
- u8 authLevel; /* Current authentication level */
- int nAuthPW; /* Size of the zAuthPW in bytes */
- char *zAuthPW; /* Password used to authenticate */
- char *zAuthUser; /* User name used to authenticate */
-};
-
-/* Allowed values for sqlite3_userauth.authLevel */
-#define UAUTH_Unknown 0 /* Authentication not yet checked */
-#define UAUTH_Fail 1 /* User authentication failed */
-#define UAUTH_User 2 /* Authenticated as a normal user */
-#define UAUTH_Admin 3 /* Authenticated as an administrator */
-
-/* Functions used only by user authorization logic */
-SQLITE_PRIVATE int sqlite3UserAuthTable(const char*);
-SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*);
-SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*);
-SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
-
-#endif /* SQLITE_USER_AUTHENTICATION */
-
/*
** typedef for the authorization callback function.
*/
-#ifdef SQLITE_USER_AUTHENTICATION
- typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
- const char*, const char*);
-#else
- typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
- const char*);
-#endif
+typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,
+ const char*);
#ifndef SQLITE_OMIT_DEPRECATED
/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
@@ -17750,6 +18147,10 @@ struct sqlite3 {
Savepoint *pSavepoint; /* List of active savepoints */
int nAnalysisLimit; /* Number of index rows to ANALYZE */
int busyTimeout; /* Busy handler timeout, in msec */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int setlkTimeout; /* Blocking lock timeout, in msec. -1 -> inf. */
+ int setlkFlags; /* Flags passed to setlk_timeout() */
+#endif
int nSavepoint; /* Number of non-transaction savepoints */
int nStatement; /* Number of nested statement-transactions */
i64 nDeferredCons; /* Net deferred constraints this transaction. */
@@ -17773,9 +18174,6 @@ struct sqlite3 {
void (*xUnlockNotify)(void **, int); /* Unlock notify callback */
sqlite3 *pNextBlocked; /* Next in list of all blocked connections */
#endif
-#ifdef SQLITE_USER_AUTHENTICATION
- sqlite3_userauth auth; /* User authentication information */
-#endif
};
/*
@@ -17839,6 +18237,9 @@ struct sqlite3 {
#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */
#define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */
#define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */
+#define SQLITE_AttachCreate HI(0x00010) /* ATTACH allowed to create new dbs */
+#define SQLITE_AttachWrite HI(0x00020) /* ATTACH allowed to open for write */
+#define SQLITE_Comments HI(0x00040) /* Enable SQL comments */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
@@ -17897,6 +18298,8 @@ struct sqlite3 {
#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */
#define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */
+#define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */
+#define SQLITE_StarQuery 0x20000000 /* Heurists for star queries */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -17933,7 +18336,7 @@ struct sqlite3 {
** field is used by per-connection app-def functions.
*/
struct FuncDef {
- i8 nArg; /* Number of arguments. -1 means unlimited */
+ i16 nArg; /* Number of arguments. -1 means unlimited */
u32 funcFlags; /* Some combination of SQLITE_FUNC_* */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
@@ -18302,6 +18705,7 @@ struct CollSeq {
#define SQLITE_AFF_INTEGER 0x44 /* 'D' */
#define SQLITE_AFF_REAL 0x45 /* 'E' */
#define SQLITE_AFF_FLEXNUM 0x46 /* 'F' */
+#define SQLITE_AFF_DEFER 0x58 /* 'X' - defer computation until later */
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
@@ -18426,6 +18830,7 @@ struct Table {
} u;
Trigger *pTrigger; /* List of triggers on this object */
Schema *pSchema; /* Schema that contains this table */
+ u8 aHx[16]; /* Column aHt[K%sizeof(aHt)] might have hash K */
};
/*
@@ -18559,9 +18964,13 @@ struct FKey {
struct sColMap { /* Mapping of columns in pFrom to columns in zTo */
int iFrom; /* Index of column in pFrom */
char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */
- } aCol[1]; /* One entry for each of nCol columns */
+ } aCol[FLEXARRAY]; /* One entry for each of nCol columns */
};
+/* The size (in bytes) of an FKey object holding N columns. The answer
+** does NOT include space to hold the zTo name. */
+#define SZ_FKEY(N) (offsetof(FKey,aCol)+(N)*sizeof(struct sColMap))
+
/*
** SQLite supports many different ways to resolve a constraint
** error. ROLLBACK processing means that a constraint violation
@@ -18623,9 +19032,12 @@ struct KeyInfo {
u16 nAllField; /* Total columns, including key plus others */
sqlite3 *db; /* The database connection */
u8 *aSortFlags; /* Sort order for each column. */
- CollSeq *aColl[1]; /* Collating sequence for each term of the key */
+ CollSeq *aColl[FLEXARRAY]; /* Collating sequence for each term of the key */
};
+/* The size (in bytes) of a KeyInfo object with up to N fields */
+#define SZ_KEYINFO(N) (offsetof(KeyInfo,aColl) + (N)*sizeof(CollSeq*))
+
/*
** Allowed bit values for entries in the KeyInfo.aSortFlags[] array.
*/
@@ -18745,7 +19157,7 @@ struct 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 */
+ u16 nColumn; /* Nr columns in btree. Can be 2*Table.nCol */
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */
unsigned bUnordered:1; /* Use this index for == or IN queries only */
@@ -18754,9 +19166,9 @@ struct Index {
unsigned isCovering:1; /* True if this is a covering index */
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
- unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
+ unsigned bIdxRowid:1; /* One or more of the index keys is the ROWID */
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
unsigned bHasExpr:1; /* Index contains an expression, either a literal
** expression, or a reference to a VIRTUAL column */
@@ -18844,7 +19256,7 @@ struct AggInfo {
** from source tables rather than from accumulators */
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
** than the source table */
- u16 nSortingColumn; /* Number of columns in the sorting index */
+ u32 nSortingColumn; /* Number of columns in the sorting index */
int sortingIdx; /* Cursor number of the sorting index */
int sortingIdxPTab; /* Cursor number of pseudo-table */
int iFirstReg; /* First register in range for aCol[] and aFunc[] */
@@ -18853,8 +19265,8 @@ struct AggInfo {
Table *pTab; /* Source table */
Expr *pCExpr; /* The original expression */
int iTable; /* Cursor number of the source table */
- i16 iColumn; /* Column number within the source table */
- i16 iSorterColumn; /* Column number in the sorting index */
+ int iColumn; /* Column number within the source table */
+ int 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.
@@ -18884,9 +19296,15 @@ struct AggInfo {
** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg.
** The assert()s that are part of this macro verify that constraint.
*/
+#ifndef NDEBUG
#define AggInfoColumnReg(A,I) (assert((A)->iFirstReg),(A)->iFirstReg+(I))
#define AggInfoFuncReg(A,I) \
(assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I))
+#else
+#define AggInfoColumnReg(A,I) ((A)->iFirstReg+(I))
+#define AggInfoFuncReg(A,I) \
+ ((A)->iFirstReg+(A)->nColumn+(I))
+#endif
/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
@@ -19067,7 +19485,7 @@ struct Expr {
#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 */
+#define EP_SubtArg 0x80000000 /* Is argument to SQLITE_SUBTYPE function */
/* The EP_Propagate mask is a set of properties that automatically propagate
** upwards into parent nodes.
@@ -19077,10 +19495,10 @@ struct Expr {
/* Macros can be used to test, set, or clear bits in the
** Expr.flags field.
*/
-#define ExprHasProperty(E,P) (((E)->flags&(P))!=0)
-#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P))
-#define ExprSetProperty(E,P) (E)->flags|=(P)
-#define ExprClearProperty(E,P) (E)->flags&=~(P)
+#define ExprHasProperty(E,P) (((E)->flags&(u32)(P))!=0)
+#define ExprHasAllProperty(E,P) (((E)->flags&(u32)(P))==(u32)(P))
+#define ExprSetProperty(E,P) (E)->flags|=(u32)(P)
+#define ExprClearProperty(E,P) (E)->flags&=~(u32)(P)
#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue)
#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse)
#define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0)
@@ -19192,9 +19610,14 @@ struct ExprList {
int iConstExprReg; /* Register in which Expr value is cached. Used only
** by Parse.pConstExpr */
} u;
- } a[1]; /* One slot for each expression in the list */
+ } a[FLEXARRAY]; /* One slot for each expression in the list */
};
+/* The size (in bytes) of an ExprList object that is big enough to hold
+** as many as N expressions. */
+#define SZ_EXPRLIST(N) \
+ (offsetof(ExprList,a) + (N)*sizeof(struct ExprList_item))
+
/*
** Allowed values for Expr.a.eEName
*/
@@ -19220,16 +19643,14 @@ struct ExprList {
*/
struct IdList {
int nId; /* Number of identifiers on the list */
- u8 eU4; /* Which element of a.u4 is valid */
struct IdList_item {
char *zName; /* Name of the identifier */
- union {
- int idx; /* Index in some Table.aCol[] of a column named zName */
- Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */
- } u4;
- } a[1];
+ } a[FLEXARRAY];
};
+/* The size (in bytes) of an IdList object that can hold up to N IDs. */
+#define SZ_IDLIST(N) (offsetof(IdList,a)+(N)*sizeof(struct IdList_item))
+
/*
** Allowed values for IdList.eType, which determines which value of the a.u4
** is valid.
@@ -19239,6 +19660,16 @@ struct IdList {
#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
/*
+** Details of the implementation of a subquery.
+*/
+struct Subquery {
+ Select *pSelect; /* A SELECT statement used in place of a table name */
+ int addrFillSub; /* Address of subroutine to initialize a subquery */
+ int regReturn; /* Register holding return address of addrFillSub */
+ int regResult; /* Registers holding results of a co-routine */
+};
+
+/*
** The SrcItem object represents a single term in the FROM clause of a query.
** The SrcList object is mostly an array of SrcItems.
**
@@ -19250,29 +19681,40 @@ struct IdList {
** In the colUsed field, the high-order bit (bit 63) is set if the table
** contains more than 63 columns and the 64-th or later column is used.
**
-** Union member validity:
+** Aggressive use of "union" helps keep the size of the object small. This
+** has been shown to boost performance, in addition to saving memory.
+** Access to union elements is gated by the following rules which should
+** always be checked, either by an if-statement or by an assert().
**
-** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
-** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
+** Field Only access if this is true
+** --------------- -----------------------------------
+** u1.zIndexedBy fg.isIndexedBy
+** u1.pFuncArg fg.isTabFunc
** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
**
-** u2.pIBIndex fg.isIndexedBy && !fg.isCte
-** u2.pCteUse fg.isCte && !fg.isIndexedBy
+** u2.pIBIndex fg.isIndexedBy
+** u2.pCteUse fg.isCte
+**
+** u3.pOn !fg.isUsing
+** u3.pUsing fg.isUsing
+**
+** u4.zDatabase !fg.fixedSchema && !fg.isSubquery
+** u4.pSchema fg.fixedSchema
+** u4.pSubq fg.isSubquery
+**
+** See also the sqlite3SrcListDelete() routine for assert() statements that
+** check invariants on the fields of this object, especially the flags
+** inside the fg struct.
*/
struct SrcItem {
- Schema *pSchema; /* Schema to which this item is fixed */
- char *zDatabase; /* Name of database holding this table */
char *zName; /* Name of the table */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
- Table *pTab; /* An SQL table corresponding to zName */
- Select *pSelect; /* A SELECT statement used in place of a table name */
- int addrFillSub; /* Address of subroutine to manifest a subquery */
- int regReturn; /* Register holding return address of addrFillSub */
- int regResult; /* Registers holding results of a co-routine */
+ Table *pSTab; /* Table object for zName. Mnemonic: Srcitem-TABle */
struct {
u8 jointype; /* Type of join between this table and the previous */
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
+ unsigned isSubquery :1; /* True if this term is a subquery */
unsigned isTabFunc :1; /* True if table-valued-function syntax */
unsigned isCorrelated :1; /* True if sub-query is correlated */
unsigned isMaterialized:1; /* This is a materialized view */
@@ -19286,12 +19728,10 @@ struct SrcItem {
unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
unsigned rowidUsed :1; /* The ROWID of this table is referenced */
+ unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */
+ unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
- union {
- Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
- IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
- } u3;
Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
@@ -19302,6 +19742,15 @@ struct SrcItem {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
} u2;
+ union {
+ Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
+ IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
+ } u3;
+ union {
+ Schema *pSchema; /* Schema to which this item is fixed */
+ char *zDatabase; /* Name of database holding this table */
+ Subquery *pSubq; /* Description of a subquery */
+ } u4;
};
/*
@@ -19321,11 +19770,19 @@ struct OnOrUsing {
**
*/
struct SrcList {
- int nSrc; /* Number of tables or subqueries in the FROM clause */
- u32 nAlloc; /* Number of entries allocated in a[] below */
- SrcItem a[1]; /* One entry for each identifier on the list */
+ int nSrc; /* Number of tables or subqueries in the FROM clause */
+ u32 nAlloc; /* Number of entries allocated in a[] below */
+ SrcItem a[FLEXARRAY]; /* One entry for each identifier on the list */
};
+/* Size (in bytes) of a SrcList object that can hold as many as N
+** SrcItem objects. */
+#define SZ_SRCLIST(N) (offsetof(SrcList,a)+(N)*sizeof(SrcItem))
+
+/* Size (in bytes( of a SrcList object that holds 1 SrcItem. This is a
+** special case of SZ_SRCITEM(1) that comes up often. */
+#define SZ_SRCLIST_1 (offsetof(SrcList,a)+sizeof(SrcItem))
+
/*
** Permitted values of the SrcList.a.jointype field
*/
@@ -19433,7 +19890,7 @@ struct NameContext {
#define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */
#define NC_UBaseReg 0x000400 /* True if uNC.iBaseReg is used */
#define NC_MinMaxAgg 0x001000 /* min/max aggregates seen. See note above */
-#define NC_Complex 0x002000 /* True if a function or subquery seen */
+/* 0x002000 // available for reuse */
#define NC_AllowWin 0x004000 /* Window functions are allowed here */
#define NC_HasWin 0x008000 /* One or more window functions seen */
#define NC_IsDDL 0x010000 /* Resolving names in a CREATE statement */
@@ -19561,8 +20018,10 @@ struct Select {
#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
#define SF_Correlated 0x20000000 /* True if references the outer context */
-/* True if S exists and has SF_NestedFrom */
-#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
+/* True if SrcItem X is a subquery that has SF_NestedFrom */
+#define IsNestedFrom(X) \
+ ((X)->fg.isSubquery && \
+ ((X)->u4.pSubq->pSelect->selFlags&SF_NestedFrom)!=0)
/*
** The results of a SELECT can be distributed in several ways, as defined
@@ -19592,7 +20051,11 @@ struct Select {
** SRT_Set The result must be a single column. Store each
** row of result as the key in table pDest->iSDParm.
** Apply the affinity pDest->affSdst before storing
-** results. Used to implement "IN (SELECT ...)".
+** results. if pDest->iSDParm2 is positive, then it is
+** a register holding a Bloom filter for the IN operator
+** that should be populated in addition to the
+** pDest->iSDParm table. This SRT is used to
+** implement "IN (SELECT ...)".
**
** SRT_EphemTab Create an temporary table pDest->iSDParm and store
** the result there. The cursor is left open after
@@ -19788,24 +20251,32 @@ struct Parse {
char *zErrMsg; /* An error message */
Vdbe *pVdbe; /* An engine for executing database bytecode */
int rc; /* Return code from execution */
- u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
- u8 checkSchema; /* Causes schema cookie check after an error */
+ LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u8 nested; /* Number of nested calls to the parser/code generator */
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
u8 mayAbort; /* True if statement may throw an ABORT exception */
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
- u8 okConstFactor; /* OK to factor out constants */
u8 disableLookaside; /* Number of times lookaside has been disabled */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
- u8 bHasWith; /* True if statement contains WITH */
+ u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */
+ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
+ u8 bReturning; /* Coding a RETURNING trigger */
+ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
+ u8 disableTriggers; /* True to disable triggers */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
#endif
#ifdef SQLITE_DEBUG
u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */
+ u8 isCreate; /* CREATE TABLE, INDEX, or VIEW (but not TRIGGER)
+ ** and ALTER TABLE ADD COLUMN. */
#endif
+ bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */
+ bft bHasWith :1; /* True if statement contains WITH */
+ bft okConstFactor :1; /* OK to factor out constants */
+ bft checkSchema :1; /* Causes schema cookie check after an error */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
@@ -19820,12 +20291,9 @@ struct Parse {
ExprList *pConstExpr;/* Constant expressions */
IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */
- Token constraintName;/* Name of the constraint currently being parsed */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
- 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 */
+ int nMaxArg; /* Max args to xUpdate and xFilter vtab methods */
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
@@ -19839,17 +20307,6 @@ struct Parse {
Table *pTriggerTab; /* Table triggers are being coded for */
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */
- union {
- int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
- Returning *pReturning; /* The RETURNING clause */
- } u1;
- u32 oldmask; /* Mask of old.* columns referenced */
- u32 newmask; /* Mask of new.* columns referenced */
- LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
- u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
- u8 bReturning; /* Coding a RETURNING trigger */
- u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
- u8 disableTriggers; /* True to disable triggers */
/**************************************************************************
** Fields above must be initialized to zero. The fields that follow,
@@ -19861,6 +20318,19 @@ struct Parse {
int aTempReg[8]; /* Holding area for temporary registers */
Parse *pOuterParse; /* Outer Parse object when nested */
Token sNameToken; /* Token with unqualified schema object name */
+ u32 oldmask; /* Mask of old.* columns referenced */
+ u32 newmask; /* Mask of new.* columns referenced */
+ union {
+ struct { /* These fields available when isCreate is true */
+ int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
+ int regRowid; /* Register holding rowid of CREATE TABLE entry */
+ int regRoot; /* Register holding root page for new objects */
+ Token constraintName; /* Name of the constraint currently being parsed */
+ } cr;
+ struct { /* These fields available to all other statements */
+ Returning *pReturning; /* The RETURNING clause */
+ } d;
+ } u1;
/************************************************************************
** Above is constant between recursions. Below is reset before and after
@@ -19878,9 +20348,7 @@ struct Parse {
int nVtabLock; /* Number of virtual tables to lock */
#endif
int nHeight; /* Expression tree height of current sub-select */
-#ifndef SQLITE_OMIT_EXPLAIN
int addrExplain; /* Address of current OP_Explain opcode */
-#endif
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 */
@@ -20095,7 +20563,7 @@ struct Returning {
};
/*
-** An objected used to accumulate the text of a string where we
+** An object used to accumulate the text of a string where we
** do not necessarily know how big the string will be in the end.
*/
struct sqlite3_str {
@@ -20109,7 +20577,7 @@ struct sqlite3_str {
};
#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 */
+#define SQLITE_PRINTF_MALLOCED 0x04 /* True if zText is allocated space */
#define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0)
@@ -20187,7 +20655,6 @@ struct Sqlite3Config {
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 */
- u8 bUseLongDouble; /* Make use of long double */
#ifdef SQLITE_DEBUG
u8 bJsonSelfcheck; /* Double-check JSON parsing */
#endif
@@ -20379,9 +20846,13 @@ struct With {
int nCte; /* Number of CTEs in the WITH clause */
int bView; /* Belongs to the outermost Select of a view */
With *pOuter; /* Containing WITH clause, or NULL */
- Cte a[1]; /* For each CTE in the WITH clause.... */
+ Cte a[FLEXARRAY]; /* For each CTE in the WITH clause.... */
};
+/* The size (in bytes) of a With object that can hold as many
+** as N different CTEs. */
+#define SZ_WITH(N) (offsetof(With,a) + (N)*sizeof(Cte))
+
/*
** The Cte object is not guaranteed to persist for the entire duration
** of code generation. (The query flattener or other parser tree
@@ -20410,9 +20881,13 @@ struct DbClientData {
DbClientData *pNext; /* Next in a linked list */
void *pData; /* The data */
void (*xDestructor)(void*); /* Destructor. Might be NULL */
- char zName[1]; /* Name of this client data. MUST BE LAST */
+ char zName[FLEXARRAY]; /* Name of this client data. MUST BE LAST */
};
+/* The size (in bytes) of a DbClientData object that can has a name
+** that is N bytes long, including the zero-terminator. */
+#define SZ_DBCLIENTDATA(N) (offsetof(DbClientData,zName)+(N))
+
#ifdef SQLITE_DEBUG
/*
** An instance of the TreeView object is used for printing the content of
@@ -20563,15 +21038,6 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
#endif
/*
-** The ctype.h header is needed for non-ASCII systems. It is also
-** needed by FTS3 when FTS3 is included in the amalgamation.
-*/
-#if !defined(SQLITE_ASCII) || \
- (defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_AMALGAMATION))
-# include <ctype.h>
-#endif
-
-/*
** The following macros mimic the standard library functions toupper(),
** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The
** sqlite versions only work for ASCII characters, regardless of locale.
@@ -20864,7 +21330,7 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(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 sqlite3TableColumnToIndex(Index*, i16);
+SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index*, int);
#ifdef SQLITE_OMIT_GENERATED_COLUMNS
# define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */
# define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */
@@ -20949,6 +21415,9 @@ SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*);
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 void sqlite3SubqueryDelete(sqlite3*,Subquery*);
+SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3*,SrcItem*);
+SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery(Parse*, SrcItem*, Select*, int);
SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
Token*, Select*, OnOrUsing*);
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
@@ -20959,7 +21428,7 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*);
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*);
SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*);
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*);
-SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
+SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**);
SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
Expr*, int, int, u8);
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
@@ -20998,6 +21467,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
+SQLITE_PRIVATE void sqlite3ExprToRegister(Expr *pExpr, int iReg);
SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int);
@@ -21060,7 +21530,7 @@ SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int,i
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
#endif
-SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*);
+SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*, Parse*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int sqlite3IsRowid(const char*);
@@ -21094,7 +21564,8 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int);
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 sqlite3QuoteValue(StrAccum*,sqlite3_value*);
+SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*,int);
+SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char*, u32);
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void);
@@ -21188,7 +21659,7 @@ 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);
+SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nByte, int nChar);
#endif
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
@@ -21959,6 +22430,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_BUG_COMPATIBLE_20160819
"BUG_COMPATIBLE_20160819",
#endif
+#ifdef SQLITE_BUG_COMPATIBLE_20250510
+ "BUG_COMPATIBLE_20250510",
+#endif
#ifdef SQLITE_CASE_SENSITIVE_LIKE
"CASE_SENSITIVE_LIKE",
#endif
@@ -22174,6 +22648,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
"ENABLE_OFFSET_SQL_FUNC",
#endif
+#ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES
+ "ENABLE_ORDERED_SET_AGGREGATES",
+#endif
#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
"ENABLE_OVERSIZE_CELL_CHECK",
#endif
@@ -22192,6 +22669,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_ENABLE_SESSION
"ENABLE_SESSION",
#endif
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ "ENABLE_SETLK_TIMEOUT",
+#endif
#ifdef SQLITE_ENABLE_SNAPSHOT
"ENABLE_SNAPSHOT",
#endif
@@ -22246,6 +22726,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_EXTRA_INIT
"EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT),
#endif
+#ifdef SQLITE_EXTRA_INIT_MUTEXED
+ "EXTRA_INIT_MUTEXED=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT_MUTEXED),
+#endif
#ifdef SQLITE_EXTRA_SHUTDOWN
"EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN),
#endif
@@ -22643,9 +23126,6 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_UNTESTABLE
"UNTESTABLE",
#endif
-#ifdef SQLITE_USER_AUTHENTICATION
- "USER_AUTHENTICATION",
-#endif
#ifdef SQLITE_USE_ALLOCA
"USE_ALLOCA",
#endif
@@ -22921,7 +23401,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
0, /* bSmallMalloc */
1, /* bExtraSchemaChecks */
- sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */
#ifdef SQLITE_DEBUG
0, /* bJsonSelfcheck */
#endif
@@ -23234,12 +23713,19 @@ struct VdbeCursor {
#endif
VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */
- /* 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 */
+ /* Space is allocated for aType to hold at least 2*nField+1 entries:
+ ** nField slots for aType[] and nField+1 array slots for aOffset[] */
+ u32 aType[FLEXARRAY]; /* Type values record decode. MUST BE LAST */
};
+/*
+** The size (in bytes) of a VdbeCursor object that has an nField value of N
+** or less. The value of SZ_VDBECURSOR(n) is guaranteed to be a multiple
+** of 8.
+*/
+#define SZ_VDBECURSOR(N) \
+ (ROUND8(offsetof(VdbeCursor,aType)) + ((N)+1)*sizeof(u64))
+
/* Return true if P is a null-only cursor
*/
#define IsNullCursor(P) \
@@ -23345,6 +23831,7 @@ struct sqlite3_value {
#ifdef SQLITE_DEBUG
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
u16 mScopyFlags; /* flags value immediately after the shallow copy */
+ u8 bScopy; /* The pScopyFrom of some other Mem *might* point here */
#endif
};
@@ -23494,14 +23981,17 @@ struct sqlite3_context {
int isError; /* Error code returned by the function. */
u8 enc; /* Encoding to use for results */
u8 skipFlag; /* Skip accumulator loading if true */
- u8 argc; /* Number of arguments */
- sqlite3_value *argv[1]; /* Argument set */
+ u16 argc; /* Number of arguments */
+ sqlite3_value *argv[FLEXARRAY]; /* Argument set */
};
-/* A bitfield type for use inside of structures. Always follow with :N where
-** N is the number of bits.
+/*
+** The size (in bytes) of an sqlite3_context object that holds N
+** argv[] arguments.
*/
-typedef unsigned bft; /* Bit Field Type */
+#define SZ_CONTEXT(N) \
+ (offsetof(sqlite3_context,argv)+(N)*sizeof(sqlite3_value*))
+
/* The ScanStatus object holds a single value for the
** sqlite3_stmt_scanstatus() interface.
@@ -23562,7 +24052,7 @@ struct Vdbe {
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 */
+ Mem **apArg; /* Arguments xUpdate and xFilter vtab methods */
VdbeCursor **apCsr; /* One element of this array for each open cursor */
Mem *aVar; /* Values for the OP_Variable opcode. */
@@ -23582,6 +24072,7 @@ struct Vdbe {
#ifdef SQLITE_DEBUG
int rcApp; /* errcode set by sqlite3_result_error_code() */
u32 nWrite; /* Number of write operations that have occurred */
+ int napArg; /* Size of the apArg[] array */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u16 nResAlloc; /* Column slots allocated to aColName[] */
@@ -23634,16 +24125,19 @@ struct PreUpdate {
VdbeCursor *pCsr; /* Cursor to read old values from */
int op; /* One of SQLITE_INSERT, UPDATE, DELETE */
u8 *aRecord; /* old.* database record */
- KeyInfo keyinfo;
+ KeyInfo *pKeyinfo; /* Key information */
UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */
UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
int iNewReg; /* Register for new.* values */
int iBlobWrite; /* Value returned by preupdate_blobwrite() */
i64 iKey1; /* First key value passed to hook */
i64 iKey2; /* Second key value passed to hook */
+ Mem oldipk; /* Memory cell holding "old" IPK value */
Mem *aNew; /* Array of new.* values */
Table *pTab; /* Schema object being updated */
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
+ sqlite3_value **apDflt; /* Array of default values, if required */
+ u8 keyinfoSpace[SZ_KEYINFO(0)]; /* Space to hold pKeyinfo[0] content */
};
/*
@@ -24010,8 +24504,9 @@ SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
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);
+ assert( db->lookaside.nSlot >= nInit+nFree );
+ if( pHighwater ) *pHighwater = (int)(db->lookaside.nSlot - nInit);
+ return (int)(db->lookaside.nSlot - (nInit+nFree));
}
/*
@@ -24064,7 +24559,7 @@ SQLITE_API int sqlite3_db_status(
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
*pCurrent = 0;
- *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
+ *pHighwater = (int)db->lookaside.anStat[op-SQLITE_DBSTATUS_LOOKASIDE_HIT];
if( resetFlag ){
db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
}
@@ -24441,6 +24936,9 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
zDate++;
}
ms /= rScale;
+ /* Truncate to avoid problems with sub-milliseconds
+ ** rounding. https://sqlite.org/forum/forumpost/766a2c9231 */
+ if( ms>0.999 ) ms = 0.999;
}
}else{
s = 0;
@@ -24490,8 +24988,8 @@ static void computeJD(DateTime *p){
Y--;
M += 12;
}
- A = Y/100;
- B = 2 - A + (A/4);
+ A = (Y+4800)/100;
+ B = 38 - A + (A/4);
X1 = 36525*(Y+4716)/100;
X2 = 306001*(M+1)/10000;
p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
@@ -24675,7 +25173,7 @@ static int validJulianDay(sqlite3_int64 iJD){
** Compute the Year, Month, and Day from the julian day number.
*/
static void computeYMD(DateTime *p){
- int Z, A, B, C, D, E, X1;
+ int Z, alpha, A, B, C, D, E, X1;
if( p->validYMD ) return;
if( !p->validJD ){
p->Y = 2000;
@@ -24686,8 +25184,8 @@ static void computeYMD(DateTime *p){
return;
}else{
Z = (int)((p->iJD + 43200000)/86400000);
- A = (int)((Z - 1867216.25)/36524.25);
- A = Z + 1 + A - (A/4);
+ alpha = (int)((Z + 32044.75)/36524.25) - 52;
+ A = Z + 1 + alpha - ((alpha+100)/4) + 25;
B = A + 1524;
C = (int)((B - 122.1)/365.25);
D = (36525*(C&32767))/100;
@@ -24886,8 +25384,8 @@ static const struct {
/* 1 */ { 6, "minute", 7.7379e+12, 60.0 },
/* 2 */ { 4, "hour", 1.2897e+11, 3600.0 },
/* 3 */ { 3, "day", 5373485.0, 86400.0 },
- /* 4 */ { 5, "month", 176546.0, 30.0*86400.0 },
- /* 5 */ { 4, "year", 14713.0, 365.0*86400.0 },
+ /* 4 */ { 5, "month", 176546.0, 2592000.0 },
+ /* 5 */ { 4, "year", 14713.0, 31536000.0 },
};
/*
@@ -25573,7 +26071,7 @@ static int daysAfterMonday(DateTime *pDate){
** In other words, return the day of the week according
** to this code:
**
-** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday
+** 0=Sunday, 1=Monday, 2=Tuesday, ..., 6=Saturday
*/
static int daysAfterSunday(DateTime *pDate){
assert( pDate->validJD );
@@ -25648,7 +26146,7 @@ static void strftimeFunc(
}
case 'f': { /* Fractional seconds. (Non-standard) */
double s = x.s;
- if( s>59.999 ) s = 59.999;
+ if( NEVER(s>59.999) ) s = 59.999;
sqlite3_str_appendf(&sRes, "%06.3f", s);
break;
}
@@ -29089,16 +29587,29 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
+**
+** Because these routines raise false-positive alerts in TSAN, disable
+** them (make them always return 1) when compiling with TSAN.
*/
SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
+# if defined(__has_feature)
+# if __has_feature(thread_sanitizer)
+ p = 0;
+# endif
+# endif
assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
}
SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
+# if defined(__has_feature)
+# if __has_feature(thread_sanitizer)
+ p = 0;
+# endif
+# endif
assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
}
-#endif
+#endif /* NDEBUG */
#endif /* !defined(SQLITE_MUTEX_OMIT) */
@@ -29769,6 +30280,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
#ifdef __CYGWIN__
# include <sys/cygwin.h>
+# include <sys/stat.h> /* amalgamator: dontcache */
+# include <unistd.h> /* amalgamator: dontcache */
# include <errno.h> /* amalgamator: dontcache */
#endif
@@ -31163,17 +31676,17 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
#define etPERCENT 7 /* Percent symbol. %% */
#define etCHARX 8 /* Characters. %c */
/* The rest are extensions, not normally found in printf() */
-#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */
-#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
- NULL pointers replaced by SQL NULL. %Q */
-#define etTOKEN 11 /* a pointer to a Token structure */
-#define etSRCITEM 12 /* a pointer to a SrcItem */
-#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 etESCAPE_q 9 /* Strings with '\'' doubled. %q */
+#define etESCAPE_Q 10 /* Strings with '\'' doubled and enclosed in '',
+ NULL pointers replaced by SQL NULL. %Q */
+#define etTOKEN 11 /* a pointer to a Token structure */
+#define etSRCITEM 12 /* a pointer to a SrcItem */
+#define etPOINTER 13 /* The %p conversion */
+#define etESCAPE_w 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 17 /* Any unrecognized conversion type */
+#define etINVALID 17 /* Any unrecognized conversion type */
/*
@@ -31212,9 +31725,9 @@ static const et_info fmtinfo[] = {
{ 's', 0, 4, etSTRING, 0, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 },
{ 'z', 0, 4, etDYNSTRING, 0, 0 },
- { 'q', 0, 4, etSQLESCAPE, 0, 0 },
- { 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
- { 'w', 0, 4, etSQLESCAPE3, 0, 0 },
+ { 'q', 0, 4, etESCAPE_q, 0, 0 },
+ { 'Q', 0, 4, etESCAPE_Q, 0, 0 },
+ { 'w', 0, 4, etESCAPE_w, 0, 0 },
{ 'c', 0, 0, etCHARX, 0, 0 },
{ 'o', 8, 0, etRADIX, 0, 2 },
{ 'u', 10, 0, etDECIMAL, 0, 0 },
@@ -31811,25 +32324,7 @@ SQLITE_API void sqlite3_str_vappendf(
}
}else{
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;
- }
+ length = sqlite3AppendOneUtf8Character(buf, ch);
}
if( precision>1 ){
i64 nPrior = 1;
@@ -31909,22 +32404,31 @@ SQLITE_API void sqlite3_str_vappendf(
while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++;
}
break;
- case etSQLESCAPE: /* %q: Escape ' characters */
- case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */
- case etSQLESCAPE3: { /* %w: Escape " characters */
+ case etESCAPE_q: /* %q: Escape ' characters */
+ case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */
+ case etESCAPE_w: { /* %w: Escape " characters */
i64 i, j, k, n;
- int needQuote, isnull;
+ int needQuote = 0;
char ch;
- char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
char *escarg;
+ char q;
if( bArgList ){
escarg = getTextArg(pArgList);
}else{
escarg = va_arg(ap,char*);
}
- isnull = escarg==0;
- if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
+ if( escarg==0 ){
+ escarg = (xtype==etESCAPE_Q ? "NULL" : "(NULL)");
+ }else if( xtype==etESCAPE_Q ){
+ needQuote = 1;
+ }
+ if( xtype==etESCAPE_w ){
+ q = '"';
+ flag_alternateform = 0;
+ }else{
+ q = '\'';
+ }
/* 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
@@ -31937,7 +32441,30 @@ SQLITE_API void sqlite3_str_vappendf(
while( (escarg[i+1]&0xc0)==0x80 ){ i++; }
}
}
- needQuote = !isnull && xtype==etSQLESCAPE2;
+ if( flag_alternateform ){
+ /* For %#q, do unistr()-style backslash escapes for
+ ** all control characters, and for backslash itself.
+ ** For %#Q, do the same but only if there is at least
+ ** one control character. */
+ u32 nBack = 0;
+ u32 nCtrl = 0;
+ for(k=0; k<i; k++){
+ if( escarg[k]=='\\' ){
+ nBack++;
+ }else if( ((u8*)escarg)[k]<=0x1f ){
+ nCtrl++;
+ }
+ }
+ if( nCtrl || xtype==etESCAPE_q ){
+ n += nBack + 5*nCtrl;
+ if( xtype==etESCAPE_Q ){
+ n += 10;
+ needQuote = 2;
+ }
+ }else{
+ flag_alternateform = 0;
+ }
+ }
n += i + 3;
if( n>etBUFSIZE ){
bufpt = zExtra = printfTempBuf(pAccum, n);
@@ -31946,13 +32473,41 @@ SQLITE_API void sqlite3_str_vappendf(
bufpt = buf;
}
j = 0;
- if( needQuote ) bufpt[j++] = q;
+ if( needQuote ){
+ if( needQuote==2 ){
+ memcpy(&bufpt[j], "unistr('", 8);
+ j += 8;
+ }else{
+ bufpt[j++] = '\'';
+ }
+ }
k = i;
- for(i=0; i<k; i++){
- bufpt[j++] = ch = escarg[i];
- if( ch==q ) bufpt[j++] = ch;
+ if( flag_alternateform ){
+ for(i=0; i<k; i++){
+ bufpt[j++] = ch = escarg[i];
+ if( ch==q ){
+ bufpt[j++] = ch;
+ }else if( ch=='\\' ){
+ bufpt[j++] = '\\';
+ }else if( ((unsigned char)ch)<=0x1f ){
+ bufpt[j-1] = '\\';
+ bufpt[j++] = 'u';
+ bufpt[j++] = '0';
+ bufpt[j++] = '0';
+ bufpt[j++] = ch>=0x10 ? '1' : '0';
+ bufpt[j++] = "0123456789abcdef"[ch&0xf];
+ }
+ }
+ }else{
+ for(i=0; i<k; i++){
+ bufpt[j++] = ch = escarg[i];
+ if( ch==q ) bufpt[j++] = ch;
+ }
+ }
+ if( needQuote ){
+ bufpt[j++] = '\'';
+ if( needQuote==2 ) bufpt[j++] = ')';
}
- if( needQuote ) bufpt[j++] = q;
bufpt[j] = 0;
length = j;
goto adjust_width_for_utf8;
@@ -31986,16 +32541,19 @@ SQLITE_API void sqlite3_str_vappendf(
if( pItem->zAlias && !flag_altform2 ){
sqlite3_str_appendall(pAccum, pItem->zAlias);
}else if( pItem->zName ){
- if( pItem->zDatabase ){
- sqlite3_str_appendall(pAccum, pItem->zDatabase);
+ if( pItem->fg.fixedSchema==0
+ && pItem->fg.isSubquery==0
+ && pItem->u4.zDatabase!=0
+ ){
+ sqlite3_str_appendall(pAccum, pItem->u4.zDatabase);
sqlite3_str_append(pAccum, ".", 1);
}
sqlite3_str_appendall(pAccum, pItem->zName);
}else if( pItem->zAlias ){
sqlite3_str_appendall(pAccum, pItem->zAlias);
- }else{
- Select *pSel = pItem->pSelect;
- assert( pSel!=0 ); /* Because of tag-20240424-1 */
+ }else if( ALWAYS(pItem->fg.isSubquery) ){/* Because of tag-20240424-1 */
+ Select *pSel = pItem->u4.pSubq->pSelect;
+ assert( pSel!=0 );
if( pSel->selFlags & SF_NestedFrom ){
sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
}else if( pSel->selFlags & SF_MultiValue ){
@@ -32073,6 +32631,7 @@ SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExp
pExpr = pExpr->pLeft;
}
if( pExpr==0 ) return;
+ if( ExprHasProperty(pExpr, EP_FromDDL) ) return;
db->errByteOffset = pExpr->w.iOfst;
}
@@ -32191,7 +32750,7 @@ SQLITE_API void sqlite3_str_appendall(sqlite3_str *p, const char *z){
static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
char *zText;
assert( p->mxAlloc>0 && !isMalloced(p) );
- zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
+ zText = sqlite3DbMallocRaw(p->db, 1+(u64)p->nChar );
if( zText ){
memcpy(zText, p->zText, p->nChar+1);
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
@@ -32436,6 +32995,15 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
return zBuf;
}
+/* Maximum size of an sqlite3_log() message. */
+#if defined(SQLITE_MAX_LOG_MESSAGE)
+ /* Leave the definition as supplied */
+#elif SQLITE_PRINT_BUF_SIZE*10>10000
+# define SQLITE_MAX_LOG_MESSAGE 10000
+#else
+# define SQLITE_MAX_LOG_MESSAGE (SQLITE_PRINT_BUF_SIZE*10)
+#endif
+
/*
** This is the routine that actually formats the sqlite3_log() message.
** We house it in a separate routine from sqlite3_log() to avoid using
@@ -32452,7 +33020,7 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
*/
static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
StrAccum acc; /* String accumulator */
- char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
+ char zMsg[SQLITE_MAX_LOG_MESSAGE]; /* Complete log message */
sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
sqlite3_str_vappendf(&acc, zFormat, ap);
@@ -32777,9 +33345,9 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc)
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
x.printfFlags |= SQLITE_PRINTF_INTERNAL;
sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
- if( pItem->pTab ){
+ if( pItem->pSTab ){
sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s",
- pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab,
+ pItem->pSTab->zName, pItem->pSTab->nCol, pItem->pSTab,
pItem->colUsed,
pItem->fg.rowidUsed ? "+rowid" : "");
}
@@ -32799,10 +33367,13 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc)
sqlite3_str_appendf(&x, " DDL");
}
if( pItem->fg.isCte ){
- sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse);
+ static const char *aMat[] = {",MAT", "", ",NO-MAT"};
+ sqlite3_str_appendf(&x, " CteUse=%d%s",
+ pItem->u2.pCteUse->nUse,
+ aMat[pItem->u2.pCteUse->eM10d]);
}
if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){
- sqlite3_str_appendf(&x, " ON");
+ sqlite3_str_appendf(&x, " isOn");
}
if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc");
if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated");
@@ -32810,25 +33381,27 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc)
if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine");
if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte");
if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom");
+ if( pItem->fg.fixedSchema ) sqlite3_str_appendf(&x, " fixedSchema");
+ if( pItem->fg.hadSchema ) sqlite3_str_appendf(&x, " hadSchema");
+ if( pItem->fg.isSubquery ) sqlite3_str_appendf(&x, " isSubquery");
sqlite3StrAccumFinish(&x);
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
n = 0;
- if( pItem->pSelect ) n++;
+ if( pItem->fg.isSubquery ) n++;
if( pItem->fg.isTabFunc ) n++;
if( pItem->fg.isUsing ) n++;
if( pItem->fg.isUsing ){
sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
}
- if( pItem->pSelect ){
- sqlite3TreeViewPush(&pView, i+1<pSrc->nSrc);
- if( pItem->pTab ){
- Table *pTab = pItem->pTab;
+ if( pItem->fg.isSubquery ){
+ assert( n==1 );
+ if( pItem->pSTab ){
+ Table *pTab = pItem->pSTab;
sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
}
- assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
- sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0);
- sqlite3TreeViewPop(&pView);
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
+ sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0);
}
if( pItem->fg.isTabFunc ){
sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
@@ -32870,7 +33443,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
n = 1000;
}else{
n = 0;
- if( p->pSrc && p->pSrc->nSrc ) n++;
+ if( p->pSrc && p->pSrc->nSrc && p->pSrc->nAlloc ) n++;
if( p->pWhere ) n++;
if( p->pGroupBy ) n++;
if( p->pHaving ) n++;
@@ -32896,7 +33469,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
sqlite3TreeViewPop(&pView);
}
#endif
- if( p->pSrc && p->pSrc->nSrc ){
+ if( p->pSrc && p->pSrc->nSrc && p->pSrc->nAlloc ){
sqlite3TreeViewPush(&pView, (n--)>0);
sqlite3TreeViewLine(pView, "FROM");
sqlite3TreeViewSrcList(pView, p->pSrc);
@@ -33404,7 +33977,8 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
case OE_Ignore: zType = "ignore"; break;
}
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "RAISE %s", zType);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
break;
}
#endif
@@ -33484,9 +34058,10 @@ SQLITE_PRIVATE void sqlite3TreeViewBareExprList(
sqlite3TreeViewLine(pView, "%s", zLabel);
for(i=0; i<pList->nExpr; i++){
int j = pList->a[i].u.x.iOrderByCol;
+ u8 sortFlags = pList->a[i].fg.sortFlags;
char *zName = pList->a[i].zEName;
int moreToFollow = i<pList->nExpr - 1;
- if( j || zName ){
+ if( j || zName || sortFlags ){
sqlite3TreeViewPush(&pView, moreToFollow);
moreToFollow = 0;
sqlite3TreeViewLine(pView, 0);
@@ -33507,13 +34082,18 @@ SQLITE_PRIVATE void sqlite3TreeViewBareExprList(
}
}
if( j ){
- fprintf(stdout, "iOrderByCol=%d", j);
+ fprintf(stdout, "iOrderByCol=%d ", j);
+ }
+ if( sortFlags & KEYINFO_ORDER_DESC ){
+ fprintf(stdout, "DESC ");
+ }else if( sortFlags & KEYINFO_ORDER_BIGNULL ){
+ fprintf(stdout, "NULLS-LAST");
}
fprintf(stdout, "\n");
fflush(stdout);
}
sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow);
- if( j || zName ){
+ if( j || zName || sortFlags ){
sqlite3TreeViewPop(&pView);
}
}
@@ -33550,21 +34130,7 @@ SQLITE_PRIVATE void sqlite3TreeViewBareIdList(
if( zName==0 ) zName = "(null)";
sqlite3TreeViewPush(&pView, moreToFollow);
sqlite3TreeViewLine(pView, 0);
- if( pList->eU4==EU4_NONE ){
- fprintf(stdout, "%s\n", zName);
- }else if( pList->eU4==EU4_IDX ){
- fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx);
- }else{
- assert( pList->eU4==EU4_EXPR );
- if( pList->a[i].u4.pExpr==0 ){
- fprintf(stdout, "%s (pExpr=NULL)\n", zName);
- }else{
- fprintf(stdout, "%s\n", zName);
- sqlite3TreeViewPush(&pView, i<pList->nId-1);
- sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0);
- sqlite3TreeViewPop(&pView);
- }
- }
+ fprintf(stdout, "%s\n", zName);
sqlite3TreeViewPop(&pView);
}
}
@@ -33874,6 +34440,10 @@ SQLITE_PRIVATE void sqlite3TreeViewTrigger(
** accessible to the debugging, and to avoid warnings about unused
** functions. But these routines only exist in debugging builds, so they
** do not contaminate the interface.
+**
+** See Also:
+**
+** sqlite3ShowWhereTerm() in where.c
*/
SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); }
SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);}
@@ -34446,6 +35016,35 @@ static const unsigned char sqlite3Utf8Trans1[] = {
}
/*
+** Write a single UTF8 character whose value is v into the
+** buffer starting at zOut. zOut must be sized to hold at
+** least four bytes. Return the number of bytes needed
+** to encode the new character.
+*/
+SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char *zOut, u32 v){
+ if( v<0x00080 ){
+ zOut[0] = (u8)(v & 0xff);
+ return 1;
+ }
+ if( v<0x00800 ){
+ zOut[0] = 0xc0 + (u8)((v>>6) & 0x1f);
+ zOut[1] = 0x80 + (u8)(v & 0x3f);
+ return 2;
+ }
+ if( v<0x10000 ){
+ zOut[0] = 0xe0 + (u8)((v>>12) & 0x0f);
+ zOut[1] = 0x80 + (u8)((v>>6) & 0x3f);
+ zOut[2] = 0x80 + (u8)(v & 0x3f);
+ return 3;
+ }
+ zOut[0] = 0xf0 + (u8)((v>>18) & 0x07);
+ zOut[1] = 0x80 + (u8)((v>>12) & 0x3f);
+ zOut[2] = 0x80 + (u8)((v>>6) & 0x3f);
+ zOut[3] = 0x80 + (u8)(v & 0x3f);
+ return 4;
+}
+
+/*
** Translate a single UTF-8 character. Return the unicode value.
**
** During translation, assume that the byte that zTerm points
@@ -34476,7 +35075,7 @@ static const unsigned char sqlite3Utf8Trans1[] = {
c = *(zIn++); \
if( c>=0xc0 ){ \
c = sqlite3Utf8Trans1[c-0xc0]; \
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
+ while( zIn<zTerm && (*zIn & 0xc0)==0x80 ){ \
c = (c<<6) + (0x3f & *(zIn++)); \
} \
if( c<0x80 \
@@ -34854,20 +35453,22 @@ SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 e
}
/*
-** zIn is a UTF-16 encoded unicode string at least nChar characters long.
+** zIn is a UTF-16 encoded unicode string at least nByte bytes long.
** Return the number of bytes in the first nChar unicode characters
-** in pZ. nChar must be non-negative.
+** in pZ. nChar must be non-negative. Surrogate pairs count as a single
+** character.
*/
-SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){
+SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nByte, int nChar){
int c;
unsigned char const *z = zIn;
+ unsigned char const *zEnd = &z[nByte-1];
int n = 0;
if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
- while( n<nChar ){
+ while( n<nChar && z<=zEnd ){
c = z[0];
z += 2;
- if( c>=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
+ if( c>=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
n++;
}
return (int)(z-(unsigned char const *)zIn)
@@ -35448,6 +36049,8 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
int eValid = 1; /* True exponent is either not used or is well-formed */
int nDigit = 0; /* Number of digits processed */
int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
+ u64 s2; /* round-tripped significand */
+ double rr[2];
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
*pResult = 0.0; /* Default return value, in case of an error */
@@ -35550,7 +36153,7 @@ do_atof_calc:
e = (e*esign) + d;
/* Try to adjust the exponent to make it smaller */
- while( e>0 && s<(LARGEST_UINT64/10) ){
+ while( e>0 && s<((LARGEST_UINT64-0x7ff)/10) ){
s *= 10;
e--;
}
@@ -35559,68 +36162,52 @@ do_atof_calc:
e++;
}
- if( e==0 ){
- *pResult = s;
- }else if( sqlite3Config.bUseLongDouble ){
- LONGDOUBLE_TYPE r = (LONGDOUBLE_TYPE)s;
- if( e>0 ){
- while( e>=100 ){ e-=100; r *= 1.0e+100L; }
- while( e>=10 ){ e-=10; r *= 1.0e+10L; }
- while( e>=1 ){ e-=1; r *= 1.0e+01L; }
- }else{
- while( e<=-100 ){ e+=100; r *= 1.0e-100L; }
- while( e<=-10 ){ e+=10; r *= 1.0e-10L; }
- while( e<=-1 ){ e+=1; r *= 1.0e-01L; }
- }
- assert( r>=0.0 );
- if( r>+1.7976931348623157081452742373e+308L ){
-#ifdef INFINITY
- *pResult = +INFINITY;
-#else
- *pResult = 1.0e308*10.0;
+ rr[0] = (double)s;
+ assert( sizeof(s2)==sizeof(rr[0]) );
+#ifdef SQLITE_DEBUG
+ rr[1] = 18446744073709549568.0;
+ memcpy(&s2, &rr[1], sizeof(s2));
+ assert( s2==0x43efffffffffffffLL );
#endif
- }else{
- *pResult = (double)r;
- }
- }else{
- double rr[2];
- u64 s2;
- rr[0] = (double)s;
+ /* Largest double that can be safely converted to u64
+ ** vvvvvvvvvvvvvvvvvvvvvv */
+ if( rr[0]<=18446744073709549568.0 ){
s2 = (u64)rr[0];
-#if defined(_MSC_VER) && _MSC_VER<1700
- if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); }
-#endif
rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
- if( e>0 ){
- while( e>=100 ){
- e -= 100;
- dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
- }
- while( e>=10 ){
- e -= 10;
- dekkerMul2(rr, 1.0e+10, 0.0);
- }
- while( e>=1 ){
- e -= 1;
- dekkerMul2(rr, 1.0e+01, 0.0);
- }
- }else{
- while( e<=-100 ){
- e += 100;
- dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
- }
- while( e<=-10 ){
- e += 10;
- dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
- }
- while( e<=-1 ){
- e += 1;
- dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
- }
+ }else{
+ rr[1] = 0.0;
+ }
+ assert( rr[1]<=1.0e-10*rr[0] ); /* Equal only when rr[0]==0.0 */
+
+ if( e>0 ){
+ while( e>=100 ){
+ e -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( e>=10 ){
+ e -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( e>=1 ){
+ e -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
+ }
+ }else{
+ while( e<=-100 ){
+ e += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( e<=-10 ){
+ e += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( e<=-1 ){
+ e += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
}
- *pResult = rr[0]+rr[1];
- if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
}
+ *pResult = rr[0]+rr[1];
+ if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
if( sign<0 ) *pResult = -*pResult;
assert( !sqlite3IsNaN(*pResult) );
@@ -35924,10 +36511,13 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){
** Decode a floating-point value into an approximate decimal
** representation.
**
-** Round the decimal representation to n significant digits if
-** n is positive. Or round to -n signficant digits after the
-** decimal point if n is negative. No rounding is performed if
-** n is zero.
+** If iRound<=0 then round to -iRound significant digits to the
+** the left of the decimal point, or to a maximum of mxRound total
+** significant digits.
+**
+** If iRound>0 round to min(iRound,mxRound) significant digits total.
+**
+** mxRound must be positive.
**
** The significant digits of the decimal representation are
** stored in p->z[] which is a often (but not always) a pointer
@@ -35938,8 +36528,11 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou
int i;
u64 v;
int e, exp = 0;
+ double rr[2];
+
p->isSpecial = 0;
p->z = p->zBuf;
+ assert( mxRound>0 );
/* Convert negative numbers to positive. Deal with Infinity, 0.0, and
** NaN. */
@@ -35966,62 +36559,45 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou
/* Multiply r by powers of ten until it lands somewhere in between
** 1.0e+19 and 1.0e+17.
+ **
+ ** Use Dekker-style double-double computation to increase the
+ ** precision.
+ **
+ ** The error terms on constants like 1.0e+100 computed using the
+ ** decimal extension, for example as follows:
+ **
+ ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
*/
- if( sqlite3Config.bUseLongDouble ){
- LONGDOUBLE_TYPE rr = r;
- if( rr>=1.0e+19 ){
- while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; }
- while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; }
- while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; }
- }else{
- while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; }
- while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; }
- while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; }
+ rr[0] = r;
+ rr[1] = 0.0;
+ if( rr[0]>9.223372036854774784e+18 ){
+ while( rr[0]>9.223372036854774784e+118 ){
+ exp += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( rr[0]>9.223372036854774784e+28 ){
+ exp += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( rr[0]>9.223372036854774784e+18 ){
+ exp += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
}
- v = (u64)rr;
}else{
- /* If high-precision floating point is not available using "long double",
- ** then use Dekker-style double-double computation to increase the
- ** precision.
- **
- ** The error terms on constants like 1.0e+100 computed using the
- ** decimal extension, for example as follows:
- **
- ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
- */
- double rr[2];
- rr[0] = r;
- rr[1] = 0.0;
- if( rr[0]>9.223372036854774784e+18 ){
- while( rr[0]>9.223372036854774784e+118 ){
- exp += 100;
- dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
- }
- while( rr[0]>9.223372036854774784e+28 ){
- exp += 10;
- dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
- }
- while( rr[0]>9.223372036854774784e+18 ){
- exp += 1;
- dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
- }
- }else{
- while( rr[0]<9.223372036854774784e-83 ){
- exp -= 100;
- dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
- }
- while( rr[0]<9.223372036854774784e+07 ){
- exp -= 10;
- dekkerMul2(rr, 1.0e+10, 0.0);
- }
- while( rr[0]<9.22337203685477478e+17 ){
- exp -= 1;
- dekkerMul2(rr, 1.0e+01, 0.0);
- }
+ while( rr[0]<9.223372036854774784e-83 ){
+ exp -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( rr[0]<9.223372036854774784e+07 ){
+ exp -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( rr[0]<9.22337203685477478e+17 ){
+ exp -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
}
- v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
}
-
+ v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
/* Extract significant digits. */
i = sizeof(p->zBuf)-1;
@@ -36064,7 +36640,11 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou
}
p->z = &p->zBuf[i+1];
assert( i+p->n < sizeof(p->zBuf) );
- while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; }
+ assert( p->n>0 );
+ while( p->z[p->n-1]=='0' ){
+ p->n--;
+ assert( p->n>0 );
+ }
}
/*
@@ -36569,7 +37149,7 @@ SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
}
/*
-** Compute the absolute value of a 32-bit signed integer, of possible. Or
+** Compute the absolute value of a 32-bit signed integer, if possible. Or
** if the integer has a value of -2147483648, return +2147483647
*/
SQLITE_PRIVATE int sqlite3AbsInt32(int x){
@@ -36792,104 +37372,6 @@ SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nNam
return 0;
}
-/*
-** High-resolution hardware timer used for debugging and testing only.
-*/
-#if defined(VDBE_PROFILE) \
- || defined(SQLITE_PERFORMANCE_TRACE) \
- || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
-/************** Include hwtime.h in the middle of util.c *********************/
-/************** Begin file hwtime.h ******************************************/
-/*
-** 2008 May 27
-**
-** 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 inline asm code for retrieving "high-performance"
-** counters for x86 and x86_64 class CPUs.
-*/
-#ifndef SQLITE_HWTIME_H
-#define SQLITE_HWTIME_H
-
-/*
-** The following routine only works on Pentium-class (or newer) processors.
-** It uses the RDTSC opcode to read the cycle count value out of the
-** processor and returns that value. This can be used for high-res
-** profiling.
-*/
-#if !defined(__STRICT_ANSI__) && \
- (defined(__GNUC__) || defined(_MSC_VER)) && \
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
-
- #if defined(__GNUC__)
-
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
- unsigned int lo, hi;
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
- return (sqlite_uint64)hi << 32 | lo;
- }
-
- #elif defined(_MSC_VER)
-
- __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
- __asm {
- rdtsc
- ret ; return value at EDX:EAX
- }
- }
-
- #endif
-
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
-
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
- unsigned int lo, hi;
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
- return (sqlite_uint64)hi << 32 | lo;
- }
-
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
-
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
- unsigned long long retval;
- unsigned long junk;
- __asm__ __volatile__ ("\n\
- 1: mftbu %1\n\
- mftb %L0\n\
- mftbu %0\n\
- cmpw %0,%1\n\
- bne 1b"
- : "=r" (retval), "=r" (junk));
- return retval;
- }
-
-#else
-
- /*
- ** 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); }
-
-#endif
-
-#endif /* !defined(SQLITE_HWTIME_H) */
-
-/************** End of hwtime.h **********************************************/
-/************** Continuing where we left off in util.c ***********************/
-#endif
-
/************** End of util.c ************************************************/
/************** Begin file hash.c ********************************************/
/*
@@ -36948,12 +37430,19 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){
*/
static unsigned int strHash(const char *z){
unsigned int h = 0;
- unsigned char c;
- while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/
+ while( z[0] ){ /*OPTIMIZATION-IF-TRUE*/
/* Knuth multiplicative hashing. (Sorting & Searching, p. 510).
** 0x9e3779b1 is 2654435761 which is the closest prime number to
- ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */
- h += sqlite3UpperToLower[c];
+ ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2.
+ **
+ ** Only bits 0xdf for ASCII and bits 0xbf for EBCDIC each octet are
+ ** hashed since the omitted bits determine the upper/lower case difference.
+ */
+#ifdef SQLITE_EBCDIC
+ h += 0xbf & (unsigned char)*(z++);
+#else
+ h += 0xdf & (unsigned char)*(z++);
+#endif
h *= 0x9e3779b1;
}
return h;
@@ -37026,9 +37515,8 @@ static int rehash(Hash *pH, unsigned int new_size){
pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht);
memset(new_ht, 0, new_size*sizeof(struct _ht));
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
- unsigned int h = strHash(elem->pKey) % new_size;
next_elem = elem->next;
- insertElement(pH, &new_ht[h], elem);
+ insertElement(pH, &new_ht[elem->h % new_size], elem);
}
return 1;
}
@@ -37046,23 +37534,22 @@ static HashElem *findElementWithHash(
HashElem *elem; /* Used to loop thru the element list */
unsigned int count; /* Number of elements left to test */
unsigned int h; /* The computed hash */
- static HashElem nullElement = { 0, 0, 0, 0 };
+ static HashElem nullElement = { 0, 0, 0, 0, 0 };
+ h = strHash(pKey);
if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
struct _ht *pEntry;
- h = strHash(pKey) % pH->htsize;
- pEntry = &pH->ht[h];
+ pEntry = &pH->ht[h % pH->htsize];
elem = pEntry->chain;
count = pEntry->count;
}else{
- h = 0;
elem = pH->first;
count = pH->count;
}
if( pHash ) *pHash = h;
while( count ){
assert( elem!=0 );
- if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
+ if( h==elem->h && sqlite3StrICmp(elem->pKey,pKey)==0 ){
return elem;
}
elem = elem->next;
@@ -37074,10 +37561,9 @@ static HashElem *findElementWithHash(
/* Remove a single entry from the hash table given a pointer to that
** element and a hash on the element's key.
*/
-static void removeElementGivenHash(
+static void removeElement(
Hash *pH, /* The pH containing "elem" */
- HashElem* elem, /* The element to be removed from the pH */
- unsigned int h /* Hash value for the element */
+ HashElem *elem /* The element to be removed from the pH */
){
struct _ht *pEntry;
if( elem->prev ){
@@ -37089,7 +37575,7 @@ static void removeElementGivenHash(
elem->next->prev = elem->prev;
}
if( pH->ht ){
- pEntry = &pH->ht[h];
+ pEntry = &pH->ht[elem->h % pH->htsize];
if( pEntry->chain==elem ){
pEntry->chain = elem->next;
}
@@ -37140,7 +37626,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
if( elem->data ){
void *old_data = elem->data;
if( data==0 ){
- removeElementGivenHash(pH,elem,h);
+ removeElement(pH,elem);
}else{
elem->data = data;
elem->pKey = pKey;
@@ -37151,15 +37637,13 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) );
if( new_elem==0 ) return data;
new_elem->pKey = pKey;
+ new_elem->h = h;
new_elem->data = data;
pH->count++;
- if( pH->count>=10 && pH->count > 2*pH->htsize ){
- if( rehash(pH, pH->count*2) ){
- assert( pH->htsize>0 );
- h = strHash(pKey) % pH->htsize;
- }
+ if( pH->count>=5 && pH->count > 2*pH->htsize ){
+ rehash(pH, pH->count*3);
}
- insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem);
+ insertElement(pH, pH->ht ? &pH->ht[new_elem->h % pH->htsize] : 0, new_elem);
return 0;
}
@@ -37227,16 +37711,16 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
/* 48 */ "Program" OpHelp(""),
/* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 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 */ "ElseEq" OpHelp(""),
- /* 59 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 50 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 51 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
+ /* 52 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
+ /* 53 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
+ /* 54 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
+ /* 55 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
+ /* 56 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
+ /* 57 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
+ /* 58 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
+ /* 59 */ "ElseEq" OpHelp(""),
/* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
/* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
/* 62 */ "IncrVacuum" OpHelp(""),
@@ -37279,23 +37763,23 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 99 */ "ReadCookie" OpHelp(""),
/* 100 */ "SetCookie" OpHelp(""),
/* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
- /* 102 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
- /* 103 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
- /* 104 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
- /* 105 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
- /* 106 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
- /* 107 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
- /* 108 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
- /* 109 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
- /* 110 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
- /* 111 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
- /* 112 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 102 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 103 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
+ /* 104 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
+ /* 105 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
+ /* 106 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
+ /* 107 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
+ /* 108 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
+ /* 109 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
+ /* 110 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
+ /* 111 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
+ /* 112 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
/* 113 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
- /* 114 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
- /* 115 */ "OpenDup" OpHelp(""),
+ /* 114 */ "OpenDup" OpHelp(""),
+ /* 115 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
/* 116 */ "OpenAutoindex" OpHelp("nColumn=P2"),
- /* 117 */ "String8" OpHelp("r[P2]='P4'"),
- /* 118 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 117 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 118 */ "String8" OpHelp("r[P2]='P4'"),
/* 119 */ "SorterOpen" OpHelp(""),
/* 120 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
/* 121 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
@@ -37330,8 +37814,8 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 150 */ "LoadAnalysis" OpHelp(""),
/* 151 */ "DropTable" OpHelp(""),
/* 152 */ "DropIndex" OpHelp(""),
- /* 153 */ "Real" OpHelp("r[P2]=P4"),
- /* 154 */ "DropTrigger" OpHelp(""),
+ /* 153 */ "DropTrigger" OpHelp(""),
+ /* 154 */ "Real" OpHelp("r[P2]=P4"),
/* 155 */ "IntegrityCk" OpHelp(""),
/* 156 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
/* 157 */ "Param" OpHelp(""),
@@ -38571,7 +39055,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){
# endif
#else /* !SQLITE_WASI */
# ifndef HAVE_FCHMOD
-# define HAVE_FCHMOD
+# define HAVE_FCHMOD 1
# endif
#endif /* SQLITE_WASI */
@@ -38642,6 +39126,7 @@ struct unixFile {
#endif
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
unsigned iBusyTimeout; /* Wait this many millisec on locks */
+ int bBlockOnConnect; /* True to block for SHARED locks */
#endif
#if OS_VXWORKS
struct vxworksFileId *pId; /* Unique file ID */
@@ -38680,7 +39165,7 @@ static pid_t randomnessPid = 0;
#define UNIXFILE_EXCL 0x01 /* Connections from one process only */
#define UNIXFILE_RDONLY 0x02 /* Connection is read only */
#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
-#ifndef SQLITE_DISABLE_DIRSYNC
+#if !defined(SQLITE_DISABLE_DIRSYNC) && !defined(_AIX)
# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
#else
# define UNIXFILE_DIRSYNC 0x00
@@ -40022,7 +40507,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
if( pInode->bProcessLock==0 ){
struct flock lock;
- assert( pInode->nLock==0 );
+ /* assert( pInode->nLock==0 ); <-- Not true if unix-excl READONLY used */
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
@@ -40035,6 +40520,13 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
rc = 0;
}
}else{
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( pFile->bBlockOnConnect && pLock->l_type==F_RDLCK
+ && pLock->l_start==SHARED_FIRST && pLock->l_len==SHARED_SIZE
+ ){
+ rc = osFcntl(pFile->h, F_SETLKW, pLock);
+ }else
+#endif
rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile);
}
return rc;
@@ -40637,26 +41129,22 @@ static int nolockClose(sqlite3_file *id) {
/*
** This routine checks if there is a RESERVED lock held on the specified
-** file by this or any other process. If such a lock is held, set *pResOut
-** to a non-zero value otherwise *pResOut is set to zero. The return value
-** is set to SQLITE_OK unless an I/O error occurs during lock checking.
-**
-** In dotfile locking, either a lock exists or it does not. So in this
-** variation of CheckReservedLock(), *pResOut is set to true if any lock
-** is held on the file and false if the file is unlocked.
+** file by this or any other process. If the caller holds a SHARED
+** or greater lock when it is called, then it is assumed that no other
+** client may hold RESERVED. Or, if the caller holds no lock, then it
+** is assumed another client holds RESERVED if the lock-file exists.
*/
static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
- int rc = SQLITE_OK;
- int reserved = 0;
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));
- *pResOut = reserved;
- return rc;
+ if( pFile->eFileLock>=SHARED_LOCK ){
+ *pResOut = 0;
+ }else{
+ *pResOut = osAccess((const char*)pFile->lockingContext, 0)==0;
+ }
+ OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, 0, *pResOut));
+ return SQLITE_OK;
}
/*
@@ -40826,54 +41314,33 @@ static int robust_flock(int fd, int op){
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
*/
static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
- int rc = SQLITE_OK;
- int reserved = 0;
+#ifdef SQLITE_DEBUG
unixFile *pFile = (unixFile*)id;
+#else
+ UNUSED_PARAMETER(id);
+#endif
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( pFile );
+ assert( pFile->eFileLock<=SHARED_LOCK );
- /* 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 */
- int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
- if( !lrc ){
- /* got the lock, unlock it */
- lrc = robust_flock(pFile->h, LOCK_UN);
- if ( lrc ) {
- int tErrno = errno;
- /* unlock failed with an error */
- lrc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
- } else {
- int tErrno = errno;
- reserved = 1;
- /* someone else might have it reserved */
- lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if( IS_LOCK_ERROR(lrc) ){
- storeLastErrno(pFile, tErrno);
- rc = lrc;
- }
- }
- }
- OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
+ /* The flock VFS only ever takes exclusive locks (see function flockLock).
+ ** Therefore, if this connection is holding any lock at all, no other
+ ** connection may be holding a RESERVED lock. So set *pResOut to 0
+ ** in this case.
+ **
+ ** Or, this connection may be holding no lock. In that case, set *pResOut to
+ ** 0 as well. The caller will then attempt to take an EXCLUSIVE lock on the
+ ** db in order to roll the hot journal back. If there is another connection
+ ** holding a lock, that attempt will fail and an SQLITE_BUSY returned to
+ ** the user. With other VFS, we try to avoid this, in order to allow a reader
+ ** to proceed while a writer is preparing its transaction. But that won't
+ ** work with the flock VFS - as it always takes EXCLUSIVE locks - so it is
+ ** not a problem in this case. */
+ *pResOut = 0;
-#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if( (rc & 0xff) == SQLITE_IOERR ){
- rc = SQLITE_OK;
- reserved=1;
- }
-#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
- *pResOut = reserved;
- return rc;
+ return SQLITE_OK;
}
/*
@@ -42345,7 +42812,7 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
/* Forward declaration */
static int unixGetTempname(int nBuf, char *zBuf);
-#ifndef SQLITE_OMIT_WAL
+#if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL)
static int unixFcntlExternalReader(unixFile*, int*);
#endif
@@ -42370,6 +42837,11 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
+ case SQLITE_FCNTL_NULL_IO: {
+ osClose(pFile->h);
+ pFile->h = -1;
+ return SQLITE_OK;
+ }
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
@@ -42416,8 +42888,9 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
case SQLITE_FCNTL_LOCK_TIMEOUT: {
int iOld = pFile->iBusyTimeout;
+ int iNew = *(int*)pArg;
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
- pFile->iBusyTimeout = *(int*)pArg;
+ pFile->iBusyTimeout = iNew<0 ? 0x7FFFFFFF : (unsigned)iNew;
#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
pFile->iBusyTimeout = !!(*(int*)pArg);
#else
@@ -42426,7 +42899,12 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
*(int*)pArg = iOld;
return SQLITE_OK;
}
-#endif
+ case SQLITE_FCNTL_BLOCK_ON_CONNECT: {
+ int iNew = *(int*)pArg;
+ pFile->bBlockOnConnect = iNew;
+ return SQLITE_OK;
+ }
+#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
#if SQLITE_MAX_MMAP_SIZE>0
case SQLITE_FCNTL_MMAP_SIZE: {
i64 newLimit = *(i64*)pArg;
@@ -42472,7 +42950,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
case SQLITE_FCNTL_EXTERNAL_READER: {
-#ifndef SQLITE_OMIT_WAL
+#if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL)
return unixFcntlExternalReader((unixFile*)id, (int*)pArg);
#else
*(int*)pArg = 0;
@@ -42511,6 +42989,7 @@ static void setDeviceCharacteristics(unixFile *pFd){
if( pFd->ctrlFlags & UNIXFILE_PSOW ){
pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
}
+ pFd->deviceCharacteristics |= SQLITE_IOCAP_SUBPAGE_READ;
pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
}
@@ -42561,7 +43040,7 @@ static void setDeviceCharacteristics(unixFile *pFile){
pFile->sectorSize = fsInfo.f_bsize;
pFile->deviceCharacteristics =
/* full bitset of atomics from max sector size and smaller */
- ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+ (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) |
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
** so it is ordered */
0;
@@ -42569,7 +43048,7 @@ static void setDeviceCharacteristics(unixFile *pFile){
pFile->sectorSize = fsInfo.f_bsize;
pFile->deviceCharacteristics =
/* full bitset of atomics from max sector size and smaller */
- ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+ (((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2) |
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
** so it is ordered */
0;
@@ -42645,7 +43124,7 @@ static int unixGetpagesize(void){
#endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */
-#ifndef SQLITE_OMIT_WAL
+#if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL)
/*
** Object used to represent an shared memory buffer.
@@ -43398,21 +43877,20 @@ static int unixShmLock(
/* 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).
+ ** 1. Recovery lock (ofst==2).
+ ** 2. Checkpointer lock (ofst==1).
+ ** 3. Write lock (ofst==0).
+ ** 4. 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
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
{
u16 lockMask = (p->exclMask|p->sharedMask);
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
- (ofst!=2) /* not RECOVER */
+ (ofst!=2 || lockMask==0)
&& (ofst!=1 || lockMask==0 || lockMask==2)
&& (ofst!=0 || lockMask<3)
&& (ofst<3 || lockMask<(1<<ofst))
@@ -45217,7 +45695,7 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
/* Almost all modern unix systems support nanosleep(). But if you are
** compiling for one of the rare exceptions, you can use
- ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if
+ ** -DHAVE_NANOSLEEP=0 (perhaps in conjunction with -DHAVE_USLEEP if
** usleep() is available) in order to bypass the use of nanosleep() */
nanosleep(&sp, NULL);
@@ -46938,8 +47416,18 @@ struct winFile {
sqlite3_int64 mmapSize; /* Size of mapped region */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
#endif
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ DWORD iBusyTimeout; /* Wait this many millisec on locks */
+ int bBlockOnConnect;
+#endif
};
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+# define winFileBusyTimeout(pDbFd) pDbFd->iBusyTimeout
+#else
+# define winFileBusyTimeout(pDbFd) 0
+#endif
+
/*
** The winVfsAppData structure is used for the pAppData member for all of the
** Win32 VFS variants.
@@ -47258,7 +47746,7 @@ static struct win_syscall {
{ "FileTimeToLocalFileTime", (SYSCALL)0, 0 },
#endif
-#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
+#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(const FILETIME*, \
LPFILETIME))aSyscall[11].pCurrent)
#if SQLITE_OS_WINCE
@@ -47267,7 +47755,7 @@ static struct win_syscall {
{ "FileTimeToSystemTime", (SYSCALL)0, 0 },
#endif
-#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
+#define osFileTimeToSystemTime ((BOOL(WINAPI*)(const FILETIME*, \
LPSYSTEMTIME))aSyscall[12].pCurrent)
{ "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
@@ -47373,6 +47861,12 @@ static struct win_syscall {
#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
LPWSTR*))aSyscall[25].pCurrent)
+/*
+** For GetLastError(), MSDN says:
+**
+** Minimum supported client: Windows XP [desktop apps | UWP apps]
+** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
+*/
{ "GetLastError", (SYSCALL)GetLastError, 0 },
#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
@@ -47541,7 +48035,7 @@ static struct win_syscall {
{ "LockFile", (SYSCALL)0, 0 },
#endif
-#ifndef osLockFile
+#if !defined(osLockFile) && defined(SQLITE_WIN32_HAS_ANSI)
#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
DWORD))aSyscall[47].pCurrent)
#endif
@@ -47605,7 +48099,7 @@ static struct win_syscall {
{ "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
-#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
+#define osSystemTimeToFileTime ((BOOL(WINAPI*)(const SYSTEMTIME*, \
LPFILETIME))aSyscall[56].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
@@ -47614,7 +48108,7 @@ static struct win_syscall {
{ "UnlockFile", (SYSCALL)0, 0 },
#endif
-#ifndef osUnlockFile
+#if !defined(osUnlockFile) && defined(SQLITE_WIN32_HAS_ANSI)
#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
DWORD))aSyscall[57].pCurrent)
#endif
@@ -47655,11 +48149,13 @@ static struct win_syscall {
#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
DWORD,DWORD))aSyscall[62].pCurrent)
-#if !SQLITE_OS_WINRT
+/*
+** For WaitForSingleObject(), MSDN says:
+**
+** Minimum supported client: Windows XP [desktop apps | UWP apps]
+** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
+*/
{ "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
-#else
- { "WaitForSingleObject", (SYSCALL)0, 0 },
-#endif
#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
DWORD))aSyscall[63].pCurrent)
@@ -47806,6 +48302,97 @@ static struct win_syscall {
#define osFlushViewOfFile \
((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
+/*
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CreateEvent()
+** to implement blocking locks with timeouts. MSDN says:
+**
+** Minimum supported client: Windows XP [desktop apps | UWP apps]
+** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
+*/
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ { "CreateEvent", (SYSCALL)CreateEvent, 0 },
+#else
+ { "CreateEvent", (SYSCALL)0, 0 },
+#endif
+
+#define osCreateEvent ( \
+ (HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \
+ aSyscall[80].pCurrent \
+)
+
+/*
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CancelIo()
+** for the case where a timeout expires and a lock request must be
+** cancelled.
+**
+** Minimum supported client: Windows XP [desktop apps | UWP apps]
+** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
+*/
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ { "CancelIo", (SYSCALL)CancelIo, 0 },
+#else
+ { "CancelIo", (SYSCALL)0, 0 },
+#endif
+
+#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[81].pCurrent)
+
+#if defined(SQLITE_WIN32_HAS_WIDE) && defined(_WIN32)
+ { "GetModuleHandleW", (SYSCALL)GetModuleHandleW, 0 },
+#else
+ { "GetModuleHandleW", (SYSCALL)0, 0 },
+#endif
+
+#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[82].pCurrent)
+
+#ifndef _WIN32
+ { "getenv", (SYSCALL)getenv, 0 },
+#else
+ { "getenv", (SYSCALL)0, 0 },
+#endif
+
+#define osGetenv ((const char *(*)(const char *))aSyscall[83].pCurrent)
+
+#ifndef _WIN32
+ { "getcwd", (SYSCALL)getcwd, 0 },
+#else
+ { "getcwd", (SYSCALL)0, 0 },
+#endif
+
+#define osGetcwd ((char*(*)(char*,size_t))aSyscall[84].pCurrent)
+
+#ifndef _WIN32
+ { "readlink", (SYSCALL)readlink, 0 },
+#else
+ { "readlink", (SYSCALL)0, 0 },
+#endif
+
+#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[85].pCurrent)
+
+#ifndef _WIN32
+ { "lstat", (SYSCALL)lstat, 0 },
+#else
+ { "lstat", (SYSCALL)0, 0 },
+#endif
+
+#define osLstat ((int(*)(const char*,struct stat*))aSyscall[86].pCurrent)
+
+#ifndef _WIN32
+ { "__errno", (SYSCALL)__errno, 0 },
+#else
+ { "__errno", (SYSCALL)0, 0 },
+#endif
+
+#define osErrno (*((int*(*)(void))aSyscall[87].pCurrent)())
+
+#ifndef _WIN32
+ { "cygwin_conv_path", (SYSCALL)cygwin_conv_path, 0 },
+#else
+ { "cygwin_conv_path", (SYSCALL)0, 0 },
+#endif
+
+#define osCygwin_conv_path ((size_t(*)(unsigned int, \
+ const void *, void *, size_t))aSyscall[88].pCurrent)
+
}; /* End of the overrideable system calls */
/*
@@ -47979,6 +48566,7 @@ SQLITE_API int sqlite3_win32_reset_heap(){
}
#endif /* SQLITE_WIN32_MALLOC */
+#ifdef _WIN32
/*
** This function outputs the specified (ANSI) string to the Win32 debugger
** (if available).
@@ -48021,6 +48609,7 @@ SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
}
#endif
}
+#endif /* _WIN32 */
/*
** The following routine suspends the current thread for at least ms
@@ -48104,7 +48693,9 @@ SQLITE_API int sqlite3_win32_is_nt(void){
}
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#elif SQLITE_TEST
- return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
+ return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2
+ || osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0
+ ;
#else
/*
** NOTE: All sub-platforms where the GetVersionEx[AW] functions are
@@ -48319,6 +48910,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
}
#endif /* SQLITE_WIN32_MALLOC */
+#ifdef _WIN32
/*
** Convert a UTF-8 string to Microsoft Unicode.
**
@@ -48344,6 +48936,7 @@ static LPWSTR winUtf8ToUnicode(const char *zText){
}
return zWideText;
}
+#endif /* _WIN32 */
/*
** Convert a Microsoft Unicode string to UTF-8.
@@ -48378,28 +48971,29 @@ static char *winUnicodeToUtf8(LPCWSTR zWideText){
** Space to hold the returned string is obtained from sqlite3_malloc().
*/
static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){
- int nByte;
+ int nWideChar;
LPWSTR zMbcsText;
int codepage = useAnsi ? CP_ACP : CP_OEMCP;
- nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
- 0)*sizeof(WCHAR);
- if( nByte==0 ){
+ nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
+ 0);
+ if( nWideChar==0 ){
return 0;
}
- zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) );
+ zMbcsText = sqlite3MallocZero( nWideChar*sizeof(WCHAR) );
if( zMbcsText==0 ){
return 0;
}
- nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
- nByte);
- if( nByte==0 ){
+ nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
+ nWideChar);
+ if( nWideChar==0 ){
sqlite3_free(zMbcsText);
zMbcsText = 0;
}
return zMbcsText;
}
+#ifdef _WIN32
/*
** Convert a Microsoft Unicode string to a multi-byte character string,
** using the ANSI or OEM code page.
@@ -48427,6 +49021,7 @@ static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){
}
return zText;
}
+#endif /* _WIN32 */
/*
** Convert a multi-byte character string to UTF-8.
@@ -48446,6 +49041,7 @@ static char *winMbcsToUtf8(const char *zText, int useAnsi){
return zTextUtf8;
}
+#ifdef _WIN32
/*
** Convert a UTF-8 string to a multi-byte character string.
**
@@ -48495,6 +49091,7 @@ SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){
#endif
return winUnicodeToUtf8(zWideText);
}
+#endif /* _WIN32 */
/*
** This is a public wrapper for the winMbcsToUtf8() function.
@@ -48512,6 +49109,7 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){
return winMbcsToUtf8(zText, osAreFileApisANSI());
}
+#ifdef _WIN32
/*
** This is a public wrapper for the winMbcsToUtf8() function.
*/
@@ -48636,6 +49234,7 @@ SQLITE_API int sqlite3_win32_set_directory(
){
return sqlite3_win32_set_directory16(type, zValue);
}
+#endif /* _WIN32 */
/*
** The return value of winGetLastErrorMsg
@@ -49184,14 +49783,99 @@ static BOOL winLockFile(
ovlp.Offset = offsetLow;
ovlp.OffsetHigh = offsetHigh;
return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
+#ifdef SQLITE_WIN32_HAS_ANSI
}else{
return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
numBytesHigh);
+#endif
}
#endif
}
/*
+** Lock a region of nByte bytes starting at offset offset of file hFile.
+** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock
+** otherwise. If nMs is greater than zero and the lock cannot be obtained
+** immediately, block for that many ms before giving up.
+**
+** This function returns SQLITE_OK if the lock is obtained successfully. If
+** some other process holds the lock, SQLITE_BUSY is returned if nMs==0, or
+** SQLITE_BUSY_TIMEOUT otherwise. Or, if an error occurs, SQLITE_IOERR.
+*/
+static int winHandleLockTimeout(
+ HANDLE hFile,
+ DWORD offset,
+ DWORD nByte,
+ int bExcl,
+ DWORD nMs
+){
+ DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0);
+ int rc = SQLITE_OK;
+ BOOL ret;
+
+ if( !osIsNT() ){
+ ret = winLockFile(&hFile, flags, offset, 0, nByte, 0);
+ }else{
+ OVERLAPPED ovlp;
+ memset(&ovlp, 0, sizeof(OVERLAPPED));
+ ovlp.Offset = offset;
+
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( nMs!=0 ){
+ flags &= ~LOCKFILE_FAIL_IMMEDIATELY;
+ }
+ ovlp.hEvent = osCreateEvent(NULL, TRUE, FALSE, NULL);
+ if( ovlp.hEvent==NULL ){
+ return SQLITE_IOERR_LOCK;
+ }
+#endif
+
+ ret = osLockFileEx(hFile, flags, 0, nByte, 0, &ovlp);
+
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* If SQLITE_ENABLE_SETLK_TIMEOUT is defined, then the file-handle was
+ ** opened with FILE_FLAG_OVERHEAD specified. In this case, the call to
+ ** LockFileEx() may fail because the request is still pending. This can
+ ** happen even if LOCKFILE_FAIL_IMMEDIATELY was specified.
+ **
+ ** If nMs is 0, then LOCKFILE_FAIL_IMMEDIATELY was set in the flags
+ ** passed to LockFileEx(). In this case, if the operation is pending,
+ ** block indefinitely until it is finished.
+ **
+ ** Otherwise, wait for up to nMs ms for the operation to finish. nMs
+ ** may be set to INFINITE.
+ */
+ if( !ret && GetLastError()==ERROR_IO_PENDING ){
+ DWORD nDelay = (nMs==0 ? INFINITE : nMs);
+ DWORD res = osWaitForSingleObject(ovlp.hEvent, nDelay);
+ if( res==WAIT_OBJECT_0 ){
+ ret = TRUE;
+ }else if( res==WAIT_TIMEOUT ){
+#if SQLITE_ENABLE_SETLK_TIMEOUT==1
+ rc = SQLITE_BUSY_TIMEOUT;
+#else
+ rc = SQLITE_BUSY;
+#endif
+ }else{
+ /* Some other error has occurred */
+ rc = SQLITE_IOERR_LOCK;
+ }
+
+ /* If it is still pending, cancel the LockFileEx() call. */
+ osCancelIo(hFile);
+ }
+
+ osCloseHandle(ovlp.hEvent);
+#endif
+ }
+
+ if( rc==SQLITE_OK && !ret ){
+ rc = SQLITE_BUSY;
+ }
+ return rc;
+}
+
+/*
** Unlock a file region.
*/
static BOOL winUnlockFile(
@@ -49215,13 +49899,23 @@ static BOOL winUnlockFile(
ovlp.Offset = offsetLow;
ovlp.OffsetHigh = offsetHigh;
return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp);
+#ifdef SQLITE_WIN32_HAS_ANSI
}else{
return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
numBytesHigh);
+#endif
}
#endif
}
+/*
+** Remove an nByte lock starting at offset iOff from HANDLE h.
+*/
+static int winHandleUnlock(HANDLE h, int iOff, int nByte){
+ BOOL ret = winUnlockFile(&h, iOff, 0, nByte, 0);
+ return (ret ? SQLITE_OK : SQLITE_IOERR_UNLOCK);
+}
+
/*****************************************************************************
** The next group of routines implement the I/O methods specified
** by the sqlite3_io_methods object.
@@ -49235,66 +49929,70 @@ static BOOL winUnlockFile(
#endif
/*
-** Move the current position of the file handle passed as the first
-** argument to offset iOffset within the file. If successful, return 0.
-** Otherwise, set pFile->lastErrno and return non-zero.
+** Seek the file handle h to offset nByte of the file.
+**
+** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite
+** error code.
*/
-static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
+static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){
+ int rc = SQLITE_OK; /* Return value */
+
#if !SQLITE_OS_WINRT
LONG upperBits; /* Most sig. 32 bits of new offset */
LONG lowerBits; /* Least sig. 32 bits of new offset */
DWORD dwRet; /* Value returned by SetFilePointer() */
- DWORD lastErrno; /* Value returned by GetLastError() */
-
- OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
lowerBits = (LONG)(iOffset & 0xffffffff);
+ dwRet = osSetFilePointer(h, lowerBits, &upperBits, FILE_BEGIN);
+
/* API oddity: If successful, SetFilePointer() returns a dword
** containing the lower 32-bits of the new file-offset. Or, if it fails,
** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
** whether an error has actually occurred, it is also necessary to call
- ** GetLastError().
- */
- dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
-
- if( (dwRet==INVALID_SET_FILE_POINTER
- && ((lastErrno = osGetLastError())!=NO_ERROR)) ){
- pFile->lastErrno = lastErrno;
- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
- "winSeekFile", pFile->zPath);
- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
- return 1;
+ ** GetLastError(). */
+ if( dwRet==INVALID_SET_FILE_POINTER ){
+ DWORD lastErrno = osGetLastError();
+ if( lastErrno!=NO_ERROR ){
+ rc = SQLITE_IOERR_SEEK;
+ }
}
-
- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
- return 0;
#else
- /*
- ** Same as above, except that this implementation works for WinRT.
- */
-
+ /* This implementation works for WinRT. */
LARGE_INTEGER x; /* The new offset */
BOOL bRet; /* Value returned by SetFilePointerEx() */
x.QuadPart = iOffset;
- bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN);
+ bRet = osSetFilePointerEx(h, x, 0, FILE_BEGIN);
if(!bRet){
- pFile->lastErrno = osGetLastError();
- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
- "winSeekFile", pFile->zPath);
- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
- return 1;
+ rc = SQLITE_IOERR_SEEK;
}
-
- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
- return 0;
#endif
+
+ OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset, sqlite3ErrName(rc)));
+ return rc;
}
+/*
+** Move the current position of the file handle passed as the first
+** argument to offset iOffset within the file. If successful, return 0.
+** Otherwise, set pFile->lastErrno and return non-zero.
+*/
+static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
+ int rc;
+
+ rc = winHandleSeek(pFile->h, iOffset);
+ if( rc!=SQLITE_OK ){
+ pFile->lastErrno = osGetLastError();
+ winLogError(rc, pFile->lastErrno, "winSeekFile", pFile->zPath);
+ }
+ return rc;
+}
+
+
#if SQLITE_MAX_MMAP_SIZE>0
/* Forward references to VFS helper methods used for memory mapped files */
static int winMapfile(winFile*, sqlite3_int64);
@@ -49555,6 +50253,60 @@ static int winWrite(
}
/*
+** Truncate the file opened by handle h to nByte bytes in size.
+*/
+static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){
+ int rc = SQLITE_OK; /* Return code */
+ rc = winHandleSeek(h, nByte);
+ if( rc==SQLITE_OK ){
+ if( 0==osSetEndOfFile(h) ){
+ rc = SQLITE_IOERR_TRUNCATE;
+ }
+ }
+ return rc;
+}
+
+/*
+** Determine the size in bytes of the file opened by the handle passed as
+** the first argument.
+*/
+static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){
+ int rc = SQLITE_OK;
+
+#if SQLITE_OS_WINRT
+ FILE_STANDARD_INFO info;
+ BOOL b;
+ b = osGetFileInformationByHandleEx(h, FileStandardInfo, &info, sizeof(info));
+ if( b ){
+ *pnByte = info.EndOfFile.QuadPart;
+ }else{
+ rc = SQLITE_IOERR_FSTAT;
+ }
+#else
+ DWORD upperBits = 0;
+ DWORD lowerBits = 0;
+
+ assert( pnByte );
+ lowerBits = osGetFileSize(h, &upperBits);
+ *pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits;
+ if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){
+ rc = SQLITE_IOERR_FSTAT;
+ }
+#endif
+
+ return rc;
+}
+
+/*
+** Close the handle passed as the only argument.
+*/
+static void winHandleClose(HANDLE h){
+ if( h!=INVALID_HANDLE_VALUE ){
+ osCloseHandle(h);
+ }
+}
+
+/*
** Truncate an open file to a specified size
*/
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
@@ -49809,8 +50561,9 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
** Different API routines are called depending on whether or not this
** is Win9x or WinNT.
*/
-static int winGetReadLock(winFile *pFile){
+static int winGetReadLock(winFile *pFile, int bBlock){
int res;
+ DWORD mask = ~(bBlock ? LOCKFILE_FAIL_IMMEDIATELY : 0);
OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
if( osIsNT() ){
#if SQLITE_OS_WINCE
@@ -49820,7 +50573,7 @@ static int winGetReadLock(winFile *pFile){
*/
res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0);
#else
- res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0,
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0,
SHARED_SIZE, 0);
#endif
}
@@ -49829,7 +50582,7 @@ static int winGetReadLock(winFile *pFile){
int lk;
sqlite3_randomness(sizeof(lk), &lk);
pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
- res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS&mask,
SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
}
#endif
@@ -49924,46 +50677,62 @@ static int winLock(sqlite3_file *id, int locktype){
assert( locktype!=PENDING_LOCK );
assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
- /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
+ /* Lock the PENDING_LOCK byte if we need to acquire an EXCLUSIVE lock or
** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
** the PENDING_LOCK byte is temporary.
*/
newLocktype = pFile->locktype;
- if( pFile->locktype==NO_LOCK
- || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK)
+ if( locktype==SHARED_LOCK
+ || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
){
int cnt = 3;
- while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
- PENDING_BYTE, 0, 1, 0))==0 ){
+
+ /* Flags for the LockFileEx() call. This should be an exclusive lock if
+ ** this call is to obtain EXCLUSIVE, or a shared lock if this call is to
+ ** obtain SHARED. */
+ int flags = LOCKFILE_FAIL_IMMEDIATELY;
+ if( locktype==EXCLUSIVE_LOCK ){
+ flags |= LOCKFILE_EXCLUSIVE_LOCK;
+ }
+ while( cnt>0 ){
/* Try 3 times to get the pending lock. This is needed to work
** around problems caused by indexing and/or anti-virus software on
** Windows systems.
+ **
** If you are using this code as a model for alternative VFSes, do not
- ** copy this retry logic. It is a hack intended for Windows only.
- */
+ ** copy this retry logic. It is a hack intended for Windows only. */
+ res = winLockFile(&pFile->h, flags, PENDING_BYTE, 0, 1, 0);
+ if( res ) break;
+
lastErrno = osGetLastError();
OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n",
- pFile->h, cnt, res));
+ pFile->h, cnt, res
+ ));
+
if( lastErrno==ERROR_INVALID_HANDLE ){
pFile->lastErrno = lastErrno;
rc = SQLITE_IOERR_LOCK;
OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n",
- pFile->h, cnt, sqlite3ErrName(rc)));
+ pFile->h, cnt, sqlite3ErrName(rc)
+ ));
return rc;
}
- if( cnt ) sqlite3_win32_sleep(1);
+
+ cnt--;
+ if( cnt>0 ) sqlite3_win32_sleep(1);
}
gotPendingLock = res;
- if( !res ){
- lastErrno = osGetLastError();
- }
}
/* Acquire a shared lock
*/
if( locktype==SHARED_LOCK && res ){
assert( pFile->locktype==NO_LOCK );
- res = winGetReadLock(pFile);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ res = winGetReadLock(pFile, pFile->bBlockOnConnect);
+#else
+ res = winGetReadLock(pFile, 0);
+#endif
if( res ){
newLocktype = SHARED_LOCK;
}else{
@@ -50001,7 +50770,7 @@ static int winLock(sqlite3_file *id, int locktype){
newLocktype = EXCLUSIVE_LOCK;
}else{
lastErrno = osGetLastError();
- winGetReadLock(pFile);
+ winGetReadLock(pFile, 0);
}
}
@@ -50081,7 +50850,7 @@ static int winUnlock(sqlite3_file *id, int locktype){
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
- if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){
+ if( locktype==SHARED_LOCK && !winGetReadLock(pFile, 0) ){
/* This should never happen. We should always be able to
** reacquire the read lock */
rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
@@ -50250,6 +51019,11 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
return SQLITE_OK;
}
#endif
+ case SQLITE_FCNTL_NULL_IO: {
+ (void)osCloseHandle(pFile->h);
+ pFile->h = NULL;
+ return SQLITE_OK;
+ }
case SQLITE_FCNTL_TEMPFILENAME: {
char *zTFile = 0;
int rc = winGetTempname(pFile->pVfs, &zTFile);
@@ -50286,6 +51060,28 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
return rc;
}
#endif
+
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ case SQLITE_FCNTL_LOCK_TIMEOUT: {
+ int iOld = pFile->iBusyTimeout;
+ int iNew = *(int*)pArg;
+#if SQLITE_ENABLE_SETLK_TIMEOUT==1
+ pFile->iBusyTimeout = (iNew < 0) ? INFINITE : (DWORD)iNew;
+#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
+ pFile->iBusyTimeout = (DWORD)(!!iNew);
+#else
+# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
+#endif
+ *(int*)pArg = iOld;
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_BLOCK_ON_CONNECT: {
+ int iNew = *(int*)pArg;
+ pFile->bBlockOnConnect = iNew;
+ return SQLITE_OK;
+ }
+#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
+
}
OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
return SQLITE_NOTFOUND;
@@ -50311,7 +51107,7 @@ static int winSectorSize(sqlite3_file *id){
*/
static int winDeviceCharacteristics(sqlite3_file *id){
winFile *p = (winFile*)id;
- return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | SQLITE_IOCAP_SUBPAGE_READ |
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
}
@@ -50366,23 +51162,27 @@ static int winShmMutexHeld(void) {
**
** The following fields are read-only after the object is created:
**
-** fid
** zFilename
**
** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
** winShmMutexHeld() is true when reading or writing any other field
** in this structure.
**
+** File-handle hSharedShm is used to (a) take the DMS lock, (b) truncate
+** the *-shm file if the DMS-locking protocol demands it, and (c) map
+** regions of the *-shm file into memory using MapViewOfFile() or
+** similar. Other locks are taken by individual clients using the
+** winShm.hShm handles.
*/
struct winShmNode {
sqlite3_mutex *mutex; /* Mutex to access this object */
char *zFilename; /* Name of the file */
- winFile hFile; /* File handle from winOpen */
+ HANDLE hSharedShm; /* File handle open on zFilename */
+ int isUnlocked; /* DMS lock has not yet been obtained */
+ int isReadonly; /* True if read-only */
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 */
@@ -50391,7 +51191,6 @@ struct winShmNode {
DWORD lastErrno; /* The Windows errno from the last I/O error */
int nRef; /* Number of winShm objects pointing to this */
- winShm *pFirst; /* All winShm objects pointing to this */
winShmNode *pNext; /* Next in list of all winShmNode objects */
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
u8 nextShmId; /* Next available winShm.id value */
@@ -50407,23 +51206,15 @@ static winShmNode *winShmNodeList = 0;
/*
** Structure used internally by this VFS to record the state of an
-** open shared memory connection.
-**
-** The following fields are initialized when this object is created and
-** are read-only thereafter:
-**
-** winShm.pShmNode
-** winShm.id
-**
-** All other fields are read/write. The winShm.pShmNode->mutex must be held
-** while accessing any read/write fields.
+** open shared memory connection. There is one such structure for each
+** winFile open on a wal mode database.
*/
struct winShm {
winShmNode *pShmNode; /* The underlying winShmNode object */
- winShm *pNext; /* Next winShm with the same winShmNode */
- u8 hasMutex; /* True if holding the winShmNode mutex */
u16 sharedMask; /* Mask of shared locks held */
u16 exclMask; /* Mask of exclusive locks held */
+ HANDLE hShm; /* File-handle on *-shm file. For locking. */
+ int bReadonly; /* True if hShm is opened read-only */
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
u8 id; /* Id of this connection with its winShmNode */
#endif
@@ -50435,50 +51226,6 @@ struct winShm {
#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
-/*
-** Apply advisory locks for all n bytes beginning at ofst.
-*/
-#define WINSHM_UNLCK 1
-#define WINSHM_RDLCK 2
-#define WINSHM_WRLCK 3
-static int winShmSystemLock(
- winShmNode *pFile, /* Apply locks to this open shared-memory segment */
- int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
- int ofst, /* Offset to first byte to be locked/unlocked */
- int nByte /* Number of bytes to lock or unlock */
-){
- int rc = 0; /* Result code form Lock/UnlockFileEx() */
-
- /* Access to the winShmNode object is serialized by the caller */
- 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));
-
- /* Release/Acquire the system-level lock */
- if( lockType==WINSHM_UNLCK ){
- rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
- }else{
- /* Initialize the locking parameters */
- DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
- if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
- rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
- }
-
- if( rc!= 0 ){
- rc = SQLITE_OK;
- }else{
- pFile->lastErrno = osGetLastError();
- rc = SQLITE_BUSY;
- }
-
- OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
- pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
- "winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
-
- return rc;
-}
-
/* Forward references to VFS methods */
static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
static int winDelete(sqlite3_vfs *,const char*,int);
@@ -50510,11 +51257,7 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
UNUSED_VARIABLE_VALUE(bRc);
}
- if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
- SimulateIOErrorBenign(1);
- winClose((sqlite3_file *)&p->hFile);
- SimulateIOErrorBenign(0);
- }
+ winHandleClose(p->hSharedShm);
if( deleteFlag ){
SimulateIOErrorBenign(1);
sqlite3BeginBenignMalloc();
@@ -50532,42 +51275,239 @@ 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.
+** The DMS lock has not yet been taken on the shm file associated with
+** pShmNode. Take the lock. Truncate the *-shm file if required.
+** Return SQLITE_OK if successful, or an SQLite error code otherwise.
*/
-static int winLockSharedMemory(winShmNode *pShmNode){
- int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
+static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){
+ HANDLE h = pShmNode->hSharedShm;
+ int rc = SQLITE_OK;
+ assert( sqlite3_mutex_held(pShmNode->mutex) );
+ rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 1, 0);
if( rc==SQLITE_OK ){
+ /* We have an EXCLUSIVE lock on the DMS byte. This means that this
+ ** is the first process to open the file. Truncate it to zero bytes
+ ** in this case. */
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);
+ rc = SQLITE_READONLY_CANTINIT;
+ }else{
+ rc = winHandleTruncate(h, 0);
}
+
+ /* Release the EXCLUSIVE lock acquired above. */
+ winUnlockFile(&h, WIN_SHM_DMS, 0, 1, 0);
+ }else if( (rc & 0xFF)==SQLITE_BUSY ){
+ rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
+ /* Take a SHARED lock on the DMS byte. */
+ rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 0, nMs);
+ if( rc==SQLITE_OK ){
+ pShmNode->isUnlocked = 0;
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+** Convert a UTF-8 filename into whatever form the underlying
+** operating system wants filenames in. Space to hold the result
+** is obtained from malloc and must be freed by the calling
+** function
+**
+** On Cygwin, 3 possible input forms are accepted:
+** - If the filename starts with "<drive>:/" or "<drive>:\",
+** it is converted to UTF-16 as-is.
+** - If the filename contains '/', it is assumed to be a
+** Cygwin absolute path, it is converted to a win32
+** absolute path in UTF-16.
+** - Otherwise it must be a filename only, the win32 filename
+** is returned in UTF-16.
+** Note: If the function cygwin_conv_path() fails, only
+** UTF-8 -> UTF-16 conversion will be done. This can only
+** happen when the file path >32k, in which case winUtf8ToUnicode()
+** will fail too.
+*/
+static void *winConvertFromUtf8Filename(const char *zFilename){
+ void *zConverted = 0;
+ if( osIsNT() ){
+#ifdef __CYGWIN__
+ int nChar;
+ LPWSTR zWideFilename;
+
+ if( osCygwin_conv_path && !(winIsDriveLetterAndColon(zFilename)
+ && winIsDirSep(zFilename[2])) ){
+ i64 nByte;
+ int convertflag = CCP_POSIX_TO_WIN_W;
+ if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE;
+ nByte = (i64)osCygwin_conv_path(convertflag,
+ zFilename, 0, 0);
+ if( nByte>0 ){
+ zConverted = sqlite3MallocZero(12+(u64)nByte);
+ if ( zConverted==0 ){
+ return zConverted;
+ }
+ zWideFilename = zConverted;
+ /* Filenames should be prefixed, except when converted
+ * full path already starts with "\\?\". */
+ if( osCygwin_conv_path(convertflag, zFilename,
+ zWideFilename+4, nByte)==0 ){
+ if( (convertflag&CCP_RELATIVE) ){
+ memmove(zWideFilename, zWideFilename+4, nByte);
+ }else if( memcmp(zWideFilename+4, L"\\\\", 4) ){
+ memcpy(zWideFilename, L"\\\\?\\", 8);
+ }else if( zWideFilename[6]!='?' ){
+ memmove(zWideFilename+6, zWideFilename+4, nByte);
+ memcpy(zWideFilename, L"\\\\?\\UNC", 14);
+ }else{
+ memmove(zWideFilename, zWideFilename+4, nByte);
+ }
+ return zConverted;
+ }
+ sqlite3_free(zConverted);
+ }
+ }
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
+ if( nChar==0 ){
+ return 0;
+ }
+ zWideFilename = sqlite3MallocZero( nChar*sizeof(WCHAR)+12 );
+ if( zWideFilename==0 ){
+ return 0;
+ }
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1,
+ zWideFilename, nChar);
+ if( nChar==0 ){
+ sqlite3_free(zWideFilename);
+ zWideFilename = 0;
+ }else if( nChar>MAX_PATH
+ && winIsDriveLetterAndColon(zFilename)
+ && winIsDirSep(zFilename[2]) ){
+ memmove(zWideFilename+4, zWideFilename, nChar*sizeof(WCHAR));
+ zWideFilename[2] = '\\';
+ memcpy(zWideFilename, L"\\\\?\\", 8);
+ }else if( nChar>MAX_PATH
+ && winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1])
+ && zFilename[2] != '?' ){
+ memmove(zWideFilename+6, zWideFilename, nChar*sizeof(WCHAR));
+ memcpy(zWideFilename, L"\\\\?\\UNC", 14);
+ }
+ zConverted = zWideFilename;
+#else
+ zConverted = winUtf8ToUnicode(zFilename);
+#endif /* __CYGWIN__ */
+ }
+#if defined(SQLITE_WIN32_HAS_ANSI) && defined(_WIN32)
+ else{
+ zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
+ }
+#endif
+ /* caller will handle out of memory */
+ return zConverted;
+}
+
+/*
+** This function is used to open a handle on a *-shm file.
+**
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined at build time, then the file
+** is opened with FILE_FLAG_OVERLAPPED specified. If not, it is not.
+*/
+static int winHandleOpen(
+ const char *zUtf8, /* File to open */
+ int *pbReadonly, /* IN/OUT: True for readonly handle */
+ HANDLE *ph /* OUT: New HANDLE for file */
+){
+ int rc = SQLITE_OK;
+ void *zConverted = 0;
+ int bReadonly = *pbReadonly;
+ HANDLE h = INVALID_HANDLE_VALUE;
+
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ const DWORD flag_overlapped = FILE_FLAG_OVERLAPPED;
+#else
+ const DWORD flag_overlapped = 0;
+#endif
+
+ /* Convert the filename to the system encoding. */
+ zConverted = winConvertFromUtf8Filename(zUtf8);
+ if( zConverted==0 ){
+ OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8));
+ rc = SQLITE_IOERR_NOMEM_BKPT;
+ goto winopenfile_out;
+ }
+
+ /* Ensure the file we are trying to open is not actually a directory. */
+ if( winIsDir(zConverted) ){
+ OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8));
+ rc = SQLITE_CANTOPEN_ISDIR;
+ goto winopenfile_out;
+ }
+
+ /* TODO: platforms.
+ ** TODO: retry-on-ioerr.
+ */
+ if( osIsNT() ){
+#if SQLITE_OS_WINRT
+ CREATEFILE2_EXTENDED_PARAMETERS extendedParameters;
+ memset(&extendedParameters, 0, sizeof(extendedParameters));
+ extendedParameters.dwSize = sizeof(extendedParameters);
+ extendedParameters.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
+ extendedParameters.dwFileFlags = flag_overlapped;
+ extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
+ h = osCreateFile2((LPCWSTR)zConverted,
+ (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)),/* dwDesiredAccess */
+ FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
+ OPEN_ALWAYS, /* dwCreationDisposition */
+ &extendedParameters
+ );
+#else
+ h = osCreateFileW((LPCWSTR)zConverted, /* lpFileName */
+ (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */
+ FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
+ NULL, /* lpSecurityAttributes */
+ OPEN_ALWAYS, /* dwCreationDisposition */
+ FILE_ATTRIBUTE_NORMAL|flag_overlapped,
+ NULL
+ );
+#endif
+ }else{
+ /* Due to pre-processor directives earlier in this file,
+ ** SQLITE_WIN32_HAS_ANSI is always defined if osIsNT() is false. */
+#ifdef SQLITE_WIN32_HAS_ANSI
+ h = osCreateFileA((LPCSTR)zConverted,
+ (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */
+ FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
+ NULL, /* lpSecurityAttributes */
+ OPEN_ALWAYS, /* dwCreationDisposition */
+ FILE_ATTRIBUTE_NORMAL|flag_overlapped,
+ NULL
+ );
+#endif
}
- return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
+ if( h==INVALID_HANDLE_VALUE ){
+ if( bReadonly==0 ){
+ bReadonly = 1;
+ rc = winHandleOpen(zUtf8, &bReadonly, &h);
+ }else{
+ rc = SQLITE_CANTOPEN_BKPT;
+ }
+ }
+
+ winopenfile_out:
+ sqlite3_free(zConverted);
+ *pbReadonly = bReadonly;
+ *ph = h;
+ return rc;
}
+
/*
** Open the shared-memory area associated with database file pDbFd.
-**
-** When opening a new shared-memory file, if no other instances of that
-** file are currently open, in this process or in other processes, then
-** the file must be truncated to zero length or have its header cleared.
*/
static int winOpenSharedMemory(winFile *pDbFd){
struct winShm *p; /* The connection to be opened */
@@ -50579,98 +51519,83 @@ static int winOpenSharedMemory(winFile *pDbFd){
assert( pDbFd->pShm==0 ); /* Not previously opened */
/* Allocate space for the new sqlite3_shm object. Also speculatively
- ** allocate space for a new winShmNode and filename.
- */
+ ** allocate space for a new winShmNode and filename. */
p = sqlite3MallocZero( sizeof(*p) );
if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT;
nName = sqlite3Strlen30(pDbFd->zPath);
- pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
+ pNew = sqlite3MallocZero( sizeof(*pShmNode) + (i64)nName + 17 );
if( pNew==0 ){
sqlite3_free(p);
return SQLITE_IOERR_NOMEM_BKPT;
}
pNew->zFilename = (char*)&pNew[1];
+ pNew->hSharedShm = INVALID_HANDLE_VALUE;
+ pNew->isUnlocked = 1;
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
+ /* Open a file-handle on the *-shm file for this connection. This file-handle
+ ** is only used for locking. The mapping of the *-shm file is created using
+ ** the shared file handle in winShmNode.hSharedShm. */
+ p->bReadonly = sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0);
+ rc = winHandleOpen(pNew->zFilename, &p->bReadonly, &p->hShm);
+
/* Look to see if there is an existing winShmNode that can be used.
- ** If no matching winShmNode currently exists, create a new one.
- */
+ ** If no matching winShmNode currently exists, then create a new one. */
winShmEnterMutex();
for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
/* TBD need to come up with better match here. Perhaps
- ** use FILE_ID_BOTH_DIR_INFO Structure.
- */
+ ** use FILE_ID_BOTH_DIR_INFO Structure. */
if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
}
- if( pShmNode ){
- sqlite3_free(pNew);
- }else{
- int inFlags = SQLITE_OPEN_WAL;
- int outFlags = 0;
-
+ if( pShmNode==0 ){
pShmNode = pNew;
- pNew = 0;
- ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
- pShmNode->pNext = winShmNodeList;
- winShmNodeList = pShmNode;
+ /* Allocate a mutex for this winShmNode object, if one is required. */
if( sqlite3GlobalConfig.bCoreMutex ){
pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
- if( pShmNode->mutex==0 ){
- rc = SQLITE_IOERR_NOMEM_BKPT;
- goto shm_open_err;
- }
+ if( pShmNode->mutex==0 ) rc = SQLITE_IOERR_NOMEM_BKPT;
}
- 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;
+ /* Open a file-handle to use for mappings, and for the DMS lock. */
+ if( rc==SQLITE_OK ){
+ HANDLE h = INVALID_HANDLE_VALUE;
+ pShmNode->isReadonly = p->bReadonly;
+ rc = winHandleOpen(pNew->zFilename, &pShmNode->isReadonly, &h);
+ pShmNode->hSharedShm = h;
}
- if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1;
- rc = winLockSharedMemory(pShmNode);
- if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
+ /* If successful, link the new winShmNode into the global list. If an
+ ** error occurred, free the object. */
+ if( rc==SQLITE_OK ){
+ pShmNode->pNext = winShmNodeList;
+ winShmNodeList = pShmNode;
+ pNew = 0;
+ }else{
+ sqlite3_mutex_free(pShmNode->mutex);
+ if( pShmNode->hSharedShm!=INVALID_HANDLE_VALUE ){
+ osCloseHandle(pShmNode->hSharedShm);
+ }
+ }
}
- /* Make the new connection a child of the winShmNode */
- p->pShmNode = pShmNode;
+ /* If no error has occurred, link the winShm object to the winShmNode and
+ ** the winShm to pDbFd. */
+ if( rc==SQLITE_OK ){
+ p->pShmNode = pShmNode;
+ pShmNode->nRef++;
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
- p->id = pShmNode->nextShmId++;
+ p->id = pShmNode->nextShmId++;
#endif
- pShmNode->nRef++;
- pDbFd->pShm = p;
- winShmLeaveMutex();
-
- /* The reference count on pShmNode has already been incremented under
- ** the cover of the winShmEnterMutex() mutex and the pointer from the
- ** new (struct winShm) 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.
- */
- sqlite3_mutex_enter(pShmNode->mutex);
- p->pNext = pShmNode->pFirst;
- pShmNode->pFirst = p;
- sqlite3_mutex_leave(pShmNode->mutex);
- return rc;
+ pDbFd->pShm = p;
+ }else if( p ){
+ winHandleClose(p->hShm);
+ sqlite3_free(p);
+ }
- /* Jump here on any error */
-shm_open_err:
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
- winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
- sqlite3_free(p);
- sqlite3_free(pNew);
+ assert( rc!=SQLITE_OK || pShmNode->isUnlocked==0 || pShmNode->nRegion==0 );
winShmLeaveMutex();
+ sqlite3_free(pNew);
return rc;
}
@@ -50685,27 +51610,19 @@ static int winShmUnmap(
winFile *pDbFd; /* Database holding shared-memory */
winShm *p; /* The connection to be closed */
winShmNode *pShmNode; /* The underlying shared-memory file */
- winShm **pp; /* For looping over sibling connections */
pDbFd = (winFile*)fd;
p = pDbFd->pShm;
if( p==0 ) return SQLITE_OK;
- pShmNode = p->pShmNode;
-
- /* Remove connection p from the set of connections associated
- ** with pShmNode */
- sqlite3_mutex_enter(pShmNode->mutex);
- for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
- *pp = p->pNext;
+ if( p->hShm!=INVALID_HANDLE_VALUE ){
+ osCloseHandle(p->hShm);
+ }
- /* Free the connection p */
- sqlite3_free(p);
- pDbFd->pShm = 0;
- sqlite3_mutex_leave(pShmNode->mutex);
+ pShmNode = p->pShmNode;
+ winShmEnterMutex();
/* If pShmNode->nRef has reached 0, then close the underlying
- ** shared-memory file, too */
- winShmEnterMutex();
+ ** shared-memory file, too. */
assert( pShmNode->nRef>0 );
pShmNode->nRef--;
if( pShmNode->nRef==0 ){
@@ -50713,6 +51630,9 @@ static int winShmUnmap(
}
winShmLeaveMutex();
+ /* Free the connection p */
+ sqlite3_free(p);
+ pDbFd->pShm = 0;
return SQLITE_OK;
}
@@ -50727,10 +51647,9 @@ static int winShmLock(
){
winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
winShm *p = pDbFd->pShm; /* The shared memory being locked */
- winShm *pX; /* For looping over all siblings */
winShmNode *pShmNode;
int rc = SQLITE_OK; /* Result code */
- u16 mask; /* Mask of locks to take or release */
+ u16 mask = (u16)((1U<<(ofst+n)) - (1U<<ofst)); /* Mask of locks to [un]take */
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
pShmNode = p->pShmNode;
@@ -50744,85 +51663,81 @@ static int winShmLock(
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
- mask = (u16)((1U<<(ofst+n)) - (1U<<ofst));
- assert( n>1 || mask==(1<<ofst) );
- sqlite3_mutex_enter(pShmNode->mutex);
- if( flags & SQLITE_SHM_UNLOCK ){
- u16 allMask = 0; /* Mask of locks held by siblings */
-
- /* See if any siblings hold this same lock */
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
- if( pX==p ) continue;
- assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
- allMask |= pX->sharedMask;
- }
+ /* 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. Recovery lock (ofst==2).
+ ** 2. Checkpointer lock (ofst==1).
+ ** 3. Write lock (ofst==0).
+ ** 4. 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.
+ */
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
+ {
+ u16 lockMask = (p->exclMask|p->sharedMask);
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
+ (ofst!=2 || lockMask==0)
+ && (ofst!=1 || lockMask==0 || lockMask==2)
+ && (ofst!=0 || lockMask<3)
+ && (ofst<3 || lockMask<(1<<ofst))
+ ));
+ }
+#endif
- /* Unlock the system-level locks */
- if( (mask & allMask)==0 ){
- rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n);
- }else{
- rc = SQLITE_OK;
- }
+ /* Check if there is any work to do. There are three cases:
+ **
+ ** a) An unlock operation where there are locks to unlock,
+ ** b) An shared lock where the requested lock is not already held
+ ** c) An exclusive lock where the requested lock is not already held
+ **
+ ** The SQLite core never requests an exclusive lock that it already holds.
+ ** This is assert()ed immediately below. */
+ assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
+ || 0==(p->exclMask & mask)
+ );
+ if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
+ || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
+ || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
+ ){
- /* Undo the local locks */
- 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" */
+ if( flags & SQLITE_SHM_UNLOCK ){
+ /* Case (a) - unlock. */
- /* Find out which shared locks are already held by sibling connections.
- ** If any sibling already holds an exclusive lock, go ahead and return
- ** SQLITE_BUSY.
- */
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
- if( (pX->exclMask & mask)!=0 ){
- rc = SQLITE_BUSY;
- break;
- }
- allShared |= pX->sharedMask;
- }
+ assert( (p->exclMask & p->sharedMask)==0 );
+ assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
+ assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
- /* Get shared locks at the system level, if necessary */
- if( rc==SQLITE_OK ){
- if( (allShared & mask)==0 ){
- rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n);
- }else{
- rc = SQLITE_OK;
- }
- }
+ rc = winHandleUnlock(p->hShm, ofst+WIN_SHM_BASE, n);
- /* Get the local shared locks */
- if( rc==SQLITE_OK ){
- p->sharedMask |= mask;
- }
- }else{
- /* Make sure no sibling connections hold locks that will block this
- ** lock. If any do, return SQLITE_BUSY right away.
- */
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
- if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
- rc = SQLITE_BUSY;
- break;
+ /* If successful, also clear the bits in sharedMask/exclMask */
+ if( rc==SQLITE_OK ){
+ p->exclMask = (p->exclMask & ~mask);
+ p->sharedMask = (p->sharedMask & ~mask);
}
- }
-
- /* Get the exclusive locks at the system level. Then if successful
- ** also mark the local connection as being locked.
- */
- if( rc==SQLITE_OK ){
- rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n);
+ }else{
+ int bExcl = ((flags & SQLITE_SHM_EXCLUSIVE) ? 1 : 0);
+ DWORD nMs = winFileBusyTimeout(pDbFd);
+ rc = winHandleLockTimeout(p->hShm, ofst+WIN_SHM_BASE, n, bExcl, nMs);
if( rc==SQLITE_OK ){
- assert( (p->sharedMask & mask)==0 );
- p->exclMask |= mask;
+ if( bExcl ){
+ p->exclMask = (p->exclMask | mask);
+ }else{
+ p->sharedMask = (p->sharedMask | mask);
+ }
}
}
}
- sqlite3_mutex_leave(pShmNode->mutex);
- OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
- osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
- sqlite3ErrName(rc)));
+
+ OSTRACE((
+ "SHM-LOCK(%d,%d,%d) pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x,"
+ " rc=%s\n",
+ ofst, n, flags,
+ osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
+ sqlite3ErrName(rc))
+ );
return rc;
}
@@ -50884,13 +51799,15 @@ static int winShmMap(
sqlite3_mutex_enter(pShmNode->mutex);
if( pShmNode->isUnlocked ){
- rc = winLockSharedMemory(pShmNode);
+ /* Take the DMS lock. */
+ assert( pShmNode->nRegion==0 );
+ rc = winLockSharedMemory(pShmNode, winFileBusyTimeout(pDbFd));
if( rc!=SQLITE_OK ) goto shmpage_out;
- pShmNode->isUnlocked = 0;
}
- assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
+ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
if( pShmNode->nRegion<=iRegion ){
+ HANDLE hShared = pShmNode->hSharedShm;
struct ShmRegion *apNew; /* New aRegion[] array */
int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
sqlite3_int64 sz; /* Current size of wal-index file */
@@ -50901,10 +51818,9 @@ static int winShmMap(
** Check to see if it has been allocated (i.e. if the wal-index file is
** large enough to contain the requested region).
*/
- rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
+ rc = winHandleSize(hShared, &sz);
if( rc!=SQLITE_OK ){
- rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
- "winShmMap1", pDbFd->zPath);
+ rc = winLogError(rc, osGetLastError(), "winShmMap1", pDbFd->zPath);
goto shmpage_out;
}
@@ -50913,19 +51829,17 @@ static int winShmMap(
** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
**
** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
- ** the requested memory region.
- */
+ ** the requested memory region. */
if( !isWrite ) goto shmpage_out;
- rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
+ rc = winHandleTruncate(hShared, nByte);
if( rc!=SQLITE_OK ){
- rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
- "winShmMap2", pDbFd->zPath);
+ rc = winLogError(rc, osGetLastError(), "winShmMap2", pDbFd->zPath);
goto shmpage_out;
}
}
/* Map the requested memory region into this processes address space. */
- apNew = (struct ShmRegion *)sqlite3_realloc64(
+ apNew = (struct ShmRegion*)sqlite3_realloc64(
pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
);
if( !apNew ){
@@ -50944,18 +51858,13 @@ static int winShmMap(
void *pMap = 0; /* Mapped memory region */
#if SQLITE_OS_WINRT
- hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
- NULL, protect, nByte, NULL
- );
+ hMap = osCreateFileMappingFromApp(hShared, NULL, protect, nByte, NULL);
#elif defined(SQLITE_WIN32_HAS_WIDE)
- hMap = osCreateFileMappingW(pShmNode->hFile.h,
- NULL, protect, 0, nByte, NULL
- );
+ hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL);
#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
- hMap = osCreateFileMappingA(pShmNode->hFile.h,
- NULL, protect, 0, nByte, NULL
- );
+ hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL);
#endif
+
OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
osGetCurrentProcessId(), pShmNode->nRegion, nByte,
hMap ? "ok" : "failed"));
@@ -50998,7 +51907,9 @@ shmpage_out:
}else{
*pp = 0;
}
- if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
+ if( pShmNode->isReadonly && rc==SQLITE_OK ){
+ rc = SQLITE_READONLY;
+ }
sqlite3_mutex_leave(pShmNode->mutex);
return rc;
}
@@ -51318,47 +52229,6 @@ static winVfsAppData winNolockAppData = {
** sqlite3_vfs object.
*/
-#if defined(__CYGWIN__)
-/*
-** Convert a filename from whatever the underlying operating system
-** supports for filenames into UTF-8. Space to hold the result is
-** obtained from malloc and must be freed by the calling function.
-*/
-static char *winConvertToUtf8Filename(const void *zFilename){
- char *zConverted = 0;
- if( osIsNT() ){
- zConverted = winUnicodeToUtf8(zFilename);
- }
-#ifdef SQLITE_WIN32_HAS_ANSI
- else{
- zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI());
- }
-#endif
- /* caller will handle out of memory */
- return zConverted;
-}
-#endif
-
-/*
-** Convert a UTF-8 filename into whatever form the underlying
-** operating system wants filenames in. Space to hold the result
-** is obtained from malloc and must be freed by the calling
-** function.
-*/
-static void *winConvertFromUtf8Filename(const char *zFilename){
- void *zConverted = 0;
- if( osIsNT() ){
- zConverted = winUtf8ToUnicode(zFilename);
- }
-#ifdef SQLITE_WIN32_HAS_ANSI
- else{
- zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
- }
-#endif
- /* caller will handle out of memory */
- return zConverted;
-}
-
/*
** This function returns non-zero if the specified UTF-8 string buffer
** ends with a directory separator character or one was successfully
@@ -51371,7 +52241,14 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){
if( winIsDirSep(zBuf[nLen-1]) ){
return 1;
}else if( nLen+1<nBuf ){
- zBuf[nLen] = winGetDirSep();
+ if( !osGetenv ){
+ zBuf[nLen] = winGetDirSep();
+ }else if( winIsDriveLetterAndColon(zBuf) && winIsDirSep(zBuf[2]) ){
+ zBuf[nLen] = '\\';
+ zBuf[2]='\\';
+ }else{
+ zBuf[nLen] = '/';
+ }
zBuf[nLen+1] = '\0';
return 1;
}
@@ -51398,14 +52275,14 @@ static int winTempDirDefined(void){
** The pointer returned in pzBuf must be freed via sqlite3_free().
*/
static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
- static char zChars[] =
+ static const char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
size_t i, j;
DWORD pid;
int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
- int nMax, nBuf, nDir, nLen;
+ i64 nMax, nBuf, nDir, nLen;
char *zBuf;
/* It's odd to simulate an io-error here, but really this is just
@@ -51417,7 +52294,8 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
/* Allocate a temporary buffer to store the fully qualified file
** name for the temporary file. If this fails, we cannot continue.
*/
- nMax = pVfs->mxPathname; nBuf = nMax + 2;
+ nMax = pVfs->mxPathname;
+ nBuf = 2 + (i64)nMax;
zBuf = sqlite3MallocZero( nBuf );
if( !zBuf ){
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
@@ -51448,7 +52326,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
}
#if defined(__CYGWIN__)
- else{
+ else if( osGetenv!=NULL ){
static const char *azDirs[] = {
0, /* getenv("SQLITE_TMPDIR") */
0, /* getenv("TMPDIR") */
@@ -51464,11 +52342,11 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
unsigned int i;
const char *zDir = 0;
- if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
- if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
- if( !azDirs[2] ) azDirs[2] = getenv("TMP");
- if( !azDirs[3] ) azDirs[3] = getenv("TEMP");
- if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE");
+ if( !azDirs[0] ) azDirs[0] = osGetenv("SQLITE_TMPDIR");
+ if( !azDirs[1] ) azDirs[1] = osGetenv("TMPDIR");
+ if( !azDirs[2] ) azDirs[2] = osGetenv("TMP");
+ if( !azDirs[3] ) azDirs[3] = osGetenv("TEMP");
+ if( !azDirs[4] ) azDirs[4] = osGetenv("USERPROFILE");
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
void *zConverted;
if( zDir==0 ) continue;
@@ -51477,7 +52355,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
** it must be converted to a native Win32 path via the Cygwin API
** prior to using it.
*/
- if( winIsDriveLetterAndColon(zDir) ){
+ {
zConverted = winConvertFromUtf8Filename(zDir);
if( !zConverted ){
sqlite3_free(zBuf);
@@ -51490,44 +52368,12 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
break;
}
sqlite3_free(zConverted);
- }else{
- zConverted = sqlite3MallocZero( nMax+1 );
- if( !zConverted ){
- sqlite3_free(zBuf);
- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
- }
- if( cygwin_conv_path(
- osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir,
- zConverted, nMax+1)<0 ){
- sqlite3_free(zConverted);
- sqlite3_free(zBuf);
- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_CONVPATH\n"));
- return winLogError(SQLITE_IOERR_CONVPATH, (DWORD)errno,
- "winGetTempname2", zDir);
- }
- if( winIsDir(zConverted) ){
- /* At this point, we know the candidate directory exists and should
- ** be used. However, we may need to convert the string containing
- ** its name into UTF-8 (i.e. if it is UTF-16 right now).
- */
- char *zUtf8 = winConvertToUtf8Filename(zConverted);
- if( !zUtf8 ){
- sqlite3_free(zConverted);
- sqlite3_free(zBuf);
- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
- }
- sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
- sqlite3_free(zUtf8);
- sqlite3_free(zConverted);
- break;
- }
- sqlite3_free(zConverted);
}
}
}
-#elif !SQLITE_OS_WINRT && !defined(__CYGWIN__)
+#endif
+
+#if !SQLITE_OS_WINRT && defined(_WIN32)
else if( osIsNT() ){
char *zMulti;
LPWSTR zWidePath = sqlite3MallocZero( nMax*sizeof(WCHAR) );
@@ -51651,7 +52497,7 @@ static int winIsDir(const void *zConverted){
return 0; /* Invalid name? */
}
attr = sAttrData.dwFileAttributes;
-#if SQLITE_OS_WINCE==0
+#if SQLITE_OS_WINCE==0 && defined(SQLITE_WIN32_HAS_ANSI)
}else{
attr = osGetFileAttributesA((char*)zConverted);
#endif
@@ -51668,6 +52514,12 @@ static int winAccess(
);
/*
+** The Windows version of xAccess() accepts an extra bit in the flags
+** parameter that prevents an anti-virus retry loop.
+*/
+#define NORETRY 0x4000
+
+/*
** Open a file.
*/
static int winOpen(
@@ -51691,6 +52543,7 @@ static int winOpen(
void *zConverted; /* Filename in OS encoding */
const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
int cnt = 0;
+ int isRO = 0; /* file is known to be accessible readonly */
/* If argument zPath is a NULL pointer, this function is required to open
** a temporary file. Use this buffer to store the file name in.
@@ -51699,7 +52552,7 @@ static int winOpen(
int rc = SQLITE_OK; /* Function Return Code */
#if !defined(NDEBUG) || SQLITE_OS_WINCE
- int eType = flags&0xFFFFFF00; /* Type of file to open */
+ int eType = flags&0x0FFF00; /* Type of file to open */
#endif
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
@@ -51855,9 +52708,9 @@ static int winOpen(
&extendedParameters);
if( h!=INVALID_HANDLE_VALUE ) break;
if( isReadWrite ){
- int rc2, isRO = 0;
+ int rc2;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -51872,9 +52725,9 @@ static int winOpen(
NULL);
if( h!=INVALID_HANDLE_VALUE ) break;
if( isReadWrite ){
- int rc2, isRO = 0;
+ int rc2;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -51892,9 +52745,9 @@ static int winOpen(
NULL);
if( h!=INVALID_HANDLE_VALUE ) break;
if( isReadWrite ){
- int rc2, isRO = 0;
+ int rc2;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -51909,7 +52762,7 @@ static int winOpen(
if( h==INVALID_HANDLE_VALUE ){
sqlite3_free(zConverted);
sqlite3_free(zTmpname);
- if( isReadWrite && !isExclusive ){
+ if( isReadWrite && isRO && !isExclusive ){
return winOpen(pVfs, zName, id,
((flags|SQLITE_OPEN_READONLY) &
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
@@ -52111,8 +52964,14 @@ static int winAccess(
int rc = 0;
DWORD lastErrno = 0;
void *zConverted;
+ int noRetry = 0; /* Do not use winRetryIoerr() */
UNUSED_PARAMETER(pVfs);
+ if( (flags & NORETRY)!=0 ){
+ noRetry = 1;
+ flags &= ~NORETRY;
+ }
+
SimulateIOError( return SQLITE_IOERR_ACCESS; );
OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
zFilename, flags, pResOut));
@@ -52135,7 +52994,10 @@ static int winAccess(
memset(&sAttrData, 0, sizeof(sAttrData));
while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
GetFileExInfoStandard,
- &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
+ &sAttrData))
+ && !noRetry
+ && winRetryIoerr(&cnt, &lastErrno)
+ ){ /* Loop until true */}
if( rc ){
/* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
** as if it does not exist.
@@ -52203,6 +53065,7 @@ static BOOL winIsDriveLetterAndColon(
return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' );
}
+#ifdef _WIN32
/*
** Returns non-zero if the specified path name should be used verbatim. If
** non-zero is returned from this function, the calling function must simply
@@ -52239,6 +53102,70 @@ static BOOL winIsVerbatimPathname(
*/
return FALSE;
}
+#endif /* _WIN32 */
+
+#ifdef __CYGWIN__
+/*
+** Simplify a filename into its canonical form
+** by making the following changes:
+**
+** * convert any '/' to '\' (win32) or reverse (Cygwin)
+** * removing any trailing and duplicate / (except for UNC paths)
+** * convert /./ into just /
+**
+** Changes are made in-place. Return the new name length.
+**
+** The original filename is in z[0..]. If the path is shortened,
+** no-longer used bytes will be written by '\0'.
+*/
+static void winSimplifyName(char *z){
+ int i, j;
+ for(i=j=0; z[i]; ++i){
+ if( winIsDirSep(z[i]) ){
+#if !defined(SQLITE_TEST)
+ /* Some test-cases assume that "./foo" and "foo" are different */
+ if( z[i+1]=='.' && winIsDirSep(z[i+2]) ){
+ ++i;
+ continue;
+ }
+#endif
+ if( !z[i+1] || (winIsDirSep(z[i+1]) && (i!=0)) ){
+ continue;
+ }
+ z[j++] = osGetenv?'/':'\\';
+ }else{
+ z[j++] = z[i];
+ }
+ }
+ while(j<i) z[j++] = '\0';
+}
+
+#define SQLITE_MAX_SYMLINKS 100
+
+static int mkFullPathname(
+ const char *zPath, /* Input path */
+ char *zOut, /* Output buffer */
+ int nOut /* Allocated size of buffer zOut */
+){
+ int nPath = sqlite3Strlen30(zPath);
+ int iOff = 0;
+ if( zPath[0]!='/' ){
+ if( osGetcwd(zOut, nOut-2)==0 ){
+ return winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "getcwd", zPath);
+ }
+ iOff = sqlite3Strlen30(zOut);
+ zOut[iOff++] = '/';
+ }
+ if( (iOff+nPath+1)>nOut ){
+ /* SQLite assumes that xFullPathname() nul-terminates the output buffer
+ ** even if it returns an error. */
+ zOut[iOff] = '\0';
+ return SQLITE_CANTOPEN_BKPT;
+ }
+ sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
+ return SQLITE_OK;
+}
+#endif /* __CYGWIN__ */
/*
** Turn a relative pathname into a full pathname. Write the full
@@ -52251,8 +53178,8 @@ static int winFullPathnameNoMutex(
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
- DWORD nByte;
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+ int nByte;
void *zConverted;
char *zOut;
#endif
@@ -52265,64 +53192,82 @@ static int winFullPathnameNoMutex(
zRelative++;
}
-#if defined(__CYGWIN__)
SimulateIOError( return SQLITE_ERROR );
- UNUSED_PARAMETER(nFull);
- assert( nFull>=pVfs->mxPathname );
- if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
- /*
- ** NOTE: We are dealing with a relative path name and the data
- ** directory has been set. Therefore, use it as the basis
- ** for converting the relative path name to an absolute
- ** one by prepending the data directory and a slash.
- */
- char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
- if( !zOut ){
- return SQLITE_IOERR_NOMEM_BKPT;
- }
- if( cygwin_conv_path(
- (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
- CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){
- sqlite3_free(zOut);
- return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
- "winFullPathname1", zRelative);
- }else{
- char *zUtf8 = winConvertToUtf8Filename(zOut);
- if( !zUtf8 ){
- sqlite3_free(zOut);
- return SQLITE_IOERR_NOMEM_BKPT;
- }
- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
- sqlite3_data_directory, winGetDirSep(), zUtf8);
- sqlite3_free(zUtf8);
- sqlite3_free(zOut);
- }
- }else{
- char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
- if( !zOut ){
- return SQLITE_IOERR_NOMEM_BKPT;
- }
- if( cygwin_conv_path(
- (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
- zRelative, zOut, pVfs->mxPathname+1)<0 ){
- sqlite3_free(zOut);
- return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
- "winFullPathname2", zRelative);
- }else{
- char *zUtf8 = winConvertToUtf8Filename(zOut);
- if( !zUtf8 ){
- sqlite3_free(zOut);
- return SQLITE_IOERR_NOMEM_BKPT;
- }
- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
- sqlite3_free(zUtf8);
- sqlite3_free(zOut);
+
+#ifdef __CYGWIN__
+ if( osGetcwd ){
+ zFull[nFull-1] = '\0';
+ if( !winIsDriveLetterAndColon(zRelative) || !winIsDirSep(zRelative[2]) ){
+ int rc = SQLITE_OK;
+ int nLink = 1; /* Number of symbolic links followed so far */
+ const char *zIn = zRelative; /* Input path for each iteration of loop */
+ char *zDel = 0;
+ struct stat buf;
+
+ UNUSED_PARAMETER(pVfs);
+
+ do {
+ /* Call lstat() on path zIn. Set bLink to true if the path is a symbolic
+ ** link, or false otherwise. */
+ int bLink = 0;
+ if( osLstat && osReadlink ) {
+ if( osLstat(zIn, &buf)!=0 ){
+ int myErrno = osErrno;
+ if( myErrno!=ENOENT ){
+ rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)myErrno, "lstat", zIn);
+ }
+ }else{
+ bLink = ((buf.st_mode & 0170000) == 0120000);
+ }
+
+ if( bLink ){
+ if( zDel==0 ){
+ zDel = sqlite3MallocZero(nFull);
+ if( zDel==0 ) rc = SQLITE_NOMEM;
+ }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ }
+
+ if( rc==SQLITE_OK ){
+ nByte = osReadlink(zIn, zDel, nFull-1);
+ if( nByte ==(DWORD)-1 ){
+ rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "readlink", zIn);
+ }else{
+ if( zDel[0]!='/' ){
+ int n;
+ for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
+ if( nByte+n+1>nFull ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ }else{
+ memmove(&zDel[n], zDel, nByte+1);
+ memcpy(zDel, zIn, n);
+ nByte += n;
+ }
+ }
+ zDel[nByte] = '\0';
+ }
+ }
+
+ zIn = zDel;
+ }
+ }
+
+ assert( rc!=SQLITE_OK || zIn!=zFull || zIn[0]=='/' );
+ if( rc==SQLITE_OK && zIn!=zFull ){
+ rc = mkFullPathname(zIn, zFull, nFull);
+ }
+ if( bLink==0 ) break;
+ zIn = zFull;
+ }while( rc==SQLITE_OK );
+
+ sqlite3_free(zDel);
+ winSimplifyName(zFull);
+ return rc;
}
}
- return SQLITE_OK;
-#endif
+#endif /* __CYGWIN__ */
-#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
+#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && defined(_WIN32)
SimulateIOError( return SQLITE_ERROR );
/* WinCE has no concept of a relative pathname, or so I am told. */
/* WinRT has no way to convert a relative path to an absolute one. */
@@ -52341,7 +53286,8 @@ static int winFullPathnameNoMutex(
return SQLITE_OK;
#endif
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
+#if defined(_WIN32)
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
** function failing. This function could fail if, for example, the
@@ -52359,6 +53305,7 @@ static int winFullPathnameNoMutex(
sqlite3_data_directory, winGetDirSep(), zRelative);
return SQLITE_OK;
}
+#endif
zConverted = winConvertFromUtf8Filename(zRelative);
if( zConverted==0 ){
return SQLITE_IOERR_NOMEM_BKPT;
@@ -52397,13 +53344,12 @@ static int winFullPathnameNoMutex(
return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
"winFullPathname3", zRelative);
}
- nByte += 3;
- zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
+ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) + 3*sizeof(zTemp[0]) );
if( zTemp==0 ){
sqlite3_free(zConverted);
return SQLITE_IOERR_NOMEM_BKPT;
}
- nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+ nByte = osGetFullPathNameA((char*)zConverted, nByte+3, zTemp, 0);
if( nByte==0 ){
sqlite3_free(zConverted);
sqlite3_free(zTemp);
@@ -52416,7 +53362,26 @@ static int winFullPathnameNoMutex(
}
#endif
if( zOut ){
+#ifdef __CYGWIN__
+ if( memcmp(zOut, "\\\\?\\", 4) ){
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
+ }else if( memcmp(zOut+4, "UNC\\", 4) ){
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+4);
+ }else{
+ char *p = zOut+6;
+ *p = '\\';
+ if( osGetcwd ){
+ /* On Cygwin, UNC paths use forward slashes */
+ while( *p ){
+ if( *p=='\\' ) *p = '/';
+ ++p;
+ }
+ }
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+6);
+ }
+#else
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
+#endif /* __CYGWIN__ */
sqlite3_free(zOut);
return SQLITE_OK;
}else{
@@ -52446,25 +53411,8 @@ static int winFullPathname(
*/
static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
HANDLE h;
-#if defined(__CYGWIN__)
- int nFull = pVfs->mxPathname+1;
- char *zFull = sqlite3MallocZero( nFull );
- void *zConverted = 0;
- if( zFull==0 ){
- OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
- return 0;
- }
- if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){
- sqlite3_free(zFull);
- OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
- return 0;
- }
- zConverted = winConvertFromUtf8Filename(zFull);
- sqlite3_free(zFull);
-#else
void *zConverted = winConvertFromUtf8Filename(zFilename);
UNUSED_PARAMETER(pVfs);
-#endif
if( zConverted==0 ){
OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
return 0;
@@ -52813,7 +53761,7 @@ SQLITE_API int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==80 );
+ assert( ArraySize(aSyscall)==89 );
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
@@ -53432,13 +54380,13 @@ static int memdbOpen(
}
if( p==0 ){
MemStore **apNew;
- p = sqlite3Malloc( sizeof(*p) + szName + 3 );
+ p = sqlite3Malloc( sizeof(*p) + (i64)szName + 3 );
if( p==0 ){
sqlite3_mutex_leave(pVfsMutex);
return SQLITE_NOMEM;
}
apNew = sqlite3Realloc(memdb_g.apMemStore,
- sizeof(apNew[0])*(memdb_g.nMemStore+1) );
+ sizeof(apNew[0])*(1+(i64)memdb_g.nMemStore) );
if( apNew==0 ){
sqlite3_free(p);
sqlite3_mutex_leave(pVfsMutex);
@@ -53871,7 +54819,7 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void){
** no fewer collisions than the no-op *1. */
#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT)
-#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *))
+#define BITVEC_NPTR ((u32)(BITVEC_USIZE/sizeof(Bitvec *)))
/*
@@ -54020,7 +54968,9 @@ bitvec_set_rehash:
}else{
memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
memset(p->u.apSub, 0, sizeof(p->u.apSub));
- p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR;
+ p->iDivisor = p->iSize/BITVEC_NPTR;
+ if( (p->iSize%BITVEC_NPTR)!=0 ) p->iDivisor++;
+ if( p->iDivisor<BITVEC_NBIT ) p->iDivisor = BITVEC_NBIT;
rc = sqlite3BitvecSet(p, i);
for(j=0; j<BITVEC_NINT; j++){
if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]);
@@ -54054,7 +55004,7 @@ SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){
}
}
if( p->iSize<=BITVEC_NBIT ){
- p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1)));
+ p->u.aBitmap[i/BITVEC_SZELEM] &= ~(BITVEC_TELEM)(1<<(i&(BITVEC_SZELEM-1)));
}else{
unsigned int j;
u32 *aiValues = pBuf;
@@ -54105,7 +55055,7 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){
** individual bits within V.
*/
#define SETBIT(V,I) V[I>>3] |= (1<<(I&7))
-#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7))
+#define CLEARBIT(V,I) V[I>>3] &= ~(BITVEC_TELEM)(1<<(I&7))
#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0
/*
@@ -54148,7 +55098,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
/* Allocate the Bitvec to be tested and a linear array of
** bits to act as the reference */
pBitvec = sqlite3BitvecCreate( sz );
- pV = sqlite3MallocZero( (sz+7)/8 + 1 );
+ pV = sqlite3MallocZero( (7+(i64)sz)/8 + 1 );
pTmpSpace = sqlite3_malloc64(BITVEC_SZ);
if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end;
@@ -54730,6 +55680,7 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
pPgHdr->pData = pPage->pBuf;
pPgHdr->pExtra = (void *)&pPgHdr[1];
memset(pPgHdr->pExtra, 0, 8);
+ assert( EIGHT_BYTE_ALIGNMENT( pPgHdr->pExtra ) );
pPgHdr->pCache = pCache;
pPgHdr->pgno = pgno;
pPgHdr->flags = PGHDR_CLEAN;
@@ -55388,10 +56339,6 @@ static SQLITE_WSD struct PCacheGlobal {
sqlite3_mutex *mutex; /* Mutex for accessing the following: */
PgFreeslot *pFree; /* Free page blocks */
int nFreeSlot; /* Number of unused pcache slots */
- /* The following value requires a mutex to change. We skip the mutex on
- ** reading because (1) most platforms read a 32-bit integer atomically and
- ** (2) even if an incorrect value is read, no great harm is done since this
- ** is really just an optimization. */
int bUnderPressure; /* True if low on PAGECACHE memory */
} pcache1_g;
@@ -55439,7 +56386,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
pcache1.pStart = pBuf;
pcache1.pFree = 0;
- pcache1.bUnderPressure = 0;
+ AtomicStore(&pcache1.bUnderPressure,0);
while( n-- ){
p = (PgFreeslot*)pBuf;
p->pNext = pcache1.pFree;
@@ -55476,7 +56423,8 @@ static int pcache1InitBulk(PCache1 *pCache){
do{
PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
pX->page.pBuf = zBulk;
- pX->page.pExtra = &pX[1];
+ pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX));
+ assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) );
pX->isBulkLocal = 1;
pX->isAnchor = 0;
pX->pNext = pCache->pFree;
@@ -55506,7 +56454,7 @@ static void *pcache1Alloc(int nByte){
if( p ){
pcache1.pFree = pcache1.pFree->pNext;
pcache1.nFreeSlot--;
- pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
+ AtomicStore(&pcache1.bUnderPressure,pcache1.nFreeSlot<pcache1.nReserve);
assert( pcache1.nFreeSlot>=0 );
sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
@@ -55545,7 +56493,7 @@ static void pcache1Free(void *p){
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
pcache1.nFreeSlot++;
- pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
+ AtomicStore(&pcache1.bUnderPressure,pcache1.nFreeSlot<pcache1.nReserve);
assert( pcache1.nFreeSlot<=pcache1.nSlot );
sqlite3_mutex_leave(pcache1.mutex);
}else{
@@ -55613,7 +56561,8 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
if( pPg==0 ) return 0;
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
p->page.pBuf = pPg;
- p->page.pExtra = &p[1];
+ p->page.pExtra = (u8*)p + ROUND8(sizeof(*p));
+ assert( EIGHT_BYTE_ALIGNMENT( p->page.pExtra ) );
p->isBulkLocal = 0;
p->isAnchor = 0;
p->pLruPrev = 0; /* Initializing this saves a valgrind error */
@@ -55675,7 +56624,7 @@ SQLITE_PRIVATE void sqlite3PageFree(void *p){
*/
static int pcache1UnderMemoryPressure(PCache1 *pCache){
if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){
- return pcache1.bUnderPressure;
+ return AtomicLoad(&pcache1.bUnderPressure);
}else{
return sqlite3HeapNearlyFull();
}
@@ -55692,12 +56641,12 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){
*/
static void pcache1ResizeHash(PCache1 *p){
PgHdr1 **apNew;
- unsigned int nNew;
- unsigned int i;
+ u64 nNew;
+ u32 i;
assert( sqlite3_mutex_held(p->pGroup->mutex) );
- nNew = p->nHash*2;
+ nNew = 2*(u64)p->nHash;
if( nNew<256 ){
nNew = 256;
}
@@ -55920,7 +56869,7 @@ static void pcache1Destroy(sqlite3_pcache *p);
static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
PCache1 *pCache; /* The newly created page cache */
PGroup *pGroup; /* The group the new page cache will belong to */
- int sz; /* Bytes of memory required to allocate the new cache */
+ i64 sz; /* Bytes of memory required to allocate the new cache */
assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
assert( szExtra < 300 );
@@ -57808,6 +58757,9 @@ struct Pager {
Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */
char *zWal; /* File name for write-ahead log */
#endif
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ sqlite3 *dbWal;
+#endif
};
/*
@@ -57897,39 +58849,33 @@ static const unsigned char aJournalMagic[] = {
# define USEFETCH(x) 0
#endif
-/*
-** 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.
-**
-** This is so that expressions can be written as:
-**
-** if( isOpen(pPager->jfd) ){ ...
-**
-** instead of
-**
-** if( pPager->jfd->pMethods ){ ...
-*/
-#define isOpen(pFd) ((pFd)->pMethods!=0)
-
#ifdef SQLITE_DIRECT_OVERFLOW_READ
/*
** 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.
+** (1) the database file is open
+** (2) the VFS for the database is able to do unaligned sub-page reads
+** (3) there are no dirty pages in the cache, and
+** (4) 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;
+ assert( pPager!=0 );
+ assert( pPager->fd!=0 );
+ if( pPager->fd->pMethods==0 ) return 0; /* Case (1) */
+ if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */
#ifndef SQLITE_OMIT_WAL
if( pPager->pWal ){
u32 iRead = 0;
(void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
- return iRead==0;
+ if( iRead ) return 0; /* Case (4) */
}
#endif
+ assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 );
+ if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd)
+ & SQLITE_IOCAP_SUBPAGE_READ)==0 ){
+ return 0; /* Case (2) */
+ }
return 1;
}
#endif
@@ -58405,7 +59351,7 @@ static void checkPage(PgHdr *pPg){
** If an error occurs while reading from the journal file, an SQLite
** error code is returned.
*/
-static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){
+static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u64 nSuper){
int rc; /* Return code */
u32 len; /* Length in bytes of super-journal name */
i64 szJ; /* Total size in bytes of journal file pJrnl */
@@ -58960,6 +59906,15 @@ static void pager_unlock(Pager *pPager){
if( pagerUseWal(pPager) ){
assert( !isOpen(pPager->jfd) );
+ if( pPager->eState==PAGER_ERROR ){
+ /* If an IO error occurs in wal.c while attempting to wrap the wal file,
+ ** then the Wal object may be holding a write-lock but no read-lock.
+ ** This call ensures that the write-lock is dropped as well. We cannot
+ ** have sqlite3WalEndReadTransaction() drop the write-lock, as it once
+ ** did, because this would break "BEGIN EXCLUSIVE" handling for
+ ** SQLITE_ENABLE_SETLK_TIMEOUT builds. */
+ sqlite3WalEndWriteTransaction(pPager->pWal);
+ }
sqlite3WalEndReadTransaction(pPager->pWal);
pPager->eState = PAGER_OPEN;
}else if( !pPager->exclusiveMode ){
@@ -59188,7 +60143,7 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
}
pPager->journalOff = 0;
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
- || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
+ || (pPager->exclusiveMode && pPager->journalMode<PAGER_JOURNALMODE_WAL)
){
rc = zeroJournalHdr(pPager, hasSuper||pPager->tempFile);
pPager->journalOff = 0;
@@ -59641,12 +60596,12 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
char *zJournal; /* Pointer to one journal within MJ file */
char *zSuperPtr; /* Space to hold super-journal filename */
char *zFree = 0; /* Free this buffer */
- int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
+ i64 nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
/* Allocate space for both the pJournal and pSuper file descriptors.
** If successful, open the super-journal file for reading.
*/
- pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
+ pSuper = (sqlite3_file *)sqlite3MallocZero(2 * (i64)pVfs->szOsFile);
if( !pSuper ){
rc = SQLITE_NOMEM_BKPT;
pJournal = 0;
@@ -59664,11 +60619,14 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
*/
rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
if( rc!=SQLITE_OK ) goto delsuper_out;
- nSuperPtr = pVfs->mxPathname+1;
+ nSuperPtr = 1 + (i64)pVfs->mxPathname;
+ assert( nSuperJournal>=0 && nSuperPtr>0 );
zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2);
if( !zFree ){
rc = SQLITE_NOMEM_BKPT;
goto delsuper_out;
+ }else{
+ assert( nSuperJournal<=0x7fffffff );
}
zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0;
zSuperJournal = &zFree[4];
@@ -59929,7 +60887,7 @@ static int pager_playback(Pager *pPager, int isHot){
** for pageSize.
*/
zSuper = pPager->pTmpSpace;
- rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
+ rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname);
if( rc==SQLITE_OK && zSuper[0] ){
rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
}
@@ -60068,7 +61026,7 @@ end_playback:
** which case it requires 4 0x00 bytes in memory immediately before
** the filename. */
zSuper = &pPager->pTmpSpace[4];
- rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
+ rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname);
testcase( rc!=SQLITE_OK );
}
if( rc==SQLITE_OK
@@ -61172,6 +62130,7 @@ static int pagerAcquireMapPage(
return SQLITE_NOMEM_BKPT;
}
p->pExtra = (void *)&p[1];
+ assert( EIGHT_BYTE_ALIGNMENT( p->pExtra ) );
p->flags = PGHDR_MMAP;
p->nRef = 1;
p->pPager = pPager;
@@ -61838,6 +62797,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
const char *zUri = 0; /* URI args to copy */
int nUriByte = 1; /* Number of bytes of URI args at *zUri */
+
/* Figure out how much space is required for each journal file-handle
** (there are two of them, the main journal and the sub-journal). */
journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
@@ -61863,8 +62823,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
*/
if( zFilename && zFilename[0] ){
const char *z;
- nPathname = pVfs->mxPathname+1;
- zPathname = sqlite3DbMallocRaw(0, nPathname*2);
+ nPathname = pVfs->mxPathname + 1;
+ zPathname = sqlite3DbMallocRaw(0, 2*(i64)nPathname);
if( zPathname==0 ){
return SQLITE_NOMEM_BKPT;
}
@@ -61951,14 +62911,14 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
ROUND8(sizeof(*pPager)) + /* Pager structure */
ROUND8(pcacheSize) + /* PCache object */
ROUND8(pVfs->szOsFile) + /* The main db file */
- journalFileSize * 2 + /* The two journal files */
+ (u64)journalFileSize * 2 + /* The two journal files */
SQLITE_PTRSIZE + /* Space to hold a pointer */
4 + /* Database prefix */
- nPathname + 1 + /* database filename */
- nUriByte + /* query parameters */
- nPathname + 8 + 1 + /* Journal filename */
+ (u64)nPathname + 1 + /* database filename */
+ (u64)nUriByte + /* query parameters */
+ (u64)nPathname + 8 + 1 + /* Journal filename */
#ifndef SQLITE_OMIT_WAL
- nPathname + 4 + 1 + /* WAL filename */
+ (u64)nPathname + 4 + 1 + /* WAL filename */
#endif
3 /* Terminator */
);
@@ -64681,6 +65641,11 @@ static int pagerOpenWal(Pager *pPager){
pPager->fd, pPager->zWal, pPager->exclusiveMode,
pPager->journalSizeLimit, &pPager->pWal
);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_OK ){
+ sqlite3WalDb(pPager->pWal, pPager->dbWal);
+ }
+#endif
}
pagerFixMaplimit(pPager);
@@ -64800,6 +65765,7 @@ SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
** blocking locks are required.
*/
SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
+ pPager->dbWal = db;
if( pagerUseWal(pPager) ){
sqlite3WalDb(pPager->pWal, db);
}
@@ -64955,7 +65921,7 @@ SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){
** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
**
** 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
+** frame consists of a 24-byte frame-header followed by <page-size> bytes
** of page data. The frame-header is six big-endian 32-bit unsigned
** integer values, as follows:
**
@@ -65413,6 +66379,11 @@ struct WalCkptInfo {
/*
** An open write-ahead log file is represented by an instance of the
** following object.
+**
+** writeLock:
+** This is usually set to 1 whenever the WRITER lock is held. However,
+** if it is set to 2, then the WRITER lock is held but must be released
+** by walHandleException() if a SEH exception is thrown.
*/
struct Wal {
sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
@@ -65452,6 +66423,7 @@ struct Wal {
#endif
#ifdef SQLITE_ENABLE_SNAPSHOT
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
+ int bGetSnapshot; /* Transaction opened for sqlite3_get_snapshot() */
#endif
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
sqlite3 *db;
@@ -65502,9 +66474,13 @@ struct WalIterator {
u32 *aPgno; /* Array of page numbers. */
int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */
int iZero; /* Frame number associated with aPgno[0] */
- } aSegment[1]; /* One for every 32KB page in the wal-index */
+ } aSegment[FLEXARRAY]; /* One for every 32KB page in the wal-index */
};
+/* Size (in bytes) of a WalIterator object suitable for N or fewer segments */
+#define SZ_WALITERATOR(N) \
+ (offsetof(WalIterator,aSegment)*(N)*sizeof(struct WalSegment))
+
/*
** Define the parameters of the hash tables in the wal-index file. There
** is a hash-table following every HASHTABLE_NPAGE page numbers in the
@@ -65663,7 +66639,7 @@ static SQLITE_NOINLINE int walIndexPageRealloc(
/* Enlarge the pWal->apWiData[] array if required */
if( pWal->nWiData<=iPage ){
- sqlite3_int64 nByte = sizeof(u32*)*(iPage+1);
+ sqlite3_int64 nByte = sizeof(u32*)*(1+(i64)iPage);
volatile u32 **apNew;
apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte);
if( !apNew ){
@@ -65772,10 +66748,8 @@ static void walChecksumBytes(
s1 = s2 = 0;
}
- assert( nByte>=8 );
- assert( (nByte&0x00000007)==0 );
- assert( nByte<=65536 );
- assert( nByte%4==0 );
+ /* nByte is a multiple of 8 between 8 and 65536 */
+ assert( nByte>=8 && (nByte&7)==0 && nByte<=65536 );
if( !nativeCksum ){
do {
@@ -66865,8 +67839,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
/* Allocate space for the WalIterator object. */
nSegment = walFramePage(iLast) + 1;
- nByte = sizeof(WalIterator)
- + (nSegment-1)*sizeof(struct WalSegment)
+ nByte = SZ_WALITERATOR(nSegment)
+ iLast*sizeof(ht_slot);
p = (WalIterator *)sqlite3_malloc64(nByte
+ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
@@ -66937,7 +67910,7 @@ static int walEnableBlockingMs(Wal *pWal, int nMs){
static int walEnableBlocking(Wal *pWal){
int res = 0;
if( pWal->db ){
- int tmout = pWal->db->busyTimeout;
+ int tmout = pWal->db->setlkTimeout;
if( tmout ){
res = walEnableBlockingMs(pWal, tmout);
}
@@ -67323,7 +68296,9 @@ static int walHandleException(Wal *pWal){
static const int S = 1;
static const int E = (1<<SQLITE_SHM_NLOCK);
int ii;
- u32 mUnlock = pWal->lockMask & ~(
+ u32 mUnlock;
+ if( pWal->writeLock==2 ) pWal->writeLock = 0;
+ mUnlock = pWal->lockMask & ~(
(pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
| (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
| (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
@@ -67344,7 +68319,7 @@ static int walHandleException(Wal *pWal){
/*
** Assert that the Wal.lockMask mask, which indicates the locks held
-** by the connenction, is consistent with the Wal.readLock, Wal.writeLock
+** by the connection, is consistent with the Wal.readLock, Wal.writeLock
** and Wal.ckptLock variables. To be used as:
**
** assert( walAssertLockmask(pWal) );
@@ -67595,7 +68570,12 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
if( bWriteLock
|| SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1))
){
- pWal->writeLock = 1;
+ /* If the write-lock was just obtained, set writeLock to 2 instead of
+ ** the usual 1. This causes walIndexPage() to behave as if the
+ ** write-lock were held (so that it allocates new pages as required),
+ ** and walHandleException() to unlock the write-lock if a SEH exception
+ ** is thrown. */
+ if( !bWriteLock ) pWal->writeLock = 2;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
if( badHdr ){
@@ -67896,11 +68876,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
*/
static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
- u32 mxReadMark; /* Largest aReadMark[] value */
- int mxI; /* Index of largest aReadMark[] value */
- int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
- u32 mxFrame; /* Wal frame to lock to */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
int nBlockTmout = 0;
#endif
@@ -67963,7 +68939,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
rc = walIndexReadHdr(pWal, pChanged);
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- walDisableBlocking(pWal);
if( rc==SQLITE_BUSY_TIMEOUT ){
rc = SQLITE_BUSY;
*pCnt |= WAL_RETRY_BLOCKED_MASK;
@@ -67978,6 +68953,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
** WAL_RETRY this routine will be called again and will probably be
** right on the second iteration.
*/
+ (void)walEnableBlocking(pWal);
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
@@ -67994,6 +68970,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
rc = SQLITE_BUSY_RECOVERY;
}
}
+ walDisableBlocking(pWal);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -68006,141 +68983,147 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
assert( pWal->apWiData[0]!=0 );
pInfo = walCkptInfo(pWal);
SEH_INJECT_FAULT;
- if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
+ {
+ u32 mxReadMark; /* Largest aReadMark[] value */
+ int mxI; /* Index of largest aReadMark[] value */
+ int i; /* Loop counter */
+ u32 mxFrame; /* Wal frame to lock to */
+ if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
#ifdef SQLITE_ENABLE_SNAPSHOT
- && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
+ && ((pWal->bGetSnapshot==0 && pWal->pSnapshot==0) || pWal->hdr.mxFrame==0)
#endif
- ){
- /* The WAL has been completely backfilled (or it is empty).
- ** and can be safely ignored.
- */
- rc = walLockShared(pWal, WAL_READ_LOCK(0));
- walShmBarrier(pWal);
- if( rc==SQLITE_OK ){
- if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
- /* It is not safe to allow the reader to continue here if frames
- ** may have been appended to the log before READ_LOCK(0) was obtained.
- ** When holding READ_LOCK(0), the reader ignores the entire log file,
- ** which implies that the database file contains a trustworthy
- ** 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
- ** 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
- ** it finished. Leaving a corrupt image in the database file.
- */
- walUnlockShared(pWal, WAL_READ_LOCK(0));
- return WAL_RETRY;
+ ){
+ /* The WAL has been completely backfilled (or it is empty).
+ ** and can be safely ignored.
+ */
+ rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ walShmBarrier(pWal);
+ if( rc==SQLITE_OK ){
+ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr,sizeof(WalIndexHdr)) ){
+ /* It is not safe to allow the reader to continue here if frames
+ ** may have been appended to the log before READ_LOCK(0) was obtained.
+ ** When holding READ_LOCK(0), the reader ignores the entire log file,
+ ** which implies that the database file contains a trustworthy
+ ** 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
+ ** 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
+ ** it finished. Leaving a corrupt image in the database file.
+ */
+ walUnlockShared(pWal, WAL_READ_LOCK(0));
+ return WAL_RETRY;
+ }
+ pWal->readLock = 0;
+ return SQLITE_OK;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
}
- pWal->readLock = 0;
- return SQLITE_OK;
- }else if( rc!=SQLITE_BUSY ){
- return rc;
}
- }
- /* If we get this far, it means that the reader will want to use
- ** the WAL to get at content from recent commits. The job now is
- ** to select one of the aReadMark[] entries that is closest to
- ** but not exceeding pWal->hdr.mxFrame and lock that entry.
- */
- mxReadMark = 0;
- mxI = 0;
- mxFrame = pWal->hdr.mxFrame;
+ /* If we get this far, it means that the reader will want to use
+ ** the WAL to get at content from recent commits. The job now is
+ ** to select one of the aReadMark[] entries that is closest to
+ ** but not exceeding pWal->hdr.mxFrame and lock that entry.
+ */
+ mxReadMark = 0;
+ mxI = 0;
+ mxFrame = pWal->hdr.mxFrame;
#ifdef SQLITE_ENABLE_SNAPSHOT
- if( pWal->pSnapshot && pWal->pSnapshot->mxFrame<mxFrame ){
- mxFrame = pWal->pSnapshot->mxFrame;
- }
-#endif
- for(i=1; i<WAL_NREADER; i++){
- u32 thisMark = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
- if( mxReadMark<=thisMark && thisMark<=mxFrame ){
- assert( thisMark!=READMARK_NOT_USED );
- mxReadMark = thisMark;
- mxI = i;
+ if( pWal->pSnapshot && pWal->pSnapshot->mxFrame<mxFrame ){
+ mxFrame = pWal->pSnapshot->mxFrame;
}
- }
- if( (pWal->readOnly & WAL_SHM_RDONLY)==0
- && (mxReadMark<mxFrame || mxI==0)
- ){
+#endif
for(i=1; i<WAL_NREADER; i++){
- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
- if( rc==SQLITE_OK ){
- AtomicStore(pInfo->aReadMark+i,mxFrame);
- mxReadMark = mxFrame;
+ u32 thisMark = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
+ if( mxReadMark<=thisMark && thisMark<=mxFrame ){
+ assert( thisMark!=READMARK_NOT_USED );
+ mxReadMark = thisMark;
mxI = i;
- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
- break;
- }else if( rc!=SQLITE_BUSY ){
- return rc;
}
}
- }
- if( mxI==0 ){
- assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
- return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
- }
+ if( (pWal->readOnly & WAL_SHM_RDONLY)==0
+ && (mxReadMark<mxFrame || mxI==0)
+ ){
+ for(i=1; i<WAL_NREADER; i++){
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ AtomicStore(pInfo->aReadMark+i,mxFrame);
+ mxReadMark = mxFrame;
+ mxI = i;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ break;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
+ }
+ }
+ }
+ if( mxI==0 ){
+ assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
+ return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
+ }
- (void)walEnableBlockingMs(pWal, nBlockTmout);
- rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
- walDisableBlocking(pWal);
- if( rc ){
+ (void)walEnableBlockingMs(pWal, nBlockTmout);
+ rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ walDisableBlocking(pWal);
+ if( rc ){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- if( rc==SQLITE_BUSY_TIMEOUT ){
- *pCnt |= WAL_RETRY_BLOCKED_MASK;
- }
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ *pCnt |= WAL_RETRY_BLOCKED_MASK;
+ }
#else
- assert( rc!=SQLITE_BUSY_TIMEOUT );
+ assert( rc!=SQLITE_BUSY_TIMEOUT );
#endif
- assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT );
- return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc;
- }
- /* Now that the read-lock has been obtained, check that neither the
- ** value in the aReadMark[] array or the contents of the wal-index
- ** header have changed.
- **
- ** It is necessary to check that the wal-index header did not change
- ** between the time it was read and when the shared-lock was obtained
- ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
- ** that the log file may have been wrapped by a writer, or that frames
- ** that occur later in the log than pWal->hdr.mxFrame may have been
- ** copied into the database by a checkpointer. If either of these things
- ** happened, then reading the database with the current value of
- ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
- ** instead.
- **
- ** Before checking that the live wal-index header has not changed
- ** since it was read, set Wal.minFrame to the first frame in the wal
- ** file that has not yet been checkpointed. This client will not need
- ** 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
- ** nBackfill and checking that the wal-header in shared-memory still
- ** 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
- ** a version of page X that lies before pWal->minFrame (call that version
- ** A) on the basis that there is a newer version (version B) of the same
- ** page later in the wal file. But if version B happens to like past
- ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
- ** that it can read version A from the database file. However, since
- ** 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 = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT;
- walShmBarrier(pWal);
- if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
- || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
- ){
- walUnlockShared(pWal, WAL_READ_LOCK(mxI));
- return WAL_RETRY;
- }else{
- assert( mxReadMark<=pWal->hdr.mxFrame );
- pWal->readLock = (i16)mxI;
+ assert((rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT);
+ return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc;
+ }
+ /* Now that the read-lock has been obtained, check that neither the
+ ** value in the aReadMark[] array or the contents of the wal-index
+ ** header have changed.
+ **
+ ** It is necessary to check that the wal-index header did not change
+ ** between the time it was read and when the shared-lock was obtained
+ ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
+ ** that the log file may have been wrapped by a writer, or that frames
+ ** that occur later in the log than pWal->hdr.mxFrame may have been
+ ** copied into the database by a checkpointer. If either of these things
+ ** happened, then reading the database with the current value of
+ ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
+ ** instead.
+ **
+ ** Before checking that the live wal-index header has not changed
+ ** since it was read, set Wal.minFrame to the first frame in the wal
+ ** file that has not yet been checkpointed. This client will not need
+ ** 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
+ ** nBackfill and checking that the wal-header in shared-memory still
+ ** 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
+ ** a version of page X that lies before pWal->minFrame (call that version
+ ** A) on the basis that there is a newer version (version B) of the same
+ ** page later in the wal file. But if version B happens to like past
+ ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
+ ** that it can read version A from the database file. However, since
+ ** 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 = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT;
+ walShmBarrier(pWal);
+ if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
+ || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
+ ){
+ walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+ return WAL_RETRY;
+ }else{
+ assert( mxReadMark<=pWal->hdr.mxFrame );
+ pWal->readLock = (i16)mxI;
+ }
}
return rc;
}
@@ -68378,8 +69361,11 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
** read-lock.
*/
SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
- sqlite3WalEndWriteTransaction(pWal);
+#ifndef SQLITE_ENABLE_SETLK_TIMEOUT
+ assert( pWal->writeLock==0 || pWal->readLock<0 );
+#endif
if( pWal->readLock>=0 ){
+ sqlite3WalEndWriteTransaction(pWal);
walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
pWal->readLock = -1;
}
@@ -68572,7 +69558,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
** 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)) );
+ assert( !memcmp(&pWal->hdr,(void*)pWal->apWiData[0],sizeof(WalIndexHdr)) );
return SQLITE_OK;
}
#endif
@@ -68672,6 +69658,7 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p
if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
}
SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ pWal->iReCksum = 0;
}
return rc;
}
@@ -68719,6 +69706,9 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
walCleanupHash(pWal);
}
SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ if( pWal->iReCksum>pWal->hdr.mxFrame ){
+ pWal->iReCksum = 0;
+ }
}
return rc;
@@ -69408,7 +70398,20 @@ SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
Wal *pWal,
sqlite3_snapshot *pSnapshot
){
- pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
+ if( pSnapshot && ((WalIndexHdr*)pSnapshot)->iVersion==0 ){
+ /* iVersion==0 means that this is a call to sqlite3_snapshot_get(). In
+ ** this case set the bGetSnapshot flag so that if the call to
+ ** sqlite3_snapshot_get() is about to read transaction on this wal
+ ** file, it does not take read-lock 0 if the wal file has been completely
+ ** checkpointed. Taking read-lock 0 would work, but then it would be
+ ** possible for a subsequent writer to destroy the snapshot even while
+ ** this connection is holding its read-transaction open. This is contrary
+ ** to user expectations, so we avoid it by not taking read-lock 0. */
+ pWal->bGetSnapshot = 1;
+ }else{
+ pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
+ pWal->bGetSnapshot = 0;
+ }
}
/*
@@ -70009,6 +71012,12 @@ struct CellInfo {
#define BTCURSOR_MAX_DEPTH 20
/*
+** Maximum amount of storage local to a database page, regardless of
+** page size.
+*/
+#define BT_MAX_LOCAL 65501 /* 65536 - 35 */
+
+/*
** A cursor is a pointer to a particular entry within a particular
** b-tree within a database file.
**
@@ -70416,7 +71425,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){
*/
static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){
int i;
- int skipOk = 1;
+ u8 skipOk = 1;
Btree *p;
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; i<db->nDb; i++){
@@ -71272,7 +72281,7 @@ static int saveCursorKey(BtCursor *pCur){
** below. */
void *pKey;
pCur->nKey = sqlite3BtreePayloadSize(pCur);
- pKey = sqlite3Malloc( pCur->nKey + 9 + 8 );
+ pKey = sqlite3Malloc( ((i64)pCur->nKey) + 9 + 8 );
if( pKey ){
rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey);
if( rc==SQLITE_OK ){
@@ -71562,7 +72571,7 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
*/
SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){
assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 );
- pCur->hints = x;
+ pCur->hints = (u8)x;
}
@@ -71756,14 +72765,15 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){
int maxLocal; /* Maximum amount of payload held locally */
maxLocal = pPage->maxLocal;
+ assert( nPayload>=0 );
if( nPayload<=maxLocal ){
- return nPayload;
+ return (int)nPayload;
}else{
int minLocal; /* Minimum amount of payload held locally */
int surplus; /* Overflow payload available for local storage */
minLocal = pPage->minLocal;
- surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4);
- return ( surplus <= maxLocal ) ? surplus : minLocal;
+ surplus = (int)(minLocal +(nPayload - minLocal)%(pPage->pBt->usableSize-4));
+ return (surplus <= maxLocal) ? surplus : minLocal;
}
}
@@ -71873,11 +72883,13 @@ static void btreeParseCellPtr(
pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
testcase( nPayload==(u32)pPage->maxLocal+1 );
+ assert( nPayload>=0 );
+ assert( pPage->maxLocal <= BT_MAX_LOCAL );
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
*/
- pInfo->nSize = nPayload + (u16)(pIter - pCell);
+ pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell);
if( pInfo->nSize<4 ) pInfo->nSize = 4;
pInfo->nLocal = (u16)nPayload;
}else{
@@ -71910,11 +72922,13 @@ static void btreeParseCellPtrIndex(
pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
testcase( nPayload==(u32)pPage->maxLocal+1 );
+ assert( nPayload>=0 );
+ assert( pPage->maxLocal <= BT_MAX_LOCAL );
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
*/
- pInfo->nSize = nPayload + (u16)(pIter - pCell);
+ pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell);
if( pInfo->nSize<4 ) pInfo->nSize = 4;
pInfo->nLocal = (u16)nPayload;
}else{
@@ -72453,14 +73467,14 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
** at the end of the page. So do additional corruption checks inside this
** routine and return SQLITE_CORRUPT if any problems are found.
*/
-static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
- u16 iPtr; /* Address of ptr to next freeblock */
- u16 iFreeBlk; /* Address of the next freeblock */
+static int freeSpace(MemPage *pPage, int iStart, int iSize){
+ int iPtr; /* Address of ptr to next freeblock */
+ int iFreeBlk; /* Address of the next freeblock */
u8 hdr; /* Page header size. 0 or 100 */
- u8 nFrag = 0; /* Reduction in fragmentation */
- u16 iOrigSize = iSize; /* Original value of iSize */
- u16 x; /* Offset to cell content area */
- u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */
+ int nFrag = 0; /* Reduction in fragmentation */
+ int iOrigSize = iSize; /* Original value of iSize */
+ int x; /* Offset to cell content area */
+ int iEnd = iStart + iSize; /* First byte past the iStart buffer */
unsigned char *data = pPage->aData; /* Page content */
u8 *pTmp; /* Temporary ptr into data[] */
@@ -72487,7 +73501,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}
iPtr = iFreeBlk;
}
- if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
+ if( iFreeBlk>(int)pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
return SQLITE_CORRUPT_PAGE(pPage);
}
assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB );
@@ -72502,7 +73516,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
nFrag = iFreeBlk - iEnd;
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
- if( iEnd > pPage->pBt->usableSize ){
+ if( iEnd > (int)pPage->pBt->usableSize ){
return SQLITE_CORRUPT_PAGE(pPage);
}
iSize = iEnd - iStart;
@@ -72523,7 +73537,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}
}
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
- data[hdr+7] -= nFrag;
+ data[hdr+7] -= (u8)nFrag;
}
pTmp = &data[hdr+5];
x = get2byte(pTmp);
@@ -72544,7 +73558,8 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
put2byte(&data[iStart], iFreeBlk);
- put2byte(&data[iStart+2], iSize);
+ assert( iSize>=0 && iSize<=0xffff );
+ put2byte(&data[iStart+2], (u16)iSize);
}
pPage->nFree += iOrigSize;
return SQLITE_OK;
@@ -72770,7 +73785,7 @@ static int btreeInitPage(MemPage *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->cellOffset = (u16)(pPage->hdrOffset + 8 + pPage->childPtrSize);
pPage->aCellIdx = data + pPage->childPtrSize + 8;
pPage->aDataEnd = pPage->aData + pBt->pageSize;
pPage->aDataOfst = pPage->aData + pPage->childPtrSize;
@@ -72804,8 +73819,8 @@ static int btreeInitPage(MemPage *pPage){
static void zeroPage(MemPage *pPage, int flags){
unsigned char *data = pPage->aData;
BtShared *pBt = pPage->pBt;
- u8 hdr = pPage->hdrOffset;
- u16 first;
+ int hdr = pPage->hdrOffset;
+ int first;
assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB );
assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
@@ -72822,7 +73837,7 @@ static void zeroPage(MemPage *pPage, int flags){
put2byte(&data[hdr+5], pBt->usableSize);
pPage->nFree = (u16)(pBt->usableSize - first);
decodeFlags(pPage, flags);
- pPage->cellOffset = first;
+ pPage->cellOffset = (u16)first;
pPage->aDataEnd = &data[pBt->pageSize];
pPage->aCellIdx = &data[first];
pPage->aDataOfst = &data[pPage->childPtrSize];
@@ -73608,7 +74623,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve,
BtShared *pBt = p->pBt;
assert( nReserve>=0 && nReserve<=255 );
sqlite3BtreeEnter(p);
- pBt->nReserveWanted = nReserve;
+ pBt->nReserveWanted = (u8)nReserve;
x = pBt->pageSize - pBt->usableSize;
if( nReserve<x ) nReserve = x;
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
@@ -73714,7 +74729,7 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) );
if( newFlag>=0 ){
p->pBt->btsFlags &= ~BTS_FAST_SECURE;
- p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag;
+ p->pBt->btsFlags |= (u16)(BTS_SECURE_DELETE*newFlag);
}
b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE;
sqlite3BtreeLeave(p);
@@ -74234,6 +75249,13 @@ static SQLITE_NOINLINE int btreeBeginTrans(
(void)sqlite3PagerWalWriteLock(pPager, 0);
unlockBtreeIfUnused(pBt);
}
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT)
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ /* If a blocking lock timed out, break out of the loop here so that
+ ** the busy-handler is not invoked. */
+ break;
+ }
+#endif
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
btreeInvokeBusyHandler(pBt) );
sqlite3PagerWalDb(pPager, 0);
@@ -75289,6 +76311,25 @@ SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){
return ROUND8(sizeof(BtCursor));
}
+#ifdef SQLITE_DEBUG
+/*
+** Return true if and only if the Btree object will be automatically
+** closed with the BtCursor closes. This is used within assert() statements
+** only.
+*/
+SQLITE_PRIVATE int sqlite3BtreeClosesWithCursor(
+ Btree *pBtree, /* the btree object */
+ BtCursor *pCur /* Corresponding cursor */
+){
+ BtShared *pBt = pBtree->pBt;
+ if( (pBt->openFlags & BTREE_SINGLE)==0 ) return 0;
+ if( pBt->pCursor!=pCur ) return 0;
+ if( pCur->pNext!=0 ) return 0;
+ if( pCur->pBtree!=pBtree ) return 0;
+ return 1;
+}
+#endif
+
/*
** Initialize memory that will be converted into a BtCursor object.
**
@@ -76532,7 +77573,7 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto(
&& indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0
&& pIdxKey->errCode==SQLITE_OK
){
- pCur->curFlags &= ~BTCF_ValidOvfl;
+ pCur->curFlags &= ~(BTCF_ValidOvfl|BTCF_AtLast);
if( !pCur->pPage->isInit ){
return SQLITE_CORRUPT_BKPT;
}
@@ -76624,7 +77665,7 @@ bypass_moveto_root:
rc = SQLITE_CORRUPT_PAGE(pPage);
goto moveto_index_finish;
}
- pCellKey = sqlite3Malloc( nCell+nOverrun );
+ pCellKey = sqlite3Malloc( (u64)nCell+(u64)nOverrun );
if( pCellKey==0 ){
rc = SQLITE_NOMEM_BKPT;
goto moveto_index_finish;
@@ -78110,7 +79151,8 @@ static int rebuildPage(
if( j>(u32)usableSize ){ j = 0; }
memcpy(&pTmp[j], &aData[j], usableSize - j);
- for(k=0; ALWAYS(k<NB*2) && pCArray->ixNx[k]<=i; k++){}
+ assert( pCArray->ixNx[NB*2-1]>i );
+ for(k=0; pCArray->ixNx[k]<=i; k++){}
pSrcEnd = pCArray->apEnd[k];
pData = pEnd;
@@ -78142,7 +79184,8 @@ static int rebuildPage(
}
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
- pPg->nCell = nCell;
+ assert( nCell < 10922 );
+ pPg->nCell = (u16)nCell;
pPg->nOverflow = 0;
put2byte(&aData[hdr+1], 0);
@@ -78193,7 +79236,8 @@ static int pageInsertArray(
u8 *pEnd; /* Maximum extent of cell data */
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
if( iEnd<=iFirst ) return 0;
- for(k=0; ALWAYS(k<NB*2) && pCArray->ixNx[k]<=i ; k++){}
+ assert( pCArray->ixNx[NB*2-1]>i );
+ for(k=0; pCArray->ixNx[k]<=i ; k++){}
pEnd = pCArray->apEnd[k];
while( 1 /*Exit by break*/ ){
int sz, rc;
@@ -78388,9 +79432,13 @@ static int editPage(
if( pageInsertArray(
pPg, pBegin, &pData, pCellptr,
iNew+nCell, nNew-nCell, pCArray
- ) ) goto editpage_fail;
+ )
+ ){
+ goto editpage_fail;
+ }
- pPg->nCell = nNew;
+ assert( nNew < 10922 );
+ pPg->nCell = (u16)nNew;
pPg->nOverflow = 0;
put2byte(&aData[hdr+3], pPg->nCell);
@@ -78478,6 +79526,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
b.szCell = &szCell;
b.apEnd[0] = pPage->aDataEnd;
b.ixNx[0] = 2;
+ b.ixNx[NB*2-1] = 0x7fffffff;
rc = rebuildPage(&b, 0, 1, pNew);
if( NEVER(rc) ){
releasePage(pNew);
@@ -78698,7 +79747,7 @@ static int balance_nonroot(
int pageFlags; /* Value of pPage->aData[0] */
int iSpace1 = 0; /* First unused byte of aSpace1[] */
int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */
- int szScratch; /* Size of scratch memory requested */
+ u64 szScratch; /* Size of scratch memory requested */
MemPage *apOld[NB]; /* pPage and up to two siblings */
MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */
u8 *pRight; /* Location in parent of right-sibling pointer */
@@ -78713,7 +79762,9 @@ static int balance_nonroot(
CellArray b; /* Parsed information on cells being balanced */
memset(abDone, 0, sizeof(abDone));
- memset(&b, 0, sizeof(b));
+ assert( sizeof(b) - sizeof(b.ixNx) == offsetof(CellArray,ixNx) );
+ memset(&b, 0, sizeof(b)-sizeof(b.ixNx[0]));
+ b.ixNx[NB*2-1] = 0x7fffffff;
pBt = pParent->pBt;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
@@ -79304,7 +80355,8 @@ static int balance_nonroot(
iOvflSpace += sz;
assert( sz<=pBt->maxLocal+23 );
assert( iOvflSpace <= (int)pBt->pageSize );
- for(k=0; ALWAYS(k<NB*2) && b.ixNx[k]<=j; k++){}
+ assert( b.ixNx[NB*2-1]>j );
+ for(k=0; b.ixNx[k]<=j; k++){}
pSrcEnd = b.apEnd[k];
if( SQLITE_OVERFLOW(pSrcEnd, pCell, pCell+sz) ){
rc = SQLITE_CORRUPT_BKPT;
@@ -79980,7 +81032,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( pCur->info.nKey==pX->nKey ){
BtreePayload x2;
x2.pData = pX->pKey;
- x2.nData = pX->nKey;
+ x2.nData = (int)pX->nKey; assert( pX->nKey<=0x7fffffff );
x2.nZero = 0;
return btreeOverwriteCell(pCur, &x2);
}
@@ -80161,7 +81213,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64
getCellInfo(pSrc);
if( pSrc->info.nPayload<0x80 ){
- *(aOut++) = pSrc->info.nPayload;
+ *(aOut++) = (u8)pSrc->info.nPayload;
}else{
aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload);
}
@@ -80174,7 +81226,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64
nRem = pSrc->info.nPayload;
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
memcpy(aOut, aIn, nIn);
- pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
+ pBt->nPreformatSize = nIn + (int)(aOut - pBt->pTmpSpace);
return SQLITE_OK;
}else{
int rc = SQLITE_OK;
@@ -80186,7 +81238,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64
u32 nOut; /* Size of output buffer aOut[] */
nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload);
- pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace);
+ pBt->nPreformatSize = (int)nOut + (int)(aOut - pBt->pTmpSpace);
if( nOut<pSrc->info.nPayload ){
pPgnoOut = &aOut[nOut];
pBt->nPreformatSize += 4;
@@ -81807,6 +82859,7 @@ SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){
*/
SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
BtShared *pBt = p->pBt;
+ assert( nBytes==0 || nBytes==sizeof(Schema) );
sqlite3BtreeEnter(p);
if( !pBt->pSchema && nBytes ){
pBt->pSchema = sqlite3DbMallocZero(0, nBytes);
@@ -82923,7 +83976,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
** 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
+** https://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
@@ -83109,7 +84162,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){
return;
}
if( pMem->enc!=SQLITE_UTF8 ) return;
- if( NEVER(pMem->z==0) ) return;
+ assert( pMem->z!=0 );
if( pMem->flags & MEM_Dyn ){
if( pMem->xDel==sqlite3_free
&& sqlite3_msize(pMem->z) >= (u64)(pMem->n+1)
@@ -83828,27 +84881,30 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
int i;
Mem *pX;
- for(i=1, pX=pVdbe->aMem+1; i<pVdbe->nMem; i++, pX++){
- if( pX->pScopyFrom==pMem ){
- 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;
- }
+ if( pMem->bScopy ){
+ for(i=1, pX=pVdbe->aMem+1; i<pVdbe->nMem; i++, pX++){
+ if( pX->pScopyFrom==pMem ){
+ 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;
+ }
+ }
+ pMem->bScopy = 0;
}
pMem->pScopyFrom = 0;
}
@@ -84219,7 +85275,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
if( pRec==0 ){
Index *pIdx = p->pIdx; /* Index being probed */
- int nByte; /* Bytes of space to allocate */
+ i64 nByte; /* Bytes of space to allocate */
int i; /* Counter variable */
int nCol = pIdx->nColumn; /* Number of index columns including rowid */
@@ -84285,7 +85341,7 @@ static int valueFromFunction(
){
sqlite3_context ctx; /* Context object for function invocation */
sqlite3_value **apVal = 0; /* Function arguments */
- int nVal = 0; /* Size of apVal[] array */
+ int nVal = 0; /* Number of function arguments */
FuncDef *pFunc = 0; /* Function definition */
sqlite3_value *pVal = 0; /* New value */
int rc = SQLITE_OK; /* Return code */
@@ -84316,7 +85372,8 @@ static int valueFromFunction(
goto value_from_function_out;
}
for(i=0; i<nVal; i++){
- rc = sqlite3ValueFromExpr(db, pList->a[i].pExpr, enc, aff, &apVal[i]);
+ rc = sqlite3Stat4ValueFromExpr(pCtx->pParse, pList->a[i].pExpr, aff,
+ &apVal[i]);
if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out;
}
}
@@ -85282,12 +86339,10 @@ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(
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);
+ pCtx = sqlite3DbMallocRawNN(pParse->db, SZ_CONTEXT(nArg));
if( pCtx==0 ){
assert( pParse->db->mallocFailed );
freeEphemeralFunction(pParse->db, (FuncDef*)pFunc);
@@ -85563,7 +86618,7 @@ static Op *opIterNext(VdbeOpIter *p){
}
if( pRet->p4type==P4_SUBPROGRAM ){
- int nByte = (p->nSub+1)*sizeof(SubProgram*);
+ i64 nByte = (1+(u64)p->nSub)*sizeof(SubProgram*);
int j;
for(j=0; j<p->nSub; j++){
if( p->apSub[j]==pRet->p4.pProgram ) break;
@@ -85693,8 +86748,8 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){
** (1) For each jump instruction with a negative P2 value (a label)
** resolve the P2 value to an actual address.
**
-** (2) Compute the maximum number of arguments used by any SQL function
-** and store that value in *pMaxFuncArgs.
+** (2) Compute the maximum number of arguments used by the xUpdate/xFilter
+** methods of any virtual table and store that value in *pMaxVtabArgs.
**
** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately
** indicate what the prepared statement actually does.
@@ -85707,8 +86762,8 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){
** script numbers the opcodes correctly. Changes to this routine must be
** coordinated with changes to mkopcodeh.tcl.
*/
-static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
- int nMaxArgs = *pMaxFuncArgs;
+static void resolveP2Values(Vdbe *p, int *pMaxVtabArgs){
+ int nMaxVtabArgs = *pMaxVtabArgs;
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
@@ -85753,15 +86808,19 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
- if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
+ if( pOp->p2>nMaxVtabArgs ) nMaxVtabArgs = pOp->p2;
break;
}
case OP_VFilter: {
int n;
+ /* The instruction immediately prior to VFilter will be an
+ ** OP_Integer that sets the "argc" value for the VFilter. See
+ ** the code where OP_VFilter is generated at tag-20250207a. */
assert( (pOp - p->aOp) >= 3 );
assert( pOp[-1].opcode==OP_Integer );
+ assert( pOp[-1].p2==pOp->p3+1 );
n = pOp[-1].p1;
- if( n>nMaxArgs ) nMaxArgs = n;
+ if( n>nMaxVtabArgs ) nMaxVtabArgs = n;
/* Fall through into the default case */
/* no break */ deliberate_fall_through
}
@@ -85802,7 +86861,7 @@ resolve_p2_values_loop_exit:
pParse->aLabel = 0;
}
pParse->nLabel = 0;
- *pMaxFuncArgs = nMaxArgs;
+ *pMaxVtabArgs = nMaxVtabArgs;
assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
}
@@ -86031,7 +87090,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
const char *zName /* Name of table or index being scanned */
){
if( IS_STMT_SCANSTATUS(p->db) ){
- sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
+ i64 nByte = (1+(i64)p->nScan) * sizeof(ScanStatus);
ScanStatus *aNew;
aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
if( aNew ){
@@ -86141,6 +87200,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
*/
SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){
VdbeOp *pOp = sqlite3VdbeGetLastOp(p);
+#ifdef SQLITE_DEBUG
+ while( pOp->opcode==OP_ReleaseReg ) pOp--;
+#endif
if( pOp->p3==iDest && pOp->opcode==OP_Column ){
pOp->p5 |= OPFLAG_TYPEOFARG;
}
@@ -86250,6 +87312,12 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4);
break;
}
+ case P4_SUBRTNSIG: {
+ SubrtnSig *pSig = (SubrtnSig*)p4;
+ sqlite3DbFree(db, pSig->zAff);
+ sqlite3DbFree(db, pSig);
+ break;
+ }
}
}
@@ -86829,6 +87897,11 @@ SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
zP4 = pOp->p4.pTab->zName;
break;
}
+ case P4_SUBRTNSIG: {
+ SubrtnSig *pSig = pOp->p4.pSubrtnSig;
+ sqlite3_str_appendf(&x, "subrtnsig:%d,%s", pSig->selId, pSig->zAff);
+ break;
+ }
default: {
zP4 = pOp->p4.z;
}
@@ -86970,6 +88043,7 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
** will be initialized before use.
*/
static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
+ assert( db!=0 );
if( N>0 ){
do{
p->flags = flags;
@@ -86977,6 +88051,7 @@ static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
p->szMalloc = 0;
#ifdef SQLITE_DEBUG
p->pScopyFrom = 0;
+ p->bScopy = 0;
#endif
p++;
}while( (--N)>0 );
@@ -86995,6 +88070,7 @@ static void releaseMemArray(Mem *p, int N){
if( p && N ){
Mem *pEnd = &p[N];
sqlite3 *db = p->db;
+ assert( db!=0 );
if( db->pnBytesFreed ){
do{
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
@@ -87466,7 +88542,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
int nVar; /* Number of parameters */
int nMem; /* Number of VM memory registers */
int nCursor; /* Number of cursors required */
- int nArg; /* Number of arguments in subprograms */
+ int nArg; /* Max number args to xFilter or xUpdate */
int n; /* Loop counter */
struct ReusableSpace x; /* Reusable bulk memory */
@@ -87475,6 +88551,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
assert( pParse!=0 );
assert( p->eVdbeState==VDBE_INIT_STATE );
assert( pParse==p->pParse );
+ assert( pParse->db==p->db );
p->pVList = pParse->pVList;
pParse->pVList = 0;
db = p->db;
@@ -87537,6 +88614,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
}
}
+#ifdef SQLITE_DEBUG
+ p->napArg = nArg;
+#endif
if( db->mallocFailed ){
p->nVar = 0;
@@ -89034,6 +90114,7 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
){
UnpackedRecord *p; /* Unpacked record to return */
int nByte; /* Number of bytes required for *p */
+ assert( sizeof(UnpackedRecord) + sizeof(Mem)*65536 < 0x7fffffff );
nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
if( !p ) return 0;
@@ -89338,7 +90419,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem
** We must use separate SQLITE_NOINLINE functions here, since otherwise
** optimizer code movement causes gcov to become very confused.
*/
-#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
static int SQLITE_NOINLINE doubleLt(double a, double b){ return a<b; }
static int SQLITE_NOINLINE doubleEq(double a, double b){ return a==b; }
#endif
@@ -89353,13 +90434,6 @@ SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){
/* SQLite considers NaN to be a NULL. And all integer values are greater
** than NULL */
return 1;
- }
- if( sqlite3Config.bUseLongDouble ){
- LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
- testcase( x<r );
- testcase( x>r );
- testcase( x==r );
- return (x<r) ? -1 : (x>r);
}else{
i64 y;
if( r<-9223372036854775808.0 ) return +1;
@@ -90347,10 +91421,11 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
preupdate.pCsr = pCsr;
preupdate.op = op;
preupdate.iNewReg = iReg;
- preupdate.keyinfo.db = db;
- preupdate.keyinfo.enc = ENC(db);
- preupdate.keyinfo.nKeyField = pTab->nCol;
- preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder;
+ preupdate.pKeyinfo = (KeyInfo*)&preupdate.keyinfoSpace;
+ preupdate.pKeyinfo->db = db;
+ preupdate.pKeyinfo->enc = ENC(db);
+ preupdate.pKeyinfo->nKeyField = pTab->nCol;
+ preupdate.pKeyinfo->aSortFlags = (u8*)&fakeSortOrder;
preupdate.iKey1 = iKey1;
preupdate.iKey2 = iKey2;
preupdate.pTab = pTab;
@@ -90360,8 +91435,9 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
db->pPreUpdate = 0;
sqlite3DbFree(db, preupdate.aRecord);
- vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
- vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
+ vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pUnpacked);
+ vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pNewUnpacked);
+ sqlite3VdbeMemRelease(&preupdate.oldipk);
if( preupdate.aNew ){
int i;
for(i=0; i<pCsr->nField; i++){
@@ -90369,6 +91445,13 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
}
sqlite3DbNNFreeNN(db, preupdate.aNew);
}
+ if( preupdate.apDflt ){
+ int i;
+ for(i=0; i<pTab->nCol; i++){
+ sqlite3ValueFree(preupdate.apDflt[i]);
+ }
+ sqlite3DbFree(db, preupdate.apDflt);
+ }
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -90439,7 +91522,6 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
sqlite3_int64 iNow;
sqlite3_int64 iElapse;
assert( p->startTime>0 );
- assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 );
assert( db->init.busy==0 );
assert( p->zSql!=0 );
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
@@ -91159,7 +92241,7 @@ static int sqlite3Step(Vdbe *p){
}
assert( db->nVdbeWrite>0 || db->autoCommit==0
- || (db->nDeferredCons==0 && db->nDeferredImmCons==0)
+ || ((db->nDeferredCons + db->nDeferredImmCons)==0)
);
#ifndef SQLITE_OMIT_TRACE
@@ -91670,6 +92752,7 @@ static const Mem *columnNullValue(void){
#ifdef SQLITE_DEBUG
/* .pScopyFrom = */ (Mem*)0,
/* .mScopyFlags= */ 0,
+ /* .bScopy = */ 0,
#endif
};
return &nullMem;
@@ -91711,7 +92794,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
** sqlite3_column_int64()
** sqlite3_column_text()
** sqlite3_column_text16()
-** sqlite3_column_real()
+** sqlite3_column_double()
** sqlite3_column_bytes()
** sqlite3_column_bytes16()
** sqlite3_column_blob()
@@ -91997,6 +93080,17 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
**
** The error code stored in database p->db is overwritten with the return
** value in any case.
+**
+** (tag-20240917-01) If vdbeUnbind(p,(u32)(i-1)) returns SQLITE_OK,
+** that means all of the the following will be true:
+**
+** p!=0
+** p->pVar!=0
+** i>0
+** i<=p->nVar
+**
+** An assert() is normally added after vdbeUnbind() to help static analyzers
+** realize this.
*/
static int vdbeUnbind(Vdbe *p, unsigned int i){
Mem *pVar;
@@ -92054,6 +93148,7 @@ static int bindText(
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
if( zData!=0 ){
pVar = &p->aVar[i-1];
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
@@ -92103,6 +93198,7 @@ SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
sqlite3_mutex_leave(p->db->mutex);
}
@@ -92116,6 +93212,7 @@ SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValu
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
sqlite3_mutex_leave(p->db->mutex);
}
@@ -92126,6 +93223,7 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
sqlite3_mutex_leave(p->db->mutex);
}
return rc;
@@ -92141,6 +93239,7 @@ SQLITE_API int sqlite3_bind_pointer(
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
sqlite3_mutex_leave(p->db->mutex);
}else if( xDestructor ){
@@ -92168,7 +93267,7 @@ SQLITE_API int sqlite3_bind_text64(
assert( xDel!=SQLITE_DYNAMIC );
if( enc!=SQLITE_UTF8 ){
if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
- nData &= ~(u16)1;
+ nData &= ~(u64)1;
}
return bindText(pStmt, i, zData, nData, xDel, enc);
}
@@ -92222,6 +93321,7 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
+ assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */
#ifndef SQLITE_OMIT_INCRBLOB
sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
#else
@@ -92535,6 +93635,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
PreUpdate *p;
Mem *pMem;
int rc = SQLITE_OK;
+ int iStore = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( db==0 || ppValue==0 ){
@@ -92549,44 +93650,75 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
goto preupdate_old_out;
}
if( p->pPk ){
- iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ iStore = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ }else{
+ iStore = sqlite3TableColumnToStorage(p->pTab, iIdx);
}
- if( iIdx>=p->pCsr->nField || iIdx<0 ){
+ if( iStore>=p->pCsr->nField || iStore<0 ){
rc = SQLITE_RANGE;
goto preupdate_old_out;
}
- /* If the old.* record has not yet been loaded into memory, do so now. */
- if( p->pUnpacked==0 ){
- u32 nRec;
- u8 *aRec;
+ if( iIdx==p->pTab->iPKey ){
+ *ppValue = pMem = &p->oldipk;
+ sqlite3VdbeMemSetInt64(pMem, p->iKey1);
+ }else{
- assert( p->pCsr->eCurType==CURTYPE_BTREE );
- nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
- aRec = sqlite3DbMallocRaw(db, nRec);
- if( !aRec ) goto preupdate_old_out;
- 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;
- }
- if( rc!=SQLITE_OK ){
- sqlite3DbFree(db, aRec);
- goto preupdate_old_out;
+ /* If the old.* record has not yet been loaded into memory, do so now. */
+ if( p->pUnpacked==0 ){
+ u32 nRec;
+ u8 *aRec;
+
+ assert( p->pCsr->eCurType==CURTYPE_BTREE );
+ nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
+ aRec = sqlite3DbMallocRaw(db, nRec);
+ if( !aRec ) goto preupdate_old_out;
+ rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
+ if( rc==SQLITE_OK ){
+ p->pUnpacked = vdbeUnpackRecord(p->pKeyinfo, nRec, aRec);
+ if( !p->pUnpacked ) rc = SQLITE_NOMEM;
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3DbFree(db, aRec);
+ goto preupdate_old_out;
+ }
+ p->aRecord = aRec;
}
- p->aRecord = aRec;
- }
- 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 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);
+ pMem = *ppValue = &p->pUnpacked->aMem[iStore];
+ if( iStore>=p->pUnpacked->nField ){
+ /* This occurs when the table has been extended using ALTER TABLE
+ ** ADD COLUMN. The value to return is the default value of the column. */
+ Column *pCol = &p->pTab->aCol[iIdx];
+ if( pCol->iDflt>0 ){
+ if( p->apDflt==0 ){
+ int nByte;
+ assert( sizeof(sqlite3_value*)*UMXV(p->pTab->nCol) < 0x7fffffff );
+ nByte = sizeof(sqlite3_value*)*p->pTab->nCol;
+ p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte);
+ if( p->apDflt==0 ) goto preupdate_old_out;
+ }
+ if( p->apDflt[iIdx]==0 ){
+ sqlite3_value *pVal = 0;
+ Expr *pDflt;
+ assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) );
+ pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
+ rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal);
+ if( rc==SQLITE_OK && pVal==0 ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }
+ p->apDflt[iIdx] = pVal;
+ }
+ *ppValue = p->apDflt[iIdx];
+ }else{
+ *ppValue = (sqlite3_value *)columnNullValue();
+ }
+ }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);
+ }
}
}
@@ -92608,7 +93740,7 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
#else
p = db->pPreUpdate;
#endif
- return (p ? p->keyinfo.nKeyField : 0);
+ return (p ? p->pKeyinfo->nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -92660,6 +93792,7 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa
PreUpdate *p;
int rc = SQLITE_OK;
Mem *pMem;
+ int iStore = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( db==0 || ppValue==0 ){
@@ -92672,9 +93805,12 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa
goto preupdate_new_out;
}
if( p->pPk && p->op!=SQLITE_UPDATE ){
- iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ iStore = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ }else{
+ iStore = sqlite3TableColumnToStorage(p->pTab, iIdx);
}
- if( iIdx>=p->pCsr->nField || iIdx<0 ){
+
+ if( iStore>=p->pCsr->nField || iStore<0 ){
rc = SQLITE_RANGE;
goto preupdate_new_out;
}
@@ -92687,40 +93823,41 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa
Mem *pData = &p->v->aMem[p->iNewReg];
rc = ExpandBlob(pData);
if( rc!=SQLITE_OK ) goto preupdate_new_out;
- pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z);
+ pUnpack = vdbeUnpackRecord(p->pKeyinfo, pData->n, pData->z);
if( !pUnpack ){
rc = SQLITE_NOMEM;
goto preupdate_new_out;
}
p->pNewUnpacked = pUnpack;
}
- pMem = &pUnpack->aMem[iIdx];
+ pMem = &pUnpack->aMem[iStore];
if( iIdx==p->pTab->iPKey ){
sqlite3VdbeMemSetInt64(pMem, p->iKey2);
- }else if( iIdx>=pUnpack->nField ){
+ }else if( iStore>=pUnpack->nField ){
pMem = (sqlite3_value *)columnNullValue();
}
}else{
- /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
+ /* For an UPDATE, memory cell (p->iNewReg+1+iStore) contains the required
** value. Make a copy of the cell contents and return a pointer to it.
** It is not safe to return a pointer to the memory cell itself as the
** caller may modify the value text encoding.
*/
assert( p->op==SQLITE_UPDATE );
if( !p->aNew ){
- p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField);
+ assert( sizeof(Mem)*UMXV(p->pCsr->nField) < 0x7fffffff );
+ p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem)*p->pCsr->nField);
if( !p->aNew ){
rc = SQLITE_NOMEM;
goto preupdate_new_out;
}
}
- assert( iIdx>=0 && iIdx<p->pCsr->nField );
- pMem = &p->aNew[iIdx];
+ assert( iStore>=0 && iStore<p->pCsr->nField );
+ pMem = &p->aNew[iStore];
if( pMem->flags==0 ){
if( iIdx==p->pTab->iPKey ){
sqlite3VdbeMemSetInt64(pMem, p->iKey2);
}else{
- rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
+ rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iStore]);
if( rc!=SQLITE_OK ) goto preupdate_new_out;
}
}
@@ -93135,6 +94272,104 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
/* #include "vdbeInt.h" */
/*
+** High-resolution hardware timer used for debugging and testing only.
+*/
+#if defined(VDBE_PROFILE) \
+ || defined(SQLITE_PERFORMANCE_TRACE) \
+ || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+/************** Include hwtime.h in the middle of vdbe.c *********************/
+/************** Begin file hwtime.h ******************************************/
+/*
+** 2008 May 27
+**
+** 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 inline asm code for retrieving "high-performance"
+** counters for x86 and x86_64 class CPUs.
+*/
+#ifndef SQLITE_HWTIME_H
+#define SQLITE_HWTIME_H
+
+/*
+** The following routine only works on Pentium-class (or newer) processors.
+** It uses the RDTSC opcode to read the cycle count value out of the
+** processor and returns that value. This can be used for high-res
+** profiling.
+*/
+#if !defined(__STRICT_ANSI__) && \
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
+
+ #if defined(__GNUC__)
+
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
+ unsigned int lo, hi;
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+ return (sqlite_uint64)hi << 32 | lo;
+ }
+
+ #elif defined(_MSC_VER)
+
+ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
+ __asm {
+ rdtsc
+ ret ; return value at EDX:EAX
+ }
+ }
+
+ #endif
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
+
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
+ unsigned int lo, hi;
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+ return (sqlite_uint64)hi << 32 | lo;
+ }
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
+
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
+ unsigned long long retval;
+ unsigned long junk;
+ __asm__ __volatile__ ("\n\
+ 1: mftbu %1\n\
+ mftb %L0\n\
+ mftbu %0\n\
+ cmpw %0,%1\n\
+ bne 1b"
+ : "=r" (retval), "=r" (junk));
+ return retval;
+ }
+
+#else
+
+ /*
+ ** 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); }
+
+#endif
+
+#endif /* !defined(SQLITE_HWTIME_H) */
+
+/************** End of hwtime.h **********************************************/
+/************** Continuing where we left off in vdbe.c ***********************/
+#endif
+
+/*
** Invoke this macro on memory cells just prior to changing the
** value of the cell. This macro verifies that shallow copies are
** not misused. A shallow copy of a string or blob just copies a
@@ -93380,11 +94615,11 @@ static VdbeCursor *allocateCursor(
*/
Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem;
- int nByte;
+ i64 nByte;
VdbeCursor *pCx = 0;
- nByte =
- ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
- (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
+ nByte = SZ_VDBECURSOR(nField);
+ assert( ROUND8(nByte)==nByte );
+ if( eCurType==CURTYPE_BTREE ) nByte += sqlite3BtreeCursorSize();
assert( iCur>=0 && iCur<p->nCursor );
if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
@@ -93408,7 +94643,7 @@ static VdbeCursor *allocateCursor(
pMem->szMalloc = 0;
return 0;
}
- pMem->szMalloc = nByte;
+ pMem->szMalloc = (int)nByte;
}
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc;
@@ -93417,8 +94652,8 @@ static VdbeCursor *allocateCursor(
pCx->nField = nField;
pCx->aOffset = &pCx->aType[nField];
if( eCurType==CURTYPE_BTREE ){
- pCx->uc.pCursor = (BtCursor*)
- &pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
+ assert( ROUND8(SZ_VDBECURSOR(nField))==SZ_VDBECURSOR(nField) );
+ pCx->uc.pCursor = (BtCursor*)&pMem->z[SZ_VDBECURSOR(nField)];
sqlite3BtreeCursorZero(pCx->uc.pCursor);
}
return pCx;
@@ -93711,6 +94946,7 @@ static void registerTrace(int iReg, Mem *p){
printf("R[%d] = ", iReg);
memTracePrint(p);
if( p->pScopyFrom ){
+ assert( p->pScopyFrom->bScopy );
printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg]));
}
printf("\n");
@@ -94327,7 +95563,7 @@ case OP_HaltIfNull: { /* in3 */
/* no break */ deliberate_fall_through
}
-/* Opcode: Halt P1 P2 * P4 P5
+/* Opcode: Halt P1 P2 P3 P4 P5
**
** Exit immediately. All open cursors, etc are closed
** automatically.
@@ -94340,18 +95576,22 @@ case OP_HaltIfNull: { /* in3 */
** then back out all changes that have occurred during this execution of the
** VDBE, but do not rollback the transaction.
**
-** If P4 is not null then it is an error message string.
+** If P3 is not zero and P4 is NULL, then P3 is a register that holds the
+** text of an error message.
+**
+** If P3 is zero and P4 is not null then the error message string is held
+** in P4.
**
-** P5 is a value between 0 and 4, inclusive, that modifies the P4 string.
+** P5 is a value between 1 and 4, inclusive, then the P4 error message
+** string is modified as follows:
**
-** 0: (no change)
** 1: NOT NULL constraint failed: P4
** 2: UNIQUE constraint failed: P4
** 3: CHECK constraint failed: P4
** 4: FOREIGN KEY constraint failed: P4
**
-** If P5 is not zero and P4 is NULL, then everything after the ":" is
-** omitted.
+** If P3 is zero and P5 is not zero and P4 is NULL, then everything after
+** the ":" is omitted.
**
** There is an implied "Halt 0 0 0" instruction inserted at the very end of
** every program. So a jump past the last instruction of the program
@@ -94364,6 +95604,9 @@ case OP_Halt: {
#ifdef SQLITE_DEBUG
if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif
+ assert( pOp->p4type==P4_NOTUSED
+ || pOp->p4type==P4_STATIC
+ || pOp->p4type==P4_DYNAMIC );
/* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates
** something is wrong with the code generator. Raise an assertion in order
@@ -94394,7 +95637,12 @@ case OP_Halt: {
p->errorAction = (u8)pOp->p2;
assert( pOp->p5<=4 );
if( p->rc ){
- if( pOp->p5 ){
+ if( pOp->p3>0 && pOp->p4type==P4_NOTUSED ){
+ const char *zErr;
+ assert( pOp->p3<=(p->nMem + 1 - p->nCursor) );
+ zErr = sqlite3ValueText(&aMem[pOp->p3], SQLITE_UTF8);
+ sqlite3VdbeError(p, "%s", zErr);
+ }else if( pOp->p5 ){
static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
"FOREIGN KEY" };
testcase( pOp->p5==1 );
@@ -94409,7 +95657,7 @@ case OP_Halt: {
sqlite3VdbeError(p, "%s", pOp->p4.z);
}
pcx = (int)(pOp - aOp);
- sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
+ sqlite3_log(pOp->p1, "abort at %d: %s; [%s]", pcx, p->zErrMsg, p->zSql);
}
rc = sqlite3VdbeHalt(p);
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
@@ -94682,6 +95930,7 @@ case OP_Move: {
{ int i;
for(i=1; i<p->nMem; i++){
if( aMem[i].pScopyFrom==pIn1 ){
+ assert( aMem[i].bScopy );
aMem[i].pScopyFrom = pOut;
}
}
@@ -94754,6 +96003,7 @@ case OP_SCopy: { /* out2 */
#ifdef SQLITE_DEBUG
pOut->pScopyFrom = pIn1;
pOut->mScopyFlags = pIn1->flags;
+ pIn1->bScopy = 1;
#endif
break;
}
@@ -95197,7 +96447,7 @@ case OP_RealAffinity: { /* in1 */
}
#endif
-#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE)
+#if !defined(SQLITE_OMIT_CAST) || !defined(SQLITE_OMIT_ANALYZE)
/* Opcode: Cast P1 P2 * * *
** Synopsis: affinity(r[P1])
**
@@ -95733,7 +96983,7 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
break;
}
-/* Opcode: Once P1 P2 * * *
+/* Opcode: Once P1 P2 P3 * *
**
** Fall through to the next instruction the first time this opcode is
** encountered on each invocation of the byte-code program. Jump to P2
@@ -95749,6 +96999,12 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
** whether or not the jump should be taken. The bitmask is necessary
** because the self-altering code trick does not work for recursive
** triggers.
+**
+** The P3 operand is not used directly by this opcode. However P3 is
+** used by the code generator as follows: If this opcode is the start
+** of a subroutine and that subroutine uses a Bloom filter, then P3 will
+** be the register that holds that Bloom filter. See tag-202407032019
+** in the source code for implementation details.
*/
case OP_Once: { /* jump */
u32 iAddr; /* Address of this instruction */
@@ -96794,6 +98050,7 @@ case OP_MakeRecord: {
zHdr += sqlite3PutVarint(zHdr, serial_type);
if( pRec->n ){
assert( pRec->z!=0 );
+ assert( pRec->z!=(const char*)sqlite3CtypeMap );
memcpy(zPayload, pRec->z, pRec->n);
zPayload += pRec->n;
}
@@ -97437,23 +98694,23 @@ case OP_OpenWrite:
if( pDb->pSchema->file_format < p->minWriteFileFormat ){
p->minWriteFileFormat = pDb->pSchema->file_format;
}
+ if( pOp->p5 & OPFLAG_P2ISREG ){
+ assert( p2>0 );
+ assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
+ 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_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. */
+ assert( p2>=2 );
+ }
}else{
wrFlag = 0;
- }
- if( pOp->p5 & OPFLAG_P2ISREG ){
- assert( p2>0 );
- 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_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. */
- assert( p2>=2 );
+ assert( (pOp->p5 & OPFLAG_P2ISREG)==0 );
}
if( pOp->p4type==P4_KEYINFO ){
pKeyInfo = pOp->p4.pKeyInfo;
@@ -97630,8 +98887,13 @@ case OP_OpenEphemeral: { /* ncycle */
}
}
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
+ assert( p->apCsr[pOp->p1]==pCx );
if( rc ){
+ assert( !sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) );
sqlite3BtreeClose(pCx->ub.pBtx);
+ p->apCsr[pOp->p1] = 0; /* Not required; helps with static analysis */
+ }else{
+ assert( sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) );
}
}
}
@@ -98409,6 +99671,7 @@ case OP_Found: { /* jump, in3, ncycle */
r.pKeyInfo = pC->pKeyInfo;
r.default_rc = 0;
#ifdef SQLITE_DEBUG
+ (void)sqlite3FaultSim(50); /* For use by --counter in TH3 */
for(ii=0; ii<r.nField; ii++){
assert( memIsValid(&r.aMem[ii]) );
assert( (r.aMem[ii].flags & MEM_Zero)==0 || r.aMem[ii].n==0 );
@@ -99139,7 +100402,7 @@ case OP_RowData: {
/* 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
+ ** If this were not the case, one of the following assert()s
** would fail. Should this ever change (because of changes in the code
** generator) then the fix would be to insert a call to
** sqlite3VdbeCursorMoveto().
@@ -100408,7 +101671,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
*/
case OP_Program: { /* jump0 */
int nMem; /* Number of memory registers for sub-program */
- int nByte; /* Bytes of runtime space required for sub-program */
+ i64 nByte; /* Bytes of runtime space required for sub-program */
Mem *pRt; /* Register to allocate runtime space */
Mem *pMem; /* Used to iterate through memory cells */
Mem *pEnd; /* Last memory cell in new array */
@@ -100459,7 +101722,7 @@ case OP_Program: { /* jump0 */
nByte = ROUND8(sizeof(VdbeFrame))
+ nMem * sizeof(Mem)
+ pProgram->nCsr * sizeof(VdbeCursor*)
- + (pProgram->nOp + 7)/8;
+ + (7 + (i64)pProgram->nOp)/8;
pFrame = sqlite3DbMallocZero(db, nByte);
if( !pFrame ){
goto no_mem;
@@ -100467,7 +101730,7 @@ case OP_Program: { /* jump0 */
sqlite3VdbeMemRelease(pRt);
pRt->flags = MEM_Blob|MEM_Dyn;
pRt->z = (char*)pFrame;
- pRt->n = nByte;
+ pRt->n = (int)nByte;
pRt->xDel = sqlite3VdbeFrameMemDel;
pFrame->v = p;
@@ -100566,12 +101829,14 @@ case OP_Param: { /* out2 */
** statement counter is incremented (immediate foreign key constraints).
*/
case OP_FkCounter: {
- if( db->flags & SQLITE_DeferFKs ){
- db->nDeferredImmCons += pOp->p2;
- }else if( pOp->p1 ){
+ if( pOp->p1 ){
db->nDeferredCons += pOp->p2;
}else{
- p->nFkConstraint += pOp->p2;
+ if( db->flags & SQLITE_DeferFKs ){
+ db->nDeferredImmCons += pOp->p2;
+ }else{
+ p->nFkConstraint += pOp->p2;
+ }
}
break;
}
@@ -100771,18 +102036,29 @@ case OP_AggInverse:
case OP_AggStep: {
int n;
sqlite3_context *pCtx;
+ u64 nAlloc;
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, n*sizeof(sqlite3_value*) +
- (sizeof(pCtx[0]) + sizeof(Mem) - sizeof(sqlite3_value*)));
+
+ /* Allocate space for (a) the context object and (n-1) extra pointers
+ ** to append to the sqlite3_context.argv[1] array, and (b) a memory
+ ** cell in which to store the accumulation. Be careful that the memory
+ ** cell is 8-byte aligned, even on platforms where a pointer is 32-bits.
+ **
+ ** Note: We could avoid this by using a regular memory cell from aMem[] for
+ ** the accumulator, instead of allocating one here. */
+ nAlloc = ROUND8P( SZ_CONTEXT(n) );
+ pCtx = sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem));
if( pCtx==0 ) goto no_mem;
- pCtx->pMem = 0;
- pCtx->pOut = (Mem*)&(pCtx->argv[n]);
+ pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc);
+ assert( EIGHT_BYTE_ALIGNMENT(pCtx->pOut) );
+
sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null);
+ pCtx->pMem = 0;
pCtx->pFunc = pOp->p4.pFunc;
pCtx->iOp = (int)(pOp - aOp);
pCtx->pVdbe = p;
@@ -101435,6 +102711,7 @@ case OP_VFilter: { /* jump, ncycle */
/* Invoke the xFilter method */
apArg = p->apArg;
+ assert( nArg<=p->napArg );
for(i = 0; i<nArg; i++){
apArg[i] = &pArgc[i+1];
}
@@ -101645,6 +102922,7 @@ case OP_VUpdate: {
u8 vtabOnConflict = db->vtabOnConflict;
apArg = p->apArg;
pX = &aMem[pOp->p3];
+ assert( nArg<=p->napArg );
for(i=0; i<nArg; i++){
assert( memIsValid(pX) );
memAboutToChange(p, pX);
@@ -102116,14 +103394,29 @@ case OP_ReleaseReg: {
/* Opcode: Noop * * * * *
**
-** Do nothing. This instruction is often useful as a jump
-** destination.
+** Do nothing. Continue downward to the next opcode.
*/
-/*
-** The magic Explain opcode are only inserted when explain==2 (which
-** is to say when the EXPLAIN QUERY PLAN syntax is used.)
-** This opcode records information from the optimizer. It is the
-** the same as a no-op. This opcodesnever appears in a real VM program.
+/* Opcode: Explain P1 P2 P3 P4 *
+**
+** This is the same as OP_Noop during normal query execution. The
+** purpose of this opcode is to hold information about the query
+** plan for the purpose of EXPLAIN QUERY PLAN output.
+**
+** The P4 value is human-readable text that describes the query plan
+** element. Something like "SCAN t1" or "SEARCH t2 USING INDEX t2x1".
+**
+** The P1 value is the ID of the current element and P2 is the parent
+** element for the case of nested query plan elements. If P2 is zero
+** then this element is a top-level element.
+**
+** For loop elements, P3 is the estimated code of each invocation of this
+** element.
+**
+** As with all opcodes, the meanings of the parameters for OP_Explain
+** are subject to change from one release to the next. Applications
+** should not attempt to interpret or use any of the information
+** contained in the OP_Explain opcode. The information provided by this
+** opcode is intended for testing and debugging use only.
*/
default: { /* This is really OP_Noop, OP_Explain */
assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
@@ -102206,8 +103499,8 @@ abort_due_to_error:
p->rc = rc;
sqlite3SystemError(db, rc);
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(rc, "statement aborts at %d: [%s] %s",
- (int)(pOp - aOp), p->zSql, p->zErrMsg);
+ sqlite3_log(rc, "statement aborts at %d: %s; [%s]",
+ (int)(pOp - aOp), p->zErrMsg, p->zSql);
if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);
if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){
@@ -102416,6 +103709,7 @@ SQLITE_API int sqlite3_blob_open(
char *zErr = 0;
Table *pTab;
Incrblob *pBlob = 0;
+ int iDb;
Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -102450,13 +103744,21 @@ SQLITE_API int sqlite3_blob_open(
pTab = 0;
sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
}
+ if( pTab && (pTab->tabFlags&TF_HasGenerated)!=0 ){
+ pTab = 0;
+ sqlite3ErrorMsg(&sParse, "cannot open table with generated columns: %s",
+ zTable);
+ }
#ifndef SQLITE_OMIT_VIEW
if( pTab && IsView(pTab) ){
pTab = 0;
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
}
#endif
- if( !pTab ){
+ if( pTab==0
+ || ((iDb = sqlite3SchemaToIndex(db, pTab->pSchema))==1 &&
+ sqlite3OpenTempDatabase(&sParse))
+ ){
if( sParse.zErrMsg ){
sqlite3DbFree(db, zErr);
zErr = sParse.zErrMsg;
@@ -102467,15 +103769,11 @@ SQLITE_API int sqlite3_blob_open(
goto blob_open_out;
}
pBlob->pTab = pTab;
- pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
+ pBlob->zDb = db->aDb[iDb].zDbSName;
/* Now search pTab for the exact column. */
- for(iCol=0; iCol<pTab->nCol; iCol++) {
- if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){
- break;
- }
- }
- if( iCol==pTab->nCol ){
+ iCol = sqlite3ColumnIndex(pTab, zColumn);
+ if( iCol<0 ){
sqlite3DbFree(db, zErr);
zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn);
rc = SQLITE_ERROR;
@@ -102555,7 +103853,6 @@ SQLITE_API int sqlite3_blob_open(
{OP_Halt, 0, 0, 0}, /* 5 */
};
Vdbe *v = (Vdbe *)pBlob->pStmt;
- int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
VdbeOp *aOp;
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag,
@@ -103133,9 +104430,12 @@ struct VdbeSorter {
u8 iPrev; /* Previous thread used to flush PMA */
u8 nTask; /* Size of aTask[] array */
u8 typeMask;
- SortSubtask aTask[1]; /* One or more subtasks */
+ SortSubtask aTask[FLEXARRAY]; /* One or more subtasks */
};
+/* Size (in bytes) of a VdbeSorter object that works with N or fewer subtasks */
+#define SZ_VDBESORTER(N) (offsetof(VdbeSorter,aTask)+(N)*sizeof(SortSubtask))
+
#define SORTER_TYPE_INTEGER 0x01
#define SORTER_TYPE_TEXT 0x02
@@ -103357,13 +104657,14 @@ static int vdbePmaReadBlob(
while( nRem>0 ){
int rc; /* vdbePmaReadBlob() return code */
int nCopy; /* Number of bytes to copy */
- u8 *aNext; /* Pointer to buffer to copy data from */
+ u8 *aNext = 0; /* Pointer to buffer to copy data from */
nCopy = nRem;
if( nRem>p->nBuffer ) nCopy = p->nBuffer;
rc = vdbePmaReadBlob(p, nCopy, &aNext);
if( rc!=SQLITE_OK ) return rc;
assert( aNext!=p->aAlloc );
+ assert( aNext!=0 );
memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy);
nRem -= nCopy;
}
@@ -103736,7 +105037,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
VdbeSorter *pSorter; /* The new sorter */
KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */
int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */
- int sz; /* Size of pSorter in bytes */
+ i64 sz; /* Size of pSorter in bytes */
int rc = SQLITE_OK;
#if SQLITE_MAX_WORKER_THREADS==0
# define nWorker 0
@@ -103764,8 +105065,10 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
assert( pCsr->pKeyInfo );
assert( !pCsr->isEphemeral );
assert( pCsr->eCurType==CURTYPE_SORTER );
- szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
- sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
+ assert( sizeof(KeyInfo) + UMXV(pCsr->pKeyInfo->nKeyField)*sizeof(CollSeq*)
+ < 0x7fffffff );
+ szKeyInfo = SZ_KEYINFO(pCsr->pKeyInfo->nKeyField);
+ sz = SZ_VDBESORTER(nWorker+1);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
pCsr->uc.pSorter = pSorter;
@@ -103977,7 +105280,7 @@ static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){
*/
static MergeEngine *vdbeMergeEngineNew(int nReader){
int N = 2; /* Smallest power of two >= nReader */
- int nByte; /* Total bytes of space to allocate */
+ i64 nByte; /* Total bytes of space to allocate */
MergeEngine *pNew; /* Pointer to allocated object to return */
assert( nReader<=SORTER_MAX_MERGE_COUNT );
@@ -104229,6 +105532,10 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
p->u.pNext = 0;
for(i=0; aSlot[i]; i++){
p = vdbeSorterMerge(pTask, p, aSlot[i]);
+ /* ,--Each aSlot[] holds twice as much as the previous. So we cannot use
+ ** | up all 64 aSlots[] with only a 64-bit address space.
+ ** v */
+ assert( i<ArraySize(aSlot) );
aSlot[i] = 0;
}
aSlot[i] = p;
@@ -106633,7 +107940,9 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
pSrc = p->pSrc;
if( ALWAYS(pSrc) ){
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
- if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
+ if( pItem->fg.isSubquery
+ && sqlite3WalkSelect(pWalker, pItem->u4.pSubq->pSelect)
+ ){
return WRC_Abort;
}
if( pItem->fg.isTabFunc
@@ -106939,7 +108248,7 @@ static void extendFJMatch(
if( pNew ){
pNew->iTable = pMatch->iCursor;
pNew->iColumn = iColumn;
- pNew->y.pTab = pMatch->pTab;
+ pNew->y.pTab = pMatch->pSTab;
assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
ExprSetProperty(pNew, EP_CanBeNull);
*ppList = sqlite3ExprListAppend(pParse, *ppList, pNew);
@@ -107018,7 +108327,6 @@ static int lookupName(
Schema *pSchema = 0; /* Schema of the expression */
int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
Table *pTab = 0; /* Table holding the row */
- Column *pCol; /* A column of pTab */
ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */
const char *zCol = pRight->u.zToken;
@@ -107069,11 +108377,10 @@ static int lookupName(
if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
- u8 hCol;
- pTab = pItem->pTab;
+ pTab = pItem->pSTab;
assert( pTab!=0 && pTab->zName!=0 );
assert( pTab->nCol>0 || pParse->nErr );
- assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem));
if( pItem->fg.isNestedFrom ){
/* In this case, pItem is a subquery that has been formed from a
** parenthesized subset of the FROM clause terms. Example:
@@ -107082,8 +108389,12 @@ static int lookupName(
** This pItem -------------^
*/
int hit = 0;
- assert( pItem->pSelect!=0 );
- pEList = pItem->pSelect->pEList;
+ Select *pSel;
+ assert( pItem->fg.isSubquery );
+ assert( pItem->u4.pSubq!=0 );
+ pSel = pItem->u4.pSubq->pSelect;
+ assert( pSel!=0 );
+ pEList = pSel->pEList;
assert( pEList!=0 );
assert( pEList->nExpr==pTab->nCol );
for(j=0; j<pEList->nExpr; j++){
@@ -107153,43 +108464,38 @@ static int lookupName(
sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
}
}
- hCol = sqlite3StrIHash(zCol);
- for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
- if( pCol->hName==hCol
- && sqlite3StrICmp(pCol->zCnName, zCol)==0
- ){
- if( cnt>0 ){
- if( pItem->fg.isUsing==0
- || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
- ){
- /* Two or more tables have the same column name which is
- ** not joined by USING. This is an error. Signal as much
- ** by clearing pFJMatch and letting cnt go above 1. */
- sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else
- if( (pItem->fg.jointype & JT_RIGHT)==0 ){
- /* An INNER or LEFT JOIN. Use the left-most table */
- continue;
- }else
- if( (pItem->fg.jointype & JT_LEFT)==0 ){
- /* A RIGHT JOIN. Use the right-most table */
- cnt = 0;
- sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else{
- /* For a FULL JOIN, we must construct a coalesce() func */
- extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
- }
- }
- cnt++;
- pMatch = pItem;
- /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
- pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
- if( pItem->fg.isNestedFrom ){
- sqlite3SrcItemColumnUsed(pItem, j);
+ j = sqlite3ColumnIndex(pTab, zCol);
+ if( j>=0 ){
+ if( cnt>0 ){
+ if( pItem->fg.isUsing==0
+ || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
+ ){
+ /* Two or more tables have the same column name which is
+ ** not joined by USING. This is an error. Signal as much
+ ** by clearing pFJMatch and letting cnt go above 1. */
+ sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else
+ if( (pItem->fg.jointype & JT_RIGHT)==0 ){
+ /* An INNER or LEFT JOIN. Use the left-most table */
+ continue;
+ }else
+ if( (pItem->fg.jointype & JT_LEFT)==0 ){
+ /* A RIGHT JOIN. Use the right-most table */
+ cnt = 0;
+ sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else{
+ /* For a FULL JOIN, we must construct a coalesce() func */
+ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
}
- break;
+ }
+ cnt++;
+ pMatch = pItem;
+ /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
+ pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
+ if( pItem->fg.isNestedFrom ){
+ sqlite3SrcItemColumnUsed(pItem, j);
}
}
if( 0==cnt && VisibleRowid(pTab) ){
@@ -107206,9 +108512,9 @@ static int lookupName(
*/
if( cntTab==0
|| (cntTab==1
- && ALWAYS(pMatch!=0)
- && ALWAYS(pMatch->pTab!=0)
- && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0
+ && pMatch!=0
+ && ALWAYS(pMatch->pSTab!=0)
+ && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0
&& (pTab->tabFlags & TF_Ephemeral)==0)
){
cntTab = 1;
@@ -107229,7 +108535,7 @@ static int lookupName(
if( pMatch ){
pExpr->iTable = pMatch->iCursor;
assert( ExprUseYTab(pExpr) );
- pExpr->y.pTab = pMatch->pTab;
+ pExpr->y.pTab = pMatch->pSTab;
if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
ExprSetProperty(pExpr, EP_CanBeNull);
}
@@ -107271,7 +108577,7 @@ static int lookupName(
if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){
Upsert *pUpsert = pNC->uNC.pUpsert;
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
- pTab = pUpsert->pUpsertSrc->a[0].pTab;
+ pTab = pUpsert->pUpsertSrc->a[0].pSTab;
pExpr->iTable = EXCLUDED_TABLE_NUMBER;
}
}
@@ -107279,23 +108585,18 @@ static int lookupName(
if( pTab ){
int iCol;
- u8 hCol = sqlite3StrIHash(zCol);
pSchema = pTab->pSchema;
cntTab++;
- for(iCol=0, pCol=pTab->aCol; iCol<pTab->nCol; iCol++, pCol++){
- if( pCol->hName==hCol
- && sqlite3StrICmp(pCol->zCnName, zCol)==0
- ){
- if( iCol==pTab->iPKey ){
- iCol = -1;
- }
- break;
+ iCol = sqlite3ColumnIndex(pTab, zCol);
+ if( iCol>=0 ){
+ if( pTab->iPKey==iCol ) iCol = -1;
+ }else{
+ if( sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
+ iCol = -1;
+ }else{
+ iCol = pTab->nCol;
}
}
- if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
- /* IMP: R-51414-32910 */
- iCol = -1;
- }
if( iCol<pTab->nCol ){
cnt++;
pMatch = 0;
@@ -107354,11 +108655,11 @@ static int lookupName(
&& pMatch
&& (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
&& sqlite3IsRowid(zCol)
- && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom)
+ && ALWAYS(VisibleRowid(pMatch->pSTab) || pMatch->fg.isNestedFrom)
){
cnt = cntTab;
#if SQLITE_ALLOW_ROWID_IN_VIEW+0==2
- if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){
+ if( pMatch->pSTab!=0 && IsView(pMatch->pSTab) ){
eNewExprOp = TK_NULL;
}
#endif
@@ -107595,7 +108896,7 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr
SrcItem *pItem = &pSrc->a[iSrc];
Table *pTab;
assert( ExprUseYTab(p) );
- pTab = p->y.pTab = pItem->pTab;
+ pTab = p->y.pTab = pItem->pSTab;
p->iTable = pItem->iCursor;
if( p->y.pTab->iPKey==iCol ){
p->iColumn = -1;
@@ -107714,7 +109015,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pItem = pSrcList->a;
pExpr->op = TK_COLUMN;
assert( ExprUseYTab(pExpr) );
- pExpr->y.pTab = pItem->pTab;
+ pExpr->y.pTab = pItem->pSTab;
pExpr->iTable = pItem->iCursor;
pExpr->iColumn--;
pExpr->affExpr = SQLITE_AFF_INTEGER;
@@ -107839,8 +109140,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
/* Resolve function names
*/
case TK_FUNCTION: {
- ExprList *pList = pExpr->x.pList; /* The argument list */
- int n = pList ? pList->nExpr : 0; /* Number of arguments */
+ ExprList *pList; /* The argument list */
+ int n; /* Number of arguments */
int no_such_func = 0; /* True if no such function exists */
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
@@ -107853,6 +109154,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
#endif
assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER );
+ pList = pExpr->x.pList;
+ n = pList ? pList->nExpr : 0;
zId = pExpr->u.zToken;
pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
if( pDef==0 ){
@@ -107901,6 +109204,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
}
#endif
+
+ /* If the function may call sqlite3_value_subtype(), then set the
+ ** EP_SubtArg flag on all of its argument expressions. This prevents
+ ** where.c from replacing the expression with a value read from an
+ ** index on the same expression, which will not have the correct
+ ** subtype. Also set the flag if the function expression itself is
+ ** an EP_SubtArg expression. In this case subtypes are required as
+ ** the function may return a value with a subtype back to its
+ ** caller using sqlite3_result_value(). */
+ if( (pDef->funcFlags & SQLITE_SUBTYPE)
+ || ExprHasProperty(pExpr, EP_SubtArg)
+ ){
+ int ii;
+ for(ii=0; ii<n; ii++){
+ ExprSetProperty(pList->a[ii].pExpr, EP_SubtArg);
+ }
+ }
+
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
@@ -107914,13 +109235,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
** sqlite_version() that might change over time cannot be used
** in an index or generated column. Curiously, they can be used
** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all
- ** all this. */
+ ** allow this. */
sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions",
NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr);
}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
@@ -107936,6 +109256,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0
&& !IN_RENAME_OBJECT
){
+ if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL);
sqlite3ExprFunctionUsable(pParse, pExpr, pDef);
}
}
@@ -108020,9 +109341,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
- if( pWin ){
+ if( pWin && pParse->nErr==0 ){
Select *pSel = pNC->pWinSelect;
- assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) );
+ assert( ExprUseYWin(pExpr) && pWin==pExpr->y.pWin );
if( IN_RENAME_OBJECT==0 ){
sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
if( pParse->db->mallocFailed ) break;
@@ -108229,7 +109550,7 @@ static int resolveOrderByTermToExprList(
int rc; /* Return code from subprocedures */
u8 savedSuppErr; /* Saved value of db->suppressErr */
- assert( sqlite3ExprIsInteger(pE, &i)==0 );
+ assert( sqlite3ExprIsInteger(pE, &i, 0)==0 );
pEList = pSelect->pEList;
/* Resolve all names in the ORDER BY term expression
@@ -108328,7 +109649,7 @@ static int resolveCompoundOrderBy(
if( pItem->fg.done ) continue;
pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
if( NEVER(pE==0) ) continue;
- if( sqlite3ExprIsInteger(pE, &iCol) ){
+ if( sqlite3ExprIsInteger(pE, &iCol, 0) ){
if( iCol<=0 || iCol>pEList->nExpr ){
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr, pE);
return 1;
@@ -108513,7 +109834,7 @@ static int resolveOrderGroupBy(
continue;
}
}
- if( sqlite3ExprIsInteger(pE2, &iCol) ){
+ if( sqlite3ExprIsInteger(pE2, &iCol, 0) ){
/* The ORDER BY term is an integer constant. Again, set the column
** number so that sqlite3ResolveOrderGroupBy() will convert the
** order-by term to a copy of the result-set expression */
@@ -108604,7 +109925,11 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** moves the pOrderBy down to the sub-query. It will be moved back
** after the names have been resolved. */
if( p->selFlags & SF_Converted ){
- Select *pSub = p->pSrc->a[0].pSelect;
+ Select *pSub;
+ assert( p->pSrc->a[0].fg.isSubquery );
+ assert( p->pSrc->a[0].u4.pSubq!=0 );
+ pSub = p->pSrc->a[0].u4.pSubq->pSelect;
+ assert( pSub!=0 );
assert( p->pSrc->nSrc==1 && p->pOrderBy );
assert( pSub->pPrior && pSub->pOrderBy==0 );
pSub->pOrderBy = p->pOrderBy;
@@ -108616,13 +109941,16 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
if( pOuterNC ) pOuterNC->nNestedSelect++;
for(i=0; i<p->pSrc->nSrc; i++){
SrcItem *pItem = &p->pSrc->a[i];
- assert( pItem->zName!=0 || pItem->pSelect!=0 );/* Test of tag-20240424-1*/
- if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
+ assert( pItem->zName!=0
+ || pItem->fg.isSubquery ); /* Test of tag-20240424-1*/
+ if( pItem->fg.isSubquery
+ && (pItem->u4.pSubq->pSelect->selFlags & SF_Resolved)==0
+ ){
int nRef = pOuterNC ? pOuterNC->nRef : 0;
const char *zSavedContext = pParse->zAuthContext;
if( pItem->zName ) pParse->zAuthContext = pItem->zName;
- sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
+ sqlite3ResolveSelectNames(pParse, pItem->u4.pSubq->pSelect, pOuterNC);
pParse->zAuthContext = zSavedContext;
if( pParse->nErr ) return WRC_Abort;
assert( db->mallocFailed==0 );
@@ -108724,7 +110052,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** These integers will be replaced by copies of the corresponding result
** set expressions by the call to resolveOrderGroupBy() below. */
if( p->selFlags & SF_Converted ){
- Select *pSub = p->pSrc->a[0].pSelect;
+ Select *pSub;
+ assert( p->pSrc->a[0].fg.isSubquery );
+ pSub = p->pSrc->a[0].u4.pSubq->pSelect;
+ assert( pSub!=0 );
p->pOrderBy = pSub->pOrderBy;
pSub->pOrderBy = 0;
}
@@ -108979,20 +110310,22 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference(
Expr *pExpr, /* Expression to resolve. May be NULL. */
ExprList *pList /* Expression list to resolve. May be NULL. */
){
- SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
+ SrcList *pSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
int rc;
+ u8 srcSpace[SZ_SRCLIST_1]; /* Memory space for the fake SrcList */
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));
+ pSrc = (SrcList*)srcSpace;
+ memset(pSrc, 0, SZ_SRCLIST_1);
if( pTab ){
- sSrc.nSrc = 1;
- sSrc.a[0].zName = pTab->zName;
- sSrc.a[0].pTab = pTab;
- sSrc.a[0].iCursor = -1;
+ pSrc->nSrc = 1;
+ pSrc->a[0].zName = pTab->zName;
+ pSrc->a[0].pSTab = pTab;
+ pSrc->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 */
@@ -109000,7 +110333,7 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference(
}
}
sNC.pParse = pParse;
- sNC.pSrcList = &sSrc;
+ sNC.pSrcList = pSrc;
sNC.ncFlags = type | NC_IsDDL;
if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc;
if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList);
@@ -109084,7 +110417,9 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
);
}
- if( op==TK_VECTOR ){
+ if( op==TK_VECTOR
+ || (op==TK_FUNCTION && pExpr->affExpr==SQLITE_AFF_DEFER)
+ ){
assert( ExprUseXList(pExpr) );
return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
}
@@ -109096,7 +110431,9 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){
op = pExpr->op;
continue;
}
- if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break;
+ if( op!=TK_REGISTER ) break;
+ op = pExpr->op2;
+ if( NEVER( op==TK_REGISTER ) ) break;
}
return pExpr->affExpr;
}
@@ -109275,7 +110612,9 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
p = p->pLeft;
continue;
}
- if( op==TK_VECTOR ){
+ if( op==TK_VECTOR
+ || (op==TK_FUNCTION && p->affExpr==SQLITE_AFF_DEFER)
+ ){
assert( ExprUseXList(p) );
p = p->x.pList->a[0].pExpr;
continue;
@@ -109488,7 +110827,7 @@ static int codeCompare(
p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
(void*)p4, P4_COLLSEQ);
- sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5);
+ sqlite3VdbeChangeP5(pParse->pVdbe, (u16)p5);
return addr;
}
@@ -110747,7 +112086,7 @@ static Expr *exprDup(
SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){
With *pRet = 0;
if( p ){
- sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1);
+ sqlite3_int64 nByte = SZ_WITH(p->nCte);
pRet = sqlite3DbMallocZero(db, nByte);
if( pRet ){
int i;
@@ -110858,7 +112197,6 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int
}
pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName);
pItem->fg = pOldItem->fg;
- pItem->fg.done = 0;
pItem->u = pOldItem->u;
}
return pNew;
@@ -110875,26 +112213,39 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
SrcList *pNew;
int i;
- int nByte;
assert( db!=0 );
if( p==0 ) return 0;
- nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
- pNew = sqlite3DbMallocRawNN(db, nByte );
+ pNew = sqlite3DbMallocRawNN(db, SZ_SRCLIST(p->nSrc) );
if( pNew==0 ) return 0;
pNew->nSrc = pNew->nAlloc = p->nSrc;
for(i=0; i<p->nSrc; i++){
SrcItem *pNewItem = &pNew->a[i];
const SrcItem *pOldItem = &p->a[i];
Table *pTab;
- pNewItem->pSchema = pOldItem->pSchema;
- pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
+ pNewItem->fg = pOldItem->fg;
+ if( pOldItem->fg.isSubquery ){
+ Subquery *pNewSubq = sqlite3DbMallocRaw(db, sizeof(Subquery));
+ if( pNewSubq==0 ){
+ assert( db->mallocFailed );
+ pNewItem->fg.isSubquery = 0;
+ }else{
+ memcpy(pNewSubq, pOldItem->u4.pSubq, sizeof(*pNewSubq));
+ pNewSubq->pSelect = sqlite3SelectDup(db, pNewSubq->pSelect, flags);
+ if( pNewSubq->pSelect==0 ){
+ sqlite3DbFree(db, pNewSubq);
+ pNewSubq = 0;
+ pNewItem->fg.isSubquery = 0;
+ }
+ }
+ pNewItem->u4.pSubq = pNewSubq;
+ }else if( pOldItem->fg.fixedSchema ){
+ pNewItem->u4.pSchema = pOldItem->u4.pSchema;
+ }else{
+ pNewItem->u4.zDatabase = sqlite3DbStrDup(db, pOldItem->u4.zDatabase);
+ }
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
- pNewItem->fg = pOldItem->fg;
pNewItem->iCursor = pOldItem->iCursor;
- pNewItem->addrFillSub = pOldItem->addrFillSub;
- pNewItem->regReturn = pOldItem->regReturn;
- pNewItem->regResult = pOldItem->regResult;
if( pNewItem->fg.isIndexedBy ){
pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
}else if( pNewItem->fg.isTabFunc ){
@@ -110907,11 +112258,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int fla
if( pNewItem->fg.isCte ){
pNewItem->u2.pCteUse->nUse++;
}
- pTab = pNewItem->pTab = pOldItem->pTab;
+ pTab = pNewItem->pSTab = pOldItem->pSTab;
if( pTab ){
pTab->nTabRef++;
}
- pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
if( pOldItem->fg.isUsing ){
assert( pNewItem->fg.isUsing );
pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
@@ -110927,16 +112277,13 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){
int i;
assert( db!=0 );
if( p==0 ) return 0;
- assert( p->eU4!=EU4_EXPR );
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) );
+ pNew = sqlite3DbMallocRawNN(db, SZ_IDLIST(p->nId));
if( pNew==0 ) return 0;
pNew->nId = p->nId;
- pNew->eU4 = p->eU4;
for(i=0; i<p->nId; i++){
struct IdList_item *pNewItem = &pNew->a[i];
const struct IdList_item *pOldItem = &p->a[i];
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
- pNewItem->u4 = pOldItem->u4;
}
return pNew;
}
@@ -110962,7 +112309,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int fla
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
pNew->iLimit = 0;
pNew->iOffset = 0;
- pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
+ pNew->selFlags = p->selFlags & ~(u32)SF_UsesEphemeral;
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = p->nSelectRow;
@@ -110985,7 +112332,6 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int fla
pp = &pNew->pPrior;
pNext = pNew;
}
-
return pRet;
}
#else
@@ -111015,7 +112361,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew(
struct ExprList_item *pItem;
ExprList *pList;
- pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 );
+ pList = sqlite3DbMallocRawNN(db, SZ_EXPRLIST(4));
if( pList==0 ){
sqlite3ExprDelete(db, pExpr);
return 0;
@@ -111035,8 +112381,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow(
struct ExprList_item *pItem;
ExprList *pNew;
pList->nAlloc *= 2;
- pNew = sqlite3DbRealloc(db, pList,
- sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0]));
+ pNew = sqlite3DbRealloc(db, pList, SZ_EXPRLIST(pList->nAlloc));
if( pNew==0 ){
sqlite3ExprListDelete(db, pList);
sqlite3ExprDelete(db, pExpr);
@@ -111642,7 +112987,7 @@ static int sqlite3ExprIsTableConstant(Expr *p, int iCur, int bAllowSubq){
** (4a) pExpr must come from an ON clause..
** (4b) and specifically the ON clause associated with the LEFT JOIN.
**
-** (5) If pSrc is not the right operand of a LEFT JOIN or the left
+** (5) If pSrc is the right operand of a LEFT JOIN or the left
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
** clause, not an ON clause.
**
@@ -111800,8 +113145,12 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){
** to fit in a 32-bit integer, return 1 and put the value of the integer
** in *pValue. If the expression is not an integer or if it is too big
** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
+**
+** If the pParse pointer is provided, then allow the expression p to be
+** a parameter (TK_VARIABLE) that is bound to an integer.
+** But if pParse is NULL, then p must be a pure integer literal.
*/
-SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr *p, int *pValue){
+SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr *p, int *pValue, Parse *pParse){
int rc = 0;
if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */
@@ -111816,18 +113165,38 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr *p, int *pValue){
}
switch( p->op ){
case TK_UPLUS: {
- rc = sqlite3ExprIsInteger(p->pLeft, pValue);
+ rc = sqlite3ExprIsInteger(p->pLeft, pValue, 0);
break;
}
case TK_UMINUS: {
int v = 0;
- if( sqlite3ExprIsInteger(p->pLeft, &v) ){
+ if( sqlite3ExprIsInteger(p->pLeft, &v, 0) ){
assert( ((unsigned int)v)!=0x80000000 );
*pValue = -v;
rc = 1;
}
break;
}
+ case TK_VARIABLE: {
+ sqlite3_value *pVal;
+ if( pParse==0 ) break;
+ if( NEVER(pParse->pVdbe==0) ) break;
+ if( (pParse->db->flags & SQLITE_EnableQPSG)!=0 ) break;
+ sqlite3VdbeSetVarmask(pParse->pVdbe, p->iColumn);
+ pVal = sqlite3VdbeGetBoundValue(pParse->pReprepare, p->iColumn,
+ SQLITE_AFF_BLOB);
+ if( pVal ){
+ if( sqlite3_value_type(pVal)==SQLITE_INTEGER ){
+ sqlite3_int64 vv = sqlite3_value_int64(pVal);
+ if( vv == (vv & 0x7fffffff) ){ /* non-negative numbers only */
+ *pValue = (int)vv;
+ rc = 1;
+ }
+ }
+ sqlite3ValueFree(pVal);
+ }
+ break;
+ }
default: break;
}
return rc;
@@ -111941,13 +113310,7 @@ SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab){
int ii;
assert( VisibleRowid(pTab) );
for(ii=0; ii<ArraySize(azOpt); ii++){
- int iCol;
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break;
- }
- if( iCol==pTab->nCol ){
- return azOpt[ii];
- }
+ if( sqlite3ColumnIndex(pTab, azOpt[ii])<0 ) return azOpt[ii];
}
return 0;
}
@@ -111981,8 +113344,8 @@ static Select *isCandidateForInOpt(const Expr *pX){
pSrc = p->pSrc;
assert( pSrc!=0 );
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
- if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
- pTab = pSrc->a[0].pTab;
+ if( pSrc->a[0].fg.isSubquery) return 0;/* FROM is not a subquery or view */
+ pTab = pSrc->a[0].pSTab;
assert( pTab!=0 );
assert( !IsView(pTab) ); /* FROM clause is not a view */
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
@@ -112165,7 +113528,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
- pTab = p->pSrc->a[0].pTab;
+ pTab = p->pSrc->a[0].pSTab;
/* Code an OP_Transaction and OP_TableLock for <table>. */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -112257,6 +113620,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
if( aiMap ) aiMap[i] = j;
}
+ assert( nExpr>0 && nExpr<BMS );
assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) );
if( colUsed==(MASKBIT(nExpr)-1) ){
/* If we reach this point, that means the index pIdx is usable */
@@ -112350,7 +113714,7 @@ static char *exprINAffinity(Parse *pParse, const Expr *pExpr){
char *zRet;
assert( pExpr->op==TK_IN );
- zRet = sqlite3DbMallocRaw(pParse->db, nVal+1);
+ zRet = sqlite3DbMallocRaw(pParse->db, 1+(i64)nVal);
if( zRet ){
int i;
for(i=0; i<nVal; i++){
@@ -112407,6 +113771,50 @@ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
#ifndef SQLITE_OMIT_SUBQUERY
/*
+** Scan all previously generated bytecode looking for an OP_BeginSubrtn
+** that is compatible with pExpr. If found, add the y.sub values
+** to pExpr and return true. If not found, return false.
+*/
+static int findCompatibleInRhsSubrtn(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* IN operator with RHS that we want to reuse */
+ SubrtnSig *pNewSig /* Signature for the IN operator */
+){
+ VdbeOp *pOp, *pEnd;
+ SubrtnSig *pSig;
+ Vdbe *v;
+
+ if( pNewSig==0 ) return 0;
+ if( (pParse->mSubrtnSig & (1<<(pNewSig->selId&7)))==0 ) return 0;
+ assert( pExpr->op==TK_IN );
+ assert( !ExprUseYSub(pExpr) );
+ assert( ExprUseXSelect(pExpr) );
+ assert( pExpr->x.pSelect!=0 );
+ assert( (pExpr->x.pSelect->selFlags & SF_All)==0 );
+ v = pParse->pVdbe;
+ assert( v!=0 );
+ pOp = sqlite3VdbeGetOp(v, 1);
+ pEnd = sqlite3VdbeGetLastOp(v);
+ for(; pOp<pEnd; pOp++){
+ if( pOp->p4type!=P4_SUBRTNSIG ) continue;
+ assert( pOp->opcode==OP_BeginSubrtn );
+ pSig = pOp->p4.pSubrtnSig;
+ assert( pSig!=0 );
+ if( !pSig->bComplete ) continue;
+ if( pNewSig->selId!=pSig->selId ) continue;
+ if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue;
+ pExpr->y.sub.iAddr = pSig->iAddr;
+ pExpr->y.sub.regReturn = pSig->regReturn;
+ pExpr->iTable = pSig->iTable;
+ ExprSetProperty(pExpr, EP_Subrtn);
+ return 1;
+ }
+ return 0;
+}
+#endif /* SQLITE_OMIT_SUBQUERY */
+
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
** 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:
@@ -112439,6 +113847,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
KeyInfo *pKeyInfo = 0; /* Key information */
int nVal; /* Size of vector pLeft */
Vdbe *v; /* The prepared statement under construction */
+ SubrtnSig *pSig = 0; /* Signature for this subroutine */
v = pParse->pVdbe;
assert( v!=0 );
@@ -112454,11 +113863,27 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
** and reuse it many names.
*/
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.
+ /* Reuse of the RHS is allowed
+ **
+ ** Compute a signature for the RHS of the IN operator to facility
+ ** finding and reusing prior instances of the same IN operator.
+ */
+ assert( !ExprUseXSelect(pExpr) || pExpr->x.pSelect!=0 );
+ if( ExprUseXSelect(pExpr) && (pExpr->x.pSelect->selFlags & SF_All)==0 ){
+ pSig = sqlite3DbMallocRawNN(pParse->db, sizeof(pSig[0]));
+ if( pSig ){
+ pSig->selId = pExpr->x.pSelect->selId;
+ pSig->zAff = exprINAffinity(pParse, pExpr);
+ }
+ }
+
+ /* Check to see if there is a prior materialization of the RHS of
+ ** this IN operator. If there is, then make use of that prior
+ ** materialization rather than recomputing it.
*/
- if( ExprHasProperty(pExpr, EP_Subrtn) ){
+ if( ExprHasProperty(pExpr, EP_Subrtn)
+ || findCompatibleInRhsSubrtn(pParse, pExpr, pSig)
+ ){
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
if( ExprUseXSelect(pExpr) ){
ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d",
@@ -112470,6 +113895,10 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
assert( iTab!=pExpr->iTable );
sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
sqlite3VdbeJumpHere(v, addrOnce);
+ if( pSig ){
+ sqlite3DbFree(pParse->db, pSig->zAff);
+ sqlite3DbFree(pParse->db, pSig);
+ }
return;
}
@@ -112480,7 +113909,14 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
pExpr->y.sub.regReturn = ++pParse->nMem;
pExpr->y.sub.iAddr =
sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1;
-
+ if( pSig ){
+ pSig->bComplete = 0;
+ pSig->iAddr = pExpr->y.sub.iAddr;
+ pSig->regReturn = pExpr->y.sub.regReturn;
+ pSig->iTable = iTab;
+ pParse->mSubrtnSig = 1 << (pSig->selId&7);
+ sqlite3VdbeChangeP4(v, -1, (const char*)pSig, P4_SUBRTNSIG);
+ }
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
@@ -112521,15 +113957,31 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
SelectDest dest;
int i;
int rc;
+ int addrBloom = 0;
sqlite3SelectDestInit(&dest, SRT_Set, iTab);
dest.zAffSdst = exprINAffinity(pParse, pExpr);
pSelect->iLimit = 0;
+ if( addrOnce && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){
+ int regBloom = ++pParse->nMem;
+ addrBloom = sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom);
+ VdbeComment((v, "Bloom filter"));
+ dest.iSDParm2 = regBloom;
+ }
testcase( pSelect->selFlags & SF_Distinct );
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
pCopy = sqlite3SelectDup(pParse->db, pSelect, 0);
rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest);
sqlite3SelectDelete(pParse->db, pCopy);
sqlite3DbFree(pParse->db, dest.zAffSdst);
+ if( addrBloom ){
+ /* Remember that location of the Bloom filter in the P3 operand
+ ** of the OP_Once that began this subroutine. tag-202407032019 */
+ sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2;
+ if( dest.iSDParm2==0 ){
+ /* If the Bloom filter won't actually be used, keep it small */
+ sqlite3VdbeGetOp(v, addrBloom)->p1 = 10;
+ }
+ }
if( rc ){
sqlite3KeyInfoUnref(pKeyInfo);
return;
@@ -112595,6 +114047,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
+ if( pSig ) pSig->bComplete = 1;
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
}
@@ -112827,9 +114280,7 @@ static void sqlite3ExprCodeIN(
if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
zAff = exprINAffinity(pParse, pExpr);
nVector = sqlite3ExprVectorSize(pExpr->pLeft);
- aiMap = (int*)sqlite3DbMallocZero(
- pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
- );
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, nVector*sizeof(int));
if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error;
/* Attempt to compute the RHS. After this step, if anything other than
@@ -112972,6 +114423,15 @@ static void sqlite3ExprCodeIN(
sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector);
if( destIfFalse==destIfNull ){
/* Combine Step 3 and Step 5 into a single opcode */
+ if( ExprHasProperty(pExpr, EP_Subrtn) ){
+ const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr);
+ assert( pOp->opcode==OP_Once || pParse->nErr );
+ if( pOp->opcode==OP_Once && pOp->p3>0 ){ /* tag-202407032019 */
+ assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) );
+ sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse,
+ rLhs, nVector); VdbeCoverage(v);
+ }
+ }
sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse,
rLhs, nVector); VdbeCoverage(v);
goto sqlite3ExprCodeIN_finished;
@@ -113254,13 +114714,17 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n
** register iReg. The caller must ensure that iReg already contains
** the correct value for the expression.
*/
-static void exprToRegister(Expr *pExpr, int iReg){
+SQLITE_PRIVATE void sqlite3ExprToRegister(Expr *pExpr, int iReg){
Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
if( NEVER(p==0) ) return;
- p->op2 = p->op;
- p->op = TK_REGISTER;
- p->iTable = iReg;
- ExprClearProperty(p, EP_Skip);
+ if( p->op==TK_REGISTER ){
+ assert( p->iTable==iReg );
+ }else{
+ p->op2 = p->op;
+ p->op = TK_REGISTER;
+ p->iTable = iReg;
+ ExprClearProperty(p, EP_Skip);
+ }
}
/*
@@ -113431,6 +114895,59 @@ static int exprCodeInlineFunction(
}
/*
+** Expression Node callback for sqlite3ExprCanReturnSubtype().
+**
+** Only a function call is able to return a subtype. So if the node
+** is not a function call, return WRC_Prune immediately.
+**
+** A function call is able to return a subtype if it has the
+** SQLITE_RESULT_SUBTYPE property.
+**
+** Assume that every function is able to pass-through a subtype from
+** one of its argument (using sqlite3_result_value()). Most functions
+** are not this way, but we don't have a mechanism to distinguish those
+** that are from those that are not, so assume they all work this way.
+** That means that if one of its arguments is another function and that
+** other function is able to return a subtype, then this function is
+** able to return a subtype.
+*/
+static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
+ int n;
+ FuncDef *pDef;
+ sqlite3 *db;
+ if( pExpr->op!=TK_FUNCTION ){
+ return WRC_Prune;
+ }
+ assert( ExprUseXList(pExpr) );
+ db = pWalker->pParse->db;
+ n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0;
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
+ if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
+ pWalker->eCode = 1;
+ return WRC_Prune;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Return TRUE if expression pExpr is able to return a subtype.
+**
+** A TRUE return does not guarantee that a subtype will be returned.
+** It only indicates that a subtype return is possible. False positives
+** are acceptable as they only disable an optimization. False negatives,
+** on the other hand, can lead to incorrect answers.
+*/
+static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.pParse = pParse;
+ w.xExprCallback = exprNodeCanReturnSubtype;
+ sqlite3WalkExpr(&w, pExpr);
+ return w.eCode;
+}
+
+
+/*
** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
** If it is, then resolve the expression by reading from the index and
** return the register into which the value has been read. If pExpr is
@@ -113462,6 +114979,17 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
continue;
}
+
+ /* Functions that might set a subtype should not be replaced by the
+ ** value taken from an expression index if they are themselves an
+ ** argument to another scalar function or aggregate.
+ ** https://sqlite.org/forum/forumpost/68d284c86b082c3e */
+ if( ExprHasProperty(pExpr, EP_SubtArg)
+ && sqlite3ExprCanReturnSubtype(pParse, pExpr)
+ ){
+ continue;
+ }
+
v = pParse->pVdbe;
assert( v!=0 );
if( p->bMaybeNullRow ){
@@ -113490,7 +115018,7 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
/*
-** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This
+** Expression pExpr is guaranteed to be a TK_COLUMN or equivalent. This
** function checks the Parse.pIdxPartExpr list to see if this column
** can be replaced with a constant value. If so, it generates code to
** put the constant value in a register (ideally, but not necessarily,
@@ -114263,7 +115791,7 @@ expr_code_doover:
break;
}
testcase( pX->op==TK_COLUMN );
- exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
+ sqlite3ExprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
testcase( regFree1==0 );
memset(&opCompare, 0, sizeof(opCompare));
opCompare.op = TK_EQ;
@@ -114317,15 +115845,14 @@ expr_code_doover:
}
assert( !ExprHasProperty(pExpr, EP_IntValue) );
if( pExpr->affExpr==OE_Ignore ){
- sqlite3VdbeAddOp4(
- v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
+ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, OE_Ignore);
VdbeCoverage(v);
}else{
- sqlite3HaltConstraint(pParse,
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ sqlite3VdbeAddOp3(v, OP_Halt,
pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
- pExpr->affExpr, pExpr->u.zToken, 0, 0);
+ pExpr->affExpr, r1);
}
-
break;
}
#endif
@@ -114614,7 +116141,7 @@ static void exprCodeBetween(
compRight.op = TK_LE;
compRight.pLeft = pDel;
compRight.pRight = pExpr->x.pList->a[1].pExpr;
- exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
+ sqlite3ExprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
if( xJump ){
xJump(pParse, &exprAnd, dest, jumpIfNull);
}else{
@@ -114748,11 +116275,11 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
- sqlite3VdbeTypeofColumn(v, r1);
+ assert( regFree1==0 || regFree1==r1 );
+ if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
- testcase( regFree1==0 );
break;
}
case TK_BETWEEN: {
@@ -114923,11 +116450,11 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
case TK_ISNULL:
case TK_NOTNULL: {
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
- sqlite3VdbeTypeofColumn(v, r1);
+ assert( regFree1==0 || regFree1==r1 );
+ if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest);
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
- testcase( regFree1==0 );
break;
}
case TK_BETWEEN: {
@@ -114993,16 +116520,23 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i
** 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.
+**
+** If the SQLITE_EnableQPSG flag is set on the database connection, then
+** this routine always returns false.
*/
-static int exprCompareVariable(
+static SQLITE_NOINLINE int exprCompareVariable(
const Parse *pParse,
const Expr *pVar,
const Expr *pExpr
){
- int res = 0;
+ int res = 2;
int iVar;
sqlite3_value *pL, *pR = 0;
+ if( pExpr->op==TK_VARIABLE && pVar->iColumn==pExpr->iColumn ){
+ return 0;
+ }
+ if( (pParse->db->flags & SQLITE_EnableQPSG)!=0 ) return 2;
sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
if( pR ){
iVar = pVar->iColumn;
@@ -115012,12 +116546,11 @@ static int exprCompareVariable(
if( sqlite3_value_type(pL)==SQLITE_TEXT ){
sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */
}
- res = 0==sqlite3MemCompare(pL, pR, 0);
+ res = sqlite3MemCompare(pL, pR, 0) ? 2 : 0;
}
sqlite3ValueFree(pR);
sqlite3ValueFree(pL);
}
-
return res;
}
@@ -115043,12 +116576,10 @@ static int exprCompareVariable(
** 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.
+** If pParse is not NULL and SQLITE_EnableQPSG is off 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.
*/
SQLITE_PRIVATE int sqlite3ExprCompare(
const Parse *pParse,
@@ -115060,8 +116591,8 @@ SQLITE_PRIVATE int sqlite3ExprCompare(
if( pA==0 || pB==0 ){
return pB==pA ? 0 : 2;
}
- if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
- return 0;
+ if( pParse && pA->op==TK_VARIABLE ){
+ return exprCompareVariable(pParse, pA, pB);
}
combinedFlags = pA->flags | pB->flags;
if( combinedFlags & EP_IntValue ){
@@ -115257,17 +116788,69 @@ static int exprImpliesNotNull(
}
/*
+** Return true if the boolean value of the expression is always either
+** FALSE or NULL.
+*/
+static int sqlite3ExprIsNotTrue(Expr *pExpr){
+ int v;
+ if( pExpr->op==TK_NULL ) return 1;
+ if( pExpr->op==TK_TRUEFALSE && sqlite3ExprTruthValue(pExpr)==0 ) return 1;
+ v = 1;
+ if( sqlite3ExprIsInteger(pExpr, &v, 0) && v==0 ) return 1;
+ return 0;
+}
+
+/*
+** Return true if the expression is one of the following:
+**
+** CASE WHEN x THEN y END
+** CASE WHEN x THEN y ELSE NULL END
+** CASE WHEN x THEN y ELSE false END
+** iif(x,y)
+** iif(x,y,NULL)
+** iif(x,y,false)
+*/
+static int sqlite3ExprIsIIF(sqlite3 *db, const Expr *pExpr){
+ ExprList *pList;
+ if( pExpr->op==TK_FUNCTION ){
+ const char *z = pExpr->u.zToken;
+ FuncDef *pDef;
+ if( (z[0]!='i' && z[0]!='I') ) return 0;
+ if( pExpr->x.pList==0 ) return 0;
+ pDef = sqlite3FindFunction(db, z, pExpr->x.pList->nExpr, ENC(db), 0);
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ if( pDef==0 ) return 0;
+#else
+ if( NEVER(pDef==0) ) return 0;
+#endif
+ if( (pDef->funcFlags & SQLITE_FUNC_INLINE)==0 ) return 0;
+ if( SQLITE_PTR_TO_INT(pDef->pUserData)!=INLINEFUNC_iif ) return 0;
+ }else if( pExpr->op==TK_CASE ){
+ if( pExpr->pLeft!=0 ) return 0;
+ }else{
+ return 0;
+ }
+ pList = pExpr->x.pList;
+ assert( pList!=0 );
+ if( pList->nExpr==2 ) return 1;
+ if( pList->nExpr==3 && sqlite3ExprIsNotTrue(pList->a[2].pExpr) ) return 1;
+ return 0;
+}
+
+/*
** Return true if we can prove the pE2 will always be true if pE1 is
** true. Return false if we cannot complete the proof or if pE2 might
** be false. Examples:
**
-** pE1: x==5 pE2: x==5 Result: true
-** pE1: x>0 pE2: x==5 Result: false
-** pE1: x=21 pE2: x=21 OR y=43 Result: true
-** pE1: x!=123 pE2: x IS NOT NULL Result: true
-** pE1: x!=?1 pE2: x IS NOT NULL Result: true
-** pE1: x IS NULL pE2: x IS NOT NULL Result: false
-** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
+** pE1: x==5 pE2: x==5 Result: true
+** pE1: x>0 pE2: x==5 Result: false
+** pE1: x=21 pE2: x=21 OR y=43 Result: true
+** pE1: x!=123 pE2: x IS NOT NULL Result: true
+** pE1: x!=?1 pE2: x IS NOT NULL Result: true
+** pE1: x IS NULL pE2: x IS NOT NULL Result: false
+** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
+** pE1: iif(x,y) pE2: x Result: true
+** PE1: iif(x,y,0) pE2: x Result: true
**
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
** Expr.iTable<0 then assume a table number given by iTab.
@@ -115301,6 +116884,9 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(
){
return 1;
}
+ if( sqlite3ExprIsIIF(pParse->db, pE1) ){
+ return sqlite3ExprImpliesExpr(pParse,pE1->x.pList->a[0].pExpr,pE2,iTab);
+ }
return 0;
}
@@ -115768,7 +117354,9 @@ static void findOrCreateAggInfoColumn(
){
struct AggInfo_col *pCol;
int k;
+ int mxTerm = pParse->db->aLimit[SQLITE_LIMIT_COLUMN];
+ assert( mxTerm <= SMXV(i16) );
assert( pAggInfo->iFirstReg==0 );
pCol = pAggInfo->aCol;
for(k=0; k<pAggInfo->nColumn; k++, pCol++){
@@ -115786,6 +117374,10 @@ static void findOrCreateAggInfoColumn(
assert( pParse->db->mallocFailed );
return;
}
+ if( k>mxTerm ){
+ sqlite3ErrorMsg(pParse, "more than %d aggregate terms", mxTerm);
+ k = mxTerm;
+ }
pCol = &pAggInfo->aCol[k];
assert( ExprUseYTab(pExpr) );
pCol->pTab = pExpr->y.pTab;
@@ -115819,6 +117411,7 @@ fix_up_expr:
if( pExpr->op==TK_COLUMN ){
pExpr->op = TK_AGG_COLUMN;
}
+ assert( k <= SMXV(pExpr->iAgg) );
pExpr->iAgg = (i16)k;
}
@@ -115903,13 +117496,19 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
** function that is already in the pAggInfo structure
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
+ int mxTerm = pParse->db->aLimit[SQLITE_LIMIT_COLUMN];
+ assert( mxTerm <= SMXV(i16) );
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
if( NEVER(pItem->pFExpr==pExpr) ) break;
if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
break;
}
}
- if( i>=pAggInfo->nFunc ){
+ if( i>mxTerm ){
+ sqlite3ErrorMsg(pParse, "more than %d aggregate terms", mxTerm);
+ i = mxTerm;
+ assert( i<pAggInfo->nFunc );
+ }else if( i>=pAggInfo->nFunc ){
/* pExpr is original. Make a new entry in pAggInfo->aFunc[]
*/
u8 enc = ENC(pParse->db);
@@ -115963,6 +117562,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
*/
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
ExprSetVVAProperty(pExpr, EP_NoReduce);
+ assert( i <= SMXV(pExpr->iAgg) );
pExpr->iAgg = (i16)i;
pExpr->pAggInfo = pAggInfo;
return WRC_Prune;
@@ -116673,13 +118273,13 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8;
assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 );
- pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc);
+ pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*(u32)nAlloc);
pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName);
if( !pNew->aCol || !pNew->zName ){
assert( db->mallocFailed );
goto exit_begin_add_column;
}
- memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
+ memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*(size_t)pNew->nCol);
for(i=0; i<pNew->nCol; i++){
Column *pCol = &pNew->aCol[i];
pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName);
@@ -116774,10 +118374,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn(
** 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].zCnName, zOld) ) break;
- }
- if( iCol==pTab->nCol ){
+ iCol = sqlite3ColumnIndex(pTab, zOld);
+ if( iCol<0 ){
sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld);
goto exit_rename_column;
}
@@ -117280,6 +118878,7 @@ static int renameParseSql(
int bTemp /* True if SQL is from temp schema */
){
int rc;
+ u64 flags;
sqlite3ParseObjectInit(p, db);
if( zSql==0 ){
@@ -117288,11 +118887,21 @@ static int renameParseSql(
if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){
return SQLITE_CORRUPT_BKPT;
}
- db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);
+ if( bTemp ){
+ db->init.iDb = 1;
+ }else{
+ int iDb = sqlite3FindDbName(db, zDb);
+ assert( iDb>=0 && iDb<=0xff );
+ db->init.iDb = (u8)iDb;
+ }
p->eParseMode = PARSE_MODE_RENAME;
p->db = db;
p->nQueryLoop = 1;
+ flags = db->flags;
+ testcase( (db->flags & SQLITE_Comments)==0 && strstr(zSql," /* ")!=0 );
+ db->flags |= SQLITE_Comments;
rc = sqlite3RunParser(p, zSql);
+ db->flags = flags;
if( db->mallocFailed ) rc = SQLITE_NOMEM;
if( rc==SQLITE_OK
&& NEVER(p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0)
@@ -117355,10 +118964,11 @@ static int renameEditSql(
nQuot = sqlite3Strlen30(zQuot)-1;
}
- assert( nQuot>=nNew );
- zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1);
+ assert( nQuot>=nNew && nSql>=0 && nNew>=0 );
+ zOut = sqlite3DbMallocZero(db, (u64)nSql + pRename->nList*(u64)nQuot + 1);
}else{
- zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3);
+ assert( nSql>0 );
+ zOut = (char*)sqlite3DbMallocZero(db, (2*(u64)nSql + 1) * 3);
if( zOut ){
zBuf1 = &zOut[nSql*2+1];
zBuf2 = &zOut[nSql*4+2];
@@ -117370,16 +118980,17 @@ static int renameEditSql(
** with the new column name, or with single-quoted versions of themselves.
** All that remains is to construct and return the edited SQL string. */
if( zOut ){
- int nOut = nSql;
- memcpy(zOut, zSql, nSql);
+ i64 nOut = nSql;
+ assert( nSql>0 );
+ memcpy(zOut, zSql, (size_t)nSql);
while( pRename->pList ){
int iOff; /* Offset of token to replace in zOut */
- u32 nReplace;
+ i64 nReplace;
const char *zReplace;
RenameToken *pBest = renameColumnTokenNext(pRename);
if( zNew ){
- if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){
+ if( bQuote==0 && sqlite3IsIdChar(*(u8*)pBest->t.z) ){
nReplace = nNew;
zReplace = zNew;
}else{
@@ -117397,14 +119008,15 @@ static int renameEditSql(
memcpy(zBuf1, pBest->t.z, pBest->t.n);
zBuf1[pBest->t.n] = 0;
sqlite3Dequote(zBuf1);
- sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1,
+ assert( nSql < 0x15555554 /* otherwise malloc would have failed */ );
+ sqlite3_snprintf((int)(nSql*2), zBuf2, "%Q%s", zBuf1,
pBest->t.z[pBest->t.n]=='\'' ? " " : ""
);
zReplace = zBuf2;
nReplace = sqlite3Strlen30(zReplace);
}
- iOff = pBest->t.z - zSql;
+ iOff = (int)(pBest->t.z - zSql);
if( pBest->t.n!=nReplace ){
memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n],
nOut - (iOff + pBest->t.n)
@@ -117430,11 +119042,12 @@ static int renameEditSql(
** Set all pEList->a[].fg.eEName fields in the expression-list to val.
*/
static void renameSetENames(ExprList *pEList, int val){
+ assert( val==ENAME_NAME || val==ENAME_TAB || val==ENAME_SPAN );
if( pEList ){
int i;
for(i=0; i<pEList->nExpr; i++){
assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
- pEList->a[i].fg.eEName = val;
+ pEList->a[i].fg.eEName = val&0x3;
}
}
}
@@ -117508,8 +119121,9 @@ static int renameResolveTrigger(Parse *pParse){
int i;
for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
SrcItem *p = &pStep->pFrom->a[i];
- if( p->pSelect ){
- sqlite3SelectPrep(pParse, p->pSelect, 0);
+ if( p->fg.isSubquery ){
+ assert( p->u4.pSubq!=0 );
+ sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0);
}
}
}
@@ -117577,8 +119191,12 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
}
if( pStep->pFrom ){
int i;
- for(i=0; i<pStep->pFrom->nSrc; i++){
- sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
+ SrcList *pFrom = pStep->pFrom;
+ for(i=0; i<pFrom->nSrc; i++){
+ if( pFrom->a[i].fg.isSubquery ){
+ assert( pFrom->a[i].u4.pSubq!=0 );
+ sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect);
+ }
}
}
}
@@ -117686,7 +119304,7 @@ static void renameColumnFunc(
if( sParse.pNewTable ){
if( IsView(sParse.pNewTable) ){
Select *pSelect = sParse.pNewTable->u.view.pSelect;
- pSelect->selFlags &= ~SF_View;
+ pSelect->selFlags &= ~(u32)SF_View;
sParse.rc = SQLITE_OK;
sqlite3SelectPrep(&sParse, pSelect, 0);
rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
@@ -117825,7 +119443,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
}
for(i=0; i<pSrc->nSrc; i++){
SrcItem *pItem = &pSrc->a[i];
- if( pItem->pTab==p->pTab ){
+ if( pItem->pSTab==p->pTab ){
renameTokenFind(pWalker->pParse, p, pItem->zName);
}
}
@@ -117904,7 +119522,7 @@ static void renameTableFunc(
sNC.pParse = &sParse;
assert( pSelect->selFlags & SF_View );
- pSelect->selFlags &= ~SF_View;
+ pSelect->selFlags &= ~(u32)SF_View;
sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC);
if( sParse.nErr ){
rc = sParse.rc;
@@ -118077,7 +119695,7 @@ static void renameQuotefixFunc(
if( sParse.pNewTable ){
if( IsView(sParse.pNewTable) ){
Select *pSelect = sParse.pNewTable->u.view.pSelect;
- pSelect->selFlags &= ~SF_View;
+ pSelect->selFlags &= ~(u32)SF_View;
sParse.rc = SQLITE_OK;
sqlite3SelectPrep(&sParse, pSelect, 0);
rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
@@ -118176,10 +119794,10 @@ static void renameTableTest(
if( zDb && zInput ){
int rc;
Parse sParse;
- int flags = db->flags;
+ u64 flags = db->flags;
if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL);
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
- db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL));
+ db->flags = flags;
if( rc==SQLITE_OK ){
if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){
NameContext sNC;
@@ -118671,7 +120289,8 @@ static void openStatTable(
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
);
- aRoot[i] = (u32)pParse->regRoot;
+ assert( pParse->isCreate || pParse->nErr );
+ aRoot[i] = (u32)pParse->u1.cr.regRoot;
aCreateTbl[i] = OPFLAG_P2ISREG;
}
}else{
@@ -118862,7 +120481,7 @@ static void statInit(
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 */
+ i64 n; /* Bytes of space to allocate */
sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */
#ifdef SQLITE_ENABLE_STAT4
/* Maximum number of samples. 0 if STAT4 data is not collected */
@@ -118898,7 +120517,7 @@ static void statInit(
p->db = db;
p->nEst = sqlite3_value_int64(argv[2]);
p->nRow = 0;
- p->nLimit = sqlite3_value_int64(argv[3]);
+ p->nLimit = sqlite3_value_int(argv[3]);
p->nCol = nCol;
p->nKeyCol = nKeyCol;
p->nSkipAhead = 0;
@@ -120031,16 +121650,6 @@ static void decodeIntArray(
while( z[0]!=0 && z[0]!=' ' ) z++;
while( z[0]==' ' ) z++;
}
-
- /* Set the bLowQual flag if the peak number of rows obtained
- ** from a full equality match is so large that a full table scan
- ** seems likely to be faster than using the index.
- */
- if( aLog[0] > 66 /* Index has more than 100 rows */
- && aLog[0] <= aLog[nOut-1] /* And only a single value seen */
- ){
- pIndex->bLowQual = 1;
- }
}
}
@@ -120253,12 +121862,13 @@ static int loadStatTbl(
while( sqlite3_step(pStmt)==SQLITE_ROW ){
int nIdxCol = 1; /* Number of columns in stat4 records */
- char *zIndex; /* Index name */
- Index *pIdx; /* Pointer to the index object */
- int nSample; /* Number of samples */
- int nByte; /* Bytes of space required */
- int i; /* Bytes of space required */
- tRowcnt *pSpace;
+ char *zIndex; /* Index name */
+ Index *pIdx; /* Pointer to the index object */
+ int nSample; /* Number of samples */
+ i64 nByte; /* Bytes of space required */
+ i64 i; /* Bytes of space required */
+ tRowcnt *pSpace; /* Available allocated memory space */
+ u8 *pPtr; /* Available memory as a u8 for easier manipulation */
zIndex = (char *)sqlite3_column_text(pStmt, 0);
if( zIndex==0 ) continue;
@@ -120278,7 +121888,7 @@ static int loadStatTbl(
}
pIdx->nSampleCol = nIdxCol;
pIdx->mxSample = nSample;
- nByte = sizeof(IndexSample) * nSample;
+ nByte = ROUND8(sizeof(IndexSample) * nSample);
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
@@ -120287,7 +121897,10 @@ static int loadStatTbl(
sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
}
- pSpace = (tRowcnt*)&pIdx->aSample[nSample];
+ pPtr = (u8*)pIdx->aSample;
+ pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0]));
+ pSpace = (tRowcnt*)pPtr;
+ assert( EIGHT_BYTE_ALIGNMENT( pSpace ) );
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
pIdx->pTable->tabFlags |= TF_HasStat4;
for(i=0; i<nSample; i++){
@@ -120632,7 +122245,7 @@ static void attachFunc(
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) );
+ aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(1+(i64)db->nDb));
if( aNew==0 ) return;
}
db->aDb = aNew;
@@ -120651,6 +122264,12 @@ static void attachFunc(
sqlite3_free(zErr);
return;
}
+ if( (db->flags & SQLITE_AttachWrite)==0 ){
+ flags &= ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE);
+ flags |= SQLITE_OPEN_READONLY;
+ }else if( (db->flags & SQLITE_AttachCreate)==0 ){
+ flags &= ~SQLITE_OPEN_CREATE;
+ }
assert( pVfs );
flags |= SQLITE_OPEN_MAIN_DB;
rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
@@ -120697,21 +122316,19 @@ static void attachFunc(
sqlite3BtreeEnterAll(db);
db->init.iDb = 0;
db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( db->setlkFlags & SQLITE_SETLK_BLOCK_ON_CONNECT ){
+ int val = 1;
+ sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pNew->pBt));
+ sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, &val);
+ }
+#endif
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 && !REOPEN_AS_MEMDB(db) ){
- u8 newAuth = 0;
- rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
- if( newAuth<db->auth.authLevel ){
- rc = SQLITE_AUTH_USER;
- }
- }
-#endif
if( rc ){
if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){
int iDb = db->nDb - 1;
@@ -120955,20 +122572,21 @@ static int fixSelectCb(Walker *p, Select *pSelect){
if( NEVER(pList==0) ) return WRC_Continue;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
- if( pFix->bTemp==0 ){
- if( pItem->zDatabase ){
- if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
+ if( pFix->bTemp==0 && pItem->fg.isSubquery==0 ){
+ if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
+ if( iDb!=sqlite3FindDbName(db, pItem->u4.zDatabase) ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
- pFix->zType, pFix->pName, pItem->zDatabase);
+ pFix->zType, pFix->pName, pItem->u4.zDatabase);
return WRC_Abort;
}
- sqlite3DbFree(db, pItem->zDatabase);
- pItem->zDatabase = 0;
+ sqlite3DbFree(db, pItem->u4.zDatabase);
pItem->fg.notCte = 1;
+ pItem->fg.hadSchema = 1;
}
- pItem->pSchema = pFix->pSchema;
+ pItem->u4.pSchema = pFix->pSchema;
pItem->fg.fromDDL = 1;
+ pItem->fg.fixedSchema = 1;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( pList->a[i].fg.isUsing==0
@@ -121208,11 +122826,7 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
int rc; /* Auth callback return code */
if( db->init.busy ) return SQLITE_OK;
- rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
-#ifdef SQLITE_USER_AUTHENTICATION
- ,db->auth.zAuthUser
-#endif
- );
+ rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext);
if( rc==SQLITE_DENY ){
char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
@@ -121261,7 +122875,7 @@ SQLITE_PRIVATE void sqlite3AuthRead(
assert( pTabList );
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
- pTab = pTabList->a[iSrc].pTab;
+ pTab = pTabList->a[iSrc].pSTab;
break;
}
}
@@ -121319,11 +122933,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
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
-#endif
- );
+ rc = db->xAuth(db->pAuthArg,code,zArg1,zArg2,zArg3,pParse->zAuthContext);
if( rc==SQLITE_DENY ){
sqlite3ErrorMsg(pParse, "not authorized");
pParse->rc = SQLITE_AUTH;
@@ -121435,6 +123045,7 @@ static SQLITE_NOINLINE void lockTable(
}
}
+ assert( pToplevel->nTableLock < 0x7fff0000 );
nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1);
pToplevel->aTableLock =
sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes);
@@ -121535,10 +123146,12 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
if( v ){
if( pParse->bReturning ){
- Returning *pReturning = pParse->u1.pReturning;
+ Returning *pReturning;
int addrRewind;
int reg;
+ assert( !pParse->isCreate );
+ pReturning = pParse->u1.d.pReturning;
if( pReturning->nRetCol ){
sqlite3VdbeAddOp0(v, OP_FkCheck);
addrRewind =
@@ -121556,17 +123169,6 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
}
sqlite3VdbeAddOp0(v, OP_Halt);
-#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE)
- if( pParse->nTableLock>0 && db->init.busy==0 ){
- sqlite3UserAuthInit(db);
- if( db->auth.authLevel<UAUTH_User ){
- sqlite3ErrorMsg(pParse, "user not authenticated");
- pParse->rc = SQLITE_AUTH_USER;
- return;
- }
- }
-#endif
-
/* The cookie mask contains one bit for each database file open.
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
** set for each database that is used. Generate code to start a
@@ -121625,7 +123227,9 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
}
if( pParse->bReturning ){
- Returning *pRet = pParse->u1.pReturning;
+ Returning *pRet;
+ assert( !pParse->isCreate );
+ pRet = pParse->u1.d.pReturning;
if( pRet->nRetCol ){
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
}
@@ -121695,16 +123299,6 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
pParse->nested--;
}
-#if SQLITE_USER_AUTHENTICATION
-/*
-** Return TRUE if zTable is the name of the system table that stores the
-** list of users and their access credentials.
-*/
-SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){
- return sqlite3_stricmp(zTable, "sqlite_user")==0;
-}
-#endif
-
/*
** Locate the in-memory structure that describes a particular database
** table given the name of that table and (optionally) the name of the
@@ -121723,13 +123317,6 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha
/* All mutexes are required for schema access. Make sure we hold them. */
assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
-#if SQLITE_USER_AUTHENTICATION
- /* Only the admin user is allowed to know that the sqlite_user table
- ** exists */
- if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
- return 0;
- }
-#endif
if( zDatabase ){
for(i=0; i<db->nDb; i++){
if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
@@ -121864,12 +123451,12 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem(
SrcItem *p
){
const char *zDb;
- assert( p->pSchema==0 || p->zDatabase==0 );
- if( p->pSchema ){
- int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
+ if( p->fg.fixedSchema ){
+ int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema);
zDb = pParse->db->aDb[iDb].zDbSName;
}else{
- zDb = p->zDatabase;
+ assert( !p->fg.isSubquery );
+ zDb = p->u4.zDatabase;
}
return sqlite3LocateTable(pParse, flags, p->zName, zDb);
}
@@ -122457,10 +124044,16 @@ SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){
** 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 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){
+SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index *pIdx, int iCol){
int i;
+ i16 iCol16;
+ assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN );
+ assert( pIdx->nColumn<=SQLITE_MAX_COLUMN+1 );
+ iCol16 = iCol;
for(i=0; i<pIdx->nColumn; i++){
- if( iCol==pIdx->aiColumn[i] ) return i;
+ if( iCol16==pIdx->aiColumn[i] ){
+ return i;
+ }
}
return -1;
}
@@ -122714,8 +124307,9 @@ SQLITE_PRIVATE void sqlite3StartTable(
/* If the file format and encoding in the database have not been set,
** set them now.
*/
- reg1 = pParse->regRowid = ++pParse->nMem;
- reg2 = pParse->regRoot = ++pParse->nMem;
+ assert( pParse->isCreate );
+ reg1 = pParse->u1.cr.regRowid = ++pParse->nMem;
+ reg2 = pParse->u1.cr.regRoot = ++pParse->nMem;
reg3 = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT);
sqlite3VdbeUsesBtree(v, iDb);
@@ -122730,8 +124324,8 @@ SQLITE_PRIVATE void sqlite3StartTable(
** The record created does not contain anything yet. It will be replaced
** by the real entry in code generated at sqlite3EndTable().
**
- ** The rowid for the new entry is left in register pParse->regRowid.
- ** The root page number of the new table is left in reg pParse->regRoot.
+ ** The rowid for the new entry is left in register pParse->u1.cr.regRowid.
+ ** The root page of the new table is left in reg pParse->u1.cr.regRoot.
** The rowid and root page number values are needed by the code that
** sqlite3EndTable will generate.
*/
@@ -122742,7 +124336,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
#endif
{
assert( !pParse->bReturning );
- pParse->u1.addrCrTab =
+ pParse->u1.cr.addrCrTab =
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
}
sqlite3OpenSchemaTable(pParse, iDb);
@@ -122820,7 +124414,8 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
sqlite3ExprListDelete(db, pList);
return;
}
- pParse->u1.pReturning = pRet;
+ assert( !pParse->isCreate );
+ pParse->u1.d.pReturning = pRet;
pRet->pParse = pParse;
pRet->pReturnEL = pList;
sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet);
@@ -122862,7 +124457,6 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
char *zType;
Column *pCol;
sqlite3 *db = pParse->db;
- u8 hName;
Column *aNew;
u8 eType = COLTYPE_CUSTOM;
u8 szEst = 1;
@@ -122916,13 +124510,10 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
memcpy(z, sName.z, sName.n);
z[sName.n] = 0;
sqlite3Dequote(z);
- hName = sqlite3StrIHash(z);
- for(i=0; i<p->nCol; i++){
- if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){
- sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
- sqlite3DbFree(db, z);
- return;
- }
+ if( p->nCol && sqlite3ColumnIndex(p, z)>=0 ){
+ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
+ sqlite3DbFree(db, z);
+ return;
}
aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0]));
if( aNew==0 ){
@@ -122933,7 +124524,7 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
pCol = &p->aCol[p->nCol];
memset(pCol, 0, sizeof(p->aCol[0]));
pCol->zCnName = z;
- pCol->hName = hName;
+ pCol->hName = sqlite3StrIHash(z);
sqlite3ColumnPropertiesFromName(p, pCol);
if( sType.n==0 ){
@@ -122957,9 +124548,14 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
pCol->affinity = sqlite3AffinityType(zType, pCol);
pCol->colFlags |= COLFLAG_HASTYPE;
}
+ if( p->nCol<=0xff ){
+ u8 h = pCol->hName % sizeof(p->aHx);
+ p->aHx[h] = p->nCol;
+ }
p->nCol++;
p->nNVCol++;
- pParse->constraintName.n = 0;
+ assert( pParse->isCreate );
+ pParse->u1.cr.constraintName.n = 0;
}
/*
@@ -123223,15 +124819,11 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
assert( pCExpr!=0 );
sqlite3StringToId(pCExpr);
if( pCExpr->op==TK_ID ){
- const char *zCName;
assert( !ExprHasProperty(pCExpr, EP_IntValue) );
- zCName = pCExpr->u.zToken;
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){
- pCol = &pTab->aCol[iCol];
- makeColumnPartOfPrimaryKey(pParse, pCol);
- break;
- }
+ iCol = sqlite3ColumnIndex(pTab, pCExpr->u.zToken);
+ if( iCol>=0 ){
+ pCol = &pTab->aCol[iCol];
+ makeColumnPartOfPrimaryKey(pParse, pCol);
}
}
}
@@ -123283,8 +124875,10 @@ SQLITE_PRIVATE void sqlite3AddCheckConstraint(
&& !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt)
){
pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
- if( pParse->constraintName.n ){
- sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
+ assert( pParse->isCreate );
+ if( pParse->u1.cr.constraintName.n ){
+ sqlite3ExprListSetName(pParse, pTab->pCheck,
+ &pParse->u1.cr.constraintName, 1);
}else{
Token t;
for(zStart++; sqlite3Isspace(zStart[0]); zStart++){}
@@ -123479,7 +125073,8 @@ static void identPut(char *z, int *pIdx, char *zSignedIdent){
** from sqliteMalloc() and must be freed by the calling function.
*/
static char *createTableStmt(sqlite3 *db, Table *p){
- int i, k, n;
+ int i, k, len;
+ i64 n;
char *zStmt;
char *zSep, *zSep2, *zEnd;
Column *pCol;
@@ -123503,8 +125098,9 @@ static char *createTableStmt(sqlite3 *db, Table *p){
sqlite3OomFault(db);
return 0;
}
- sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
- k = sqlite3Strlen30(zStmt);
+ assert( n>14 && n<=0x7fffffff );
+ memcpy(zStmt, "CREATE TABLE ", 13);
+ k = 13;
identPut(zStmt, &k, p->zName);
zStmt[k++] = '(';
for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
@@ -123516,13 +125112,15 @@ static char *createTableStmt(sqlite3 *db, Table *p){
/* SQLITE_AFF_REAL */ " REAL",
/* SQLITE_AFF_FLEXNUM */ " NUM",
};
- int len;
const char *zType;
- sqlite3_snprintf(n-k, &zStmt[k], zSep);
- k += sqlite3Strlen30(&zStmt[k]);
+ len = sqlite3Strlen30(zSep);
+ assert( k+len<n );
+ memcpy(&zStmt[k], zSep, len);
+ k += len;
zSep = zSep2;
identPut(zStmt, &k, pCol->zCnName);
+ assert( k<n );
assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 );
assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) );
testcase( pCol->affinity==SQLITE_AFF_BLOB );
@@ -123537,11 +125135,14 @@ static char *createTableStmt(sqlite3 *db, Table *p){
assert( pCol->affinity==SQLITE_AFF_BLOB
|| pCol->affinity==SQLITE_AFF_FLEXNUM
|| pCol->affinity==sqlite3AffinityType(zType, 0) );
+ assert( k+len<n );
memcpy(&zStmt[k], zType, len);
k += len;
assert( k<=n );
}
- sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
+ len = sqlite3Strlen30(zEnd);
+ assert( k+len<n );
+ memcpy(&zStmt[k], zEnd, len+1);
return zStmt;
}
@@ -123549,12 +125150,17 @@ static char *createTableStmt(sqlite3 *db, Table *p){
** Resize an Index object to hold N columns total. Return SQLITE_OK
** on success and SQLITE_NOMEM on an OOM error.
*/
-static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
+static int resizeIndexObject(Parse *pParse, Index *pIdx, int N){
char *zExtra;
- int nByte;
+ u64 nByte;
+ sqlite3 *db;
if( pIdx->nColumn>=N ) return SQLITE_OK;
+ db = pParse->db;
+ assert( N>0 );
+ assert( N <= SQLITE_MAX_COLUMN*2 /* tag-20250221-1 */ );
+ testcase( N==2*pParse->db->aLimit[SQLITE_LIMIT_COLUMN] );
assert( pIdx->isResized==0 );
- nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N;
+ nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*(u64)N;
zExtra = sqlite3DbMallocZero(db, nByte);
if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
@@ -123568,7 +125174,7 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
zExtra += sizeof(i16)*N;
memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn);
pIdx->aSortOrder = (u8*)zExtra;
- pIdx->nColumn = N;
+ pIdx->nColumn = (u16)N; /* See tag-20250221-1 above for proof of safety */
pIdx->isResized = 1;
return SQLITE_OK;
}
@@ -123734,9 +125340,9 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
** into BTREE_BLOBKEY.
*/
assert( !pParse->bReturning );
- if( pParse->u1.addrCrTab ){
+ if( pParse->u1.cr.addrCrTab ){
assert( v );
- sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY);
+ sqlite3VdbeChangeP3(v, pParse->u1.cr.addrCrTab, BTREE_BLOBKEY);
}
/* Locate the PRIMARY KEY index. Or, if this table was originally
@@ -123822,14 +125428,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
pIdx->nColumn = pIdx->nKeyCol;
continue;
}
- if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return;
+ if( resizeIndexObject(pParse, pIdx, pIdx->nKeyCol+n) ) return;
for(i=0, j=pIdx->nKeyCol; i<nPk; 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 */
+ /* See ticket https://sqlite.org/src/info/bba7b69f9849b5bf */
pIdx->bAscKeyBug = 1;
}
j++;
@@ -123846,7 +125452,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
if( !hasColumn(pPk->aiColumn, nPk, i)
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++;
}
- if( resizeIndexObject(db, pPk, nPk+nExtra) ) return;
+ if( resizeIndexObject(pParse, 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
@@ -124176,7 +125782,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
/* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
** statement to populate the new table. The root-page number for the
- ** new table is in register pParse->regRoot.
+ ** new table is in register pParse->u1.cr.regRoot.
**
** Once the SELECT has been coded by sqlite3Select(), it is in a
** suitable state to query for the column names and types to be used
@@ -124207,7 +125813,8 @@ SQLITE_PRIVATE void sqlite3EndTable(
regRec = ++pParse->nMem;
regRowid = ++pParse->nMem;
sqlite3MayAbort(pParse);
- sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb);
+ assert( pParse->isCreate );
+ sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->u1.cr.regRoot, iDb);
sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
@@ -124252,6 +125859,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
** schema table. We just need to update that slot with all
** the information we've collected.
*/
+ assert( pParse->isCreate );
sqlite3NestedParse(pParse,
"UPDATE %Q." LEGACY_SCHEMA_TABLE
" SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q"
@@ -124260,9 +125868,9 @@ SQLITE_PRIVATE void sqlite3EndTable(
zType,
p->zName,
p->zName,
- pParse->regRoot,
+ pParse->u1.cr.regRoot,
zStmt,
- pParse->regRowid
+ pParse->u1.cr.regRowid
);
sqlite3DbFree(db, zStmt);
sqlite3ChangeCookie(pParse, iDb);
@@ -124854,6 +126462,8 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
}
assert( pParse->nErr==0 );
assert( pName->nSrc==1 );
+ assert( pName->a[0].fg.fixedSchema==0 );
+ assert( pName->a[0].fg.isSubquery==0 );
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
if( noErr ) db->suppressErr++;
assert( isView==0 || isView==LOCATE_VIEW );
@@ -124862,7 +126472,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
if( pTab==0 ){
if( noErr ){
- sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
+ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
sqlite3ForceNotReadOnly(pParse);
}
goto exit_drop_table;
@@ -125000,7 +126610,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
}else{
nCol = pFromCol->nExpr;
}
- nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1;
+ nByte = SZ_FKEY(nCol) + pTo->n + 1;
if( pToCol ){
for(i=0; i<pToCol->nExpr; i++){
nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1;
@@ -125202,7 +126812,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
** 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
+ ** See ticket: https://sqlite.org/src/info/bba7b69f9849b5bf
*/
sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx);
}
@@ -125226,13 +126836,14 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
*/
SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
sqlite3 *db, /* Database connection */
- i16 nCol, /* Total number of columns in the index */
+ int nCol, /* Total number of columns in the index */
int nExtra, /* Number of bytes of extra space to alloc */
char **ppExtra /* Pointer to the "extra" space */
){
Index *p; /* Allocated index object */
- int nByte; /* Bytes of space for Index object + arrays */
+ i64 nByte; /* Bytes of space for Index object + arrays */
+ assert( nCol <= 2*db->aLimit[SQLITE_LIMIT_COLUMN] );
nByte = ROUND8(sizeof(Index)) + /* Index structure */
ROUND8(sizeof(char*)*nCol) + /* Index.azColl */
ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */
@@ -125245,8 +126856,9 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
p->aSortOrder = (u8*)pExtra;
- p->nColumn = nCol;
- p->nKeyCol = nCol - 1;
+ assert( nCol>0 );
+ p->nColumn = (u16)nCol;
+ p->nKeyCol = (u16)(nCol - 1);
*ppExtra = ((char*)p) + nByte;
}
return p;
@@ -125386,9 +126998,6 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
&& db->init.busy==0
&& pTblName!=0
-#if SQLITE_USER_AUTHENTICATION
- && sqlite3UserAuthTable(pTab->zName)==0
-#endif
){
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
goto exit_create_index;
@@ -125587,6 +127196,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
assert( j<=0x7fff );
if( j<0 ){
j = pTab->iPKey;
+ pIndex->bIdxRowid = 1;
}else{
if( pTab->aCol[j].notNull==0 ){
pIndex->uniqNotNull = 0;
@@ -125953,15 +127563,17 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
}
assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
assert( pName->nSrc==1 );
+ assert( pName->a[0].fg.fixedSchema==0 );
+ assert( pName->a[0].fg.isSubquery==0 );
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto exit_drop_index;
}
- pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
+ pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase);
if( pIndex==0 ){
if( !ifExists ){
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
}else{
- sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
+ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
sqlite3ForceNotReadOnly(pParse);
}
pParse->checkSchema = 1;
@@ -126058,12 +127670,11 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *
sqlite3 *db = pParse->db;
int i;
if( pList==0 ){
- pList = sqlite3DbMallocZero(db, sizeof(IdList) );
+ pList = sqlite3DbMallocZero(db, SZ_IDLIST(1));
if( pList==0 ) return 0;
}else{
IdList *pNew;
- pNew = sqlite3DbRealloc(db, pList,
- sizeof(IdList) + pList->nId*sizeof(pList->a));
+ pNew = sqlite3DbRealloc(db, pList, SZ_IDLIST(pList->nId+1));
if( pNew==0 ){
sqlite3IdListDelete(db, pList);
return 0;
@@ -126085,7 +127696,6 @@ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
int i;
assert( db!=0 );
if( pList==0 ) return;
- assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
for(i=0; i<pList->nId; i++){
sqlite3DbFree(db, pList->a[i].zName);
}
@@ -126163,8 +127773,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
return 0;
}
if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST;
- pNew = sqlite3DbRealloc(db, pSrc,
- sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
+ pNew = sqlite3DbRealloc(db, pSrc, SZ_SRCLIST(nAlloc));
if( pNew==0 ){
assert( db->mallocFailed );
return 0;
@@ -126239,7 +127848,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
assert( pParse->db!=0 );
db = pParse->db;
if( pList==0 ){
- pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) );
+ pList = sqlite3DbMallocRawNN(pParse->db, SZ_SRCLIST(1));
if( pList==0 ) return 0;
pList->nAlloc = 1;
pList->nSrc = 1;
@@ -126258,12 +127867,14 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
if( pDatabase && pDatabase->z==0 ){
pDatabase = 0;
}
+ assert( pItem->fg.fixedSchema==0 );
+ assert( pItem->fg.isSubquery==0 );
if( pDatabase ){
pItem->zName = sqlite3NameFromToken(db, pDatabase);
- pItem->zDatabase = sqlite3NameFromToken(db, pTable);
+ pItem->u4.zDatabase = sqlite3NameFromToken(db, pTable);
}else{
pItem->zName = sqlite3NameFromToken(db, pTable);
- pItem->zDatabase = 0;
+ pItem->u4.zDatabase = 0;
}
return pList;
}
@@ -126279,14 +127890,41 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->iCursor>=0 ) continue;
pItem->iCursor = pParse->nTab++;
- if( pItem->pSelect ){
- sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
+ if( pItem->fg.isSubquery ){
+ assert( pItem->u4.pSubq!=0 );
+ assert( pItem->u4.pSubq->pSelect!=0 );
+ assert( pItem->u4.pSubq->pSelect->pSrc!=0 );
+ sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc);
}
}
}
}
/*
+** Delete a Subquery object and its substructure.
+*/
+SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3 *db, Subquery *pSubq){
+ assert( pSubq!=0 && pSubq->pSelect!=0 );
+ sqlite3SelectDelete(db, pSubq->pSelect);
+ sqlite3DbFree(db, pSubq);
+}
+
+/*
+** Remove a Subquery from a SrcItem. Return the associated Select object.
+** The returned Select becomes the responsibility of the caller.
+*/
+SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3 *db, SrcItem *pItem){
+ Select *pSel;
+ assert( pItem!=0 );
+ assert( pItem->fg.isSubquery );
+ pSel = pItem->u4.pSubq->pSelect;
+ sqlite3DbFree(db, pItem->u4.pSubq);
+ pItem->u4.pSubq = 0;
+ pItem->fg.isSubquery = 0;
+ return pSel;
+}
+
+/*
** Delete an entire SrcList including all its substructure.
*/
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
@@ -126295,13 +127933,24 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
assert( db!=0 );
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
- if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
+
+ /* Check invariants on SrcItem */
+ assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc );
+ assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy );
+ assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery );
+ assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 &&
+ pItem->u4.pSubq->pSelect!=0) );
+
if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
+ if( pItem->fg.isSubquery ){
+ sqlite3SubqueryDelete(db, pItem->u4.pSubq);
+ }else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
+ sqlite3DbNNFreeNN(db, pItem->u4.zDatabase);
+ }
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
- sqlite3DeleteTable(db, pItem->pTab);
- if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
+ sqlite3DeleteTable(db, pItem->pSTab);
if( pItem->fg.isUsing ){
sqlite3IdListDelete(db, pItem->u3.pUsing);
}else if( pItem->u3.pOn ){
@@ -126312,6 +127961,54 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
}
/*
+** Attach a Subquery object to pItem->uv.pSubq. Set the
+** pSelect value but leave all the other values initialized
+** to zero.
+**
+** A copy of the Select object is made if dupSelect is true, and the
+** SrcItem takes responsibility for deleting the copy. If dupSelect is
+** false, ownership of the Select passes to the SrcItem. Either way,
+** the SrcItem will take responsibility for deleting the Select.
+**
+** When dupSelect is zero, that means the Select might get deleted right
+** away if there is an OOM error. Beware.
+**
+** Return non-zero on success. Return zero on an OOM error.
+*/
+SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery(
+ Parse *pParse, /* Parsing context */
+ SrcItem *pItem, /* Item to which the subquery is to be attached */
+ Select *pSelect, /* The subquery SELECT. Must be non-NULL */
+ int dupSelect /* If true, attach a copy of pSelect, not pSelect itself.*/
+){
+ Subquery *p;
+ assert( pSelect!=0 );
+ assert( pItem->fg.isSubquery==0 );
+ if( pItem->fg.fixedSchema ){
+ pItem->u4.pSchema = 0;
+ pItem->fg.fixedSchema = 0;
+ }else if( pItem->u4.zDatabase!=0 ){
+ sqlite3DbFree(pParse->db, pItem->u4.zDatabase);
+ pItem->u4.zDatabase = 0;
+ }
+ if( dupSelect ){
+ pSelect = sqlite3SelectDup(pParse->db, pSelect, 0);
+ if( pSelect==0 ) return 0;
+ }
+ p = pItem->u4.pSubq = sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery));
+ if( p==0 ){
+ sqlite3SelectDelete(pParse->db, pSelect);
+ return 0;
+ }
+ pItem->fg.isSubquery = 1;
+ p->pSelect = pSelect;
+ assert( offsetof(Subquery, pSelect)==0 );
+ memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect));
+ return 1;
+}
+
+
+/*
** This routine is called by the parser to add a new term to the
** end of a growing FROM clause. The "p" parameter is the part of
** the FROM clause that has already been constructed. "p" is NULL
@@ -126360,10 +128057,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
if( pAlias->n ){
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
}
+ assert( pSubquery==0 || pDatabase==0 );
if( pSubquery ){
- pItem->pSelect = pSubquery;
- if( pSubquery->selFlags & SF_NestedFrom ){
- pItem->fg.isNestedFrom = 1;
+ if( sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){
+ if( pSubquery->selFlags & SF_NestedFrom ){
+ pItem->fg.isNestedFrom = 1;
+ }
}
}
assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
@@ -127035,10 +128734,9 @@ SQLITE_PRIVATE With *sqlite3WithAdd(
}
if( pWith ){
- sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte);
- pNew = sqlite3DbRealloc(db, pWith, nByte);
+ pNew = sqlite3DbRealloc(db, pWith, SZ_WITH(pWith->nCte+1));
}else{
- pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
+ pNew = sqlite3DbMallocZero(db, SZ_WITH(1));
}
assert( (pNew!=0 && zName!=0) || db->mallocFailed );
@@ -127376,12 +129074,18 @@ static int matchQuality(
u8 enc /* Desired text encoding */
){
int match;
- assert( p->nArg>=-1 );
+ assert( p->nArg>=(-4) && p->nArg!=(-2) );
+ assert( nArg>=(-2) );
/* Wrong number of arguments means "no match" */
if( p->nArg!=nArg ){
- if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
+ if( nArg==(-2) ) return p->xSFunc==0 ? 0 : FUNC_PERFECT_MATCH;
if( p->nArg>=0 ) return 0;
+ /* Special p->nArg values available to built-in functions only:
+ ** -3 1 or more arguments required
+ ** -4 2 or more arguments required
+ */
+ if( p->nArg<(-2) && nArg<(-2-p->nArg) ) return 0;
}
/* Give a better score to a function with a specific number of arguments
@@ -127641,8 +129345,8 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
**
** The following fields are initialized appropriate in pSrc:
**
-** pSrc->a[0].pTab Pointer to the Table object
-** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one
+** pSrc->a[0].spTab Pointer to the Table object
+** pSrc->a[0].u2.pIBIndex Pointer to the INDEXED BY index, if there is one
**
*/
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
@@ -127650,8 +129354,8 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
Table *pTab;
assert( pItem && pSrc->nSrc>=1 );
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
- if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab);
- pItem->pTab = pTab;
+ if( pItem->pSTab ) sqlite3DeleteTable(pParse->db, pItem->pSTab);
+ pItem->pSTab = pTab;
pItem->fg.notCte = 1;
if( pTab ){
pTab->nTabRef++;
@@ -127692,6 +129396,7 @@ SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char *
** is for a top-level SQL statement.
*/
static int vtabIsReadOnly(Parse *pParse, Table *pTab){
+ assert( IsVirtual(pTab) );
if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
return 1;
}
@@ -127773,7 +129478,8 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
if( pFrom ){
assert( pFrom->nSrc==1 );
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
- pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
+ assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 );
+ pFrom->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
assert( pFrom->a[0].fg.isUsing==0 );
assert( pFrom->a[0].u3.pOn==0 );
}
@@ -127835,7 +129541,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
** );
*/
- pTab = pSrc->a[0].pTab;
+ pTab = pSrc->a[0].pSTab;
if( HasRowid(pTab) ){
pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
pEList = sqlite3ExprListAppend(
@@ -127868,9 +129574,9 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
- pSrc->a[0].pTab = 0;
+ pSrc->a[0].pSTab = 0;
pSelectSrc = sqlite3SrcListDup(db, pSrc, 0);
- pSrc->a[0].pTab = pTab;
+ pSrc->a[0].pSTab = pTab;
if( pSrc->a[0].fg.isIndexedBy ){
assert( pSrc->a[0].fg.isCte==0 );
pSrc->a[0].u2.pIBIndex = 0;
@@ -129002,16 +130708,10 @@ static void substrFunc(
int len;
int p0type;
i64 p1, p2;
- int negP2 = 0;
assert( argc==3 || argc==2 );
- if( sqlite3_value_type(argv[1])==SQLITE_NULL
- || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL)
- ){
- return;
- }
p0type = sqlite3_value_type(argv[0]);
- p1 = sqlite3_value_int(argv[1]);
+ p1 = sqlite3_value_int64(argv[1]);
if( p0type==SQLITE_BLOB ){
len = sqlite3_value_bytes(argv[0]);
z = sqlite3_value_blob(argv[0]);
@@ -129027,28 +130727,31 @@ static void substrFunc(
}
}
}
-#ifdef SQLITE_SUBSTR_COMPATIBILITY
- /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
- ** as substr(X,1,N) - it returns the first N characters of X. This
- ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
- ** from 2009-02-02 for compatibility of applications that exploited the
- ** old buggy behavior. */
- if( p1==0 ) p1 = 1; /* <rdar://problem/6778339> */
-#endif
if( argc==3 ){
- p2 = sqlite3_value_int(argv[2]);
- if( p2<0 ){
- p2 = -p2;
- negP2 = 1;
- }
+ p2 = sqlite3_value_int64(argv[2]);
+ if( p2==0 && sqlite3_value_type(argv[2])==SQLITE_NULL ) return;
}else{
p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH];
}
+ if( p1==0 ){
+#ifdef SQLITE_SUBSTR_COMPATIBILITY
+ /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
+ ** as substr(X,1,N) - it returns the first N characters of X. This
+ ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
+ ** from 2009-02-02 for compatibility of applications that exploited the
+ ** old buggy behavior. */
+ p1 = 1; /* <rdar://problem/6778339> */
+#endif
+ if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return;
+ }
if( p1<0 ){
p1 += len;
if( p1<0 ){
- p2 += p1;
- if( p2<0 ) p2 = 0;
+ if( p2<0 ){
+ p2 = 0;
+ }else{
+ p2 += p1;
+ }
p1 = 0;
}
}else if( p1>0 ){
@@ -129056,12 +130759,13 @@ static void substrFunc(
}else if( p2>0 ){
p2--;
}
- if( negP2 ){
- p1 -= p2;
- if( p1<0 ){
- p2 += p1;
- p1 = 0;
+ if( p2<0 ){
+ if( p2<-p1 ){
+ p2 = p1;
+ }else{
+ p2 = -p2;
}
+ p1 -= p2;
}
assert( p1>=0 && p2>=0 );
if( p0type!=SQLITE_BLOB ){
@@ -129075,9 +130779,11 @@ static void substrFunc(
sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT,
SQLITE_UTF8);
}else{
- if( p1+p2>len ){
+ if( p1>=len ){
+ p1 = p2 = 0;
+ }else if( p2>len-p1 ){
p2 = len-p1;
- if( p2<0 ) p2 = 0;
+ assert( p2>0 );
}
sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT);
}
@@ -129088,13 +130794,13 @@ static void substrFunc(
*/
#ifndef SQLITE_OMIT_FLOATING_POINT
static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- int n = 0;
+ i64 n = 0;
double r;
char *zBuf;
assert( argc==1 || argc==2 );
if( argc==2 ){
if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return;
- n = sqlite3_value_int(argv[1]);
+ n = sqlite3_value_int64(argv[1]);
if( n>30 ) n = 30;
if( n<0 ) n = 0;
}
@@ -129109,7 +130815,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}else if( n==0 ){
r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5)));
}else{
- zBuf = sqlite3_mprintf("%!.*f",n,r);
+ zBuf = sqlite3_mprintf("%!.*f",(int)n,r);
if( zBuf==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -129738,7 +131444,7 @@ static const char hexdigits[] = {
** Append to pStr text that is the SQL literal representation of the
** value contained in pValue.
*/
-SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
+SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){
/* As currently implemented, the string must be initially empty.
** we might relax this requirement in the future, but that will
** require enhancements to the implementation. */
@@ -129786,7 +131492,7 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
}
case SQLITE_TEXT: {
const unsigned char *zArg = sqlite3_value_text(pValue);
- sqlite3_str_appendf(pStr, "%Q", zArg);
+ sqlite3_str_appendf(pStr, bEscape ? "%#Q" : "%Q", zArg);
break;
}
default: {
@@ -129798,6 +131504,105 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
}
/*
+** Return true if z[] begins with N hexadecimal digits, and write
+** a decoding of those digits into *pVal. Or return false if any
+** one of the first N characters in z[] is not a hexadecimal digit.
+*/
+static int isNHex(const char *z, int N, u32 *pVal){
+ int i;
+ int v = 0;
+ for(i=0; i<N; i++){
+ if( !sqlite3Isxdigit(z[i]) ) return 0;
+ v = (v<<4) + sqlite3HexToInt(z[i]);
+ }
+ *pVal = v;
+ return 1;
+}
+
+/*
+** Implementation of the UNISTR() function.
+**
+** This is intended to be a work-alike of the UNISTR() function in
+** PostgreSQL. Quoting from the PG documentation (PostgreSQL 17 -
+** scraped on 2025-02-22):
+**
+** Evaluate escaped Unicode characters in the argument. Unicode
+** characters can be specified as \XXXX (4 hexadecimal digits),
+** \+XXXXXX (6 hexadecimal digits), \uXXXX (4 hexadecimal digits),
+** or \UXXXXXXXX (8 hexadecimal digits). To specify a backslash,
+** write two backslashes. All other characters are taken literally.
+*/
+static void unistrFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ char *zOut;
+ const char *zIn;
+ int nIn;
+ int i, j, n;
+ u32 v;
+
+ assert( argc==1 );
+ UNUSED_PARAMETER( argc );
+ zIn = (const char*)sqlite3_value_text(argv[0]);
+ if( zIn==0 ) return;
+ nIn = sqlite3_value_bytes(argv[0]);
+ zOut = sqlite3_malloc64(nIn+1);
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ i = j = 0;
+ while( i<nIn ){
+ char *z = strchr(&zIn[i],'\\');
+ if( z==0 ){
+ n = nIn - i;
+ memmove(&zOut[j], &zIn[i], n);
+ j += n;
+ break;
+ }
+ n = z - &zIn[i];
+ if( n>0 ){
+ memmove(&zOut[j], &zIn[i], n);
+ j += n;
+ i += n;
+ }
+ if( zIn[i+1]=='\\' ){
+ i += 2;
+ zOut[j++] = '\\';
+ }else if( sqlite3Isxdigit(zIn[i+1]) ){
+ if( !isNHex(&zIn[i+1], 4, &v) ) goto unistr_error;
+ i += 5;
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
+ }else if( zIn[i+1]=='+' ){
+ if( !isNHex(&zIn[i+2], 6, &v) ) goto unistr_error;
+ i += 8;
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
+ }else if( zIn[i+1]=='u' ){
+ if( !isNHex(&zIn[i+2], 4, &v) ) goto unistr_error;
+ i += 6;
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
+ }else if( zIn[i+1]=='U' ){
+ if( !isNHex(&zIn[i+2], 8, &v) ) goto unistr_error;
+ i += 10;
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
+ }else{
+ goto unistr_error;
+ }
+ }
+ zOut[j] = 0;
+ sqlite3_result_text64(context, zOut, j, sqlite3_free, SQLITE_UTF8);
+ return;
+
+unistr_error:
+ sqlite3_free(zOut);
+ sqlite3_result_error(context, "invalid Unicode escape", -1);
+ return;
+}
+
+
+/*
** Implementation of the QUOTE() function.
**
** The quote(X) function returns the text of an SQL literal which is the
@@ -129806,6 +131611,10 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
** as needed. BLOBs are encoded as hexadecimal literals. Strings with
** embedded NUL characters cannot be represented as string literals in SQL
** and hence the returned string literal is truncated prior to the first NUL.
+**
+** If sqlite3_user_data() is non-zero, then the UNISTR_QUOTE() function is
+** implemented instead. The difference is that UNISTR_QUOTE() uses the
+** UNISTR() function to escape control characters.
*/
static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3_str str;
@@ -129813,7 +131622,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
assert( argc==1 );
UNUSED_PARAMETER(argc);
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
- sqlite3QuoteValue(&str,argv[0]);
+ sqlite3QuoteValue(&str,argv[0],SQLITE_PTR_TO_INT(sqlite3_user_data(context)));
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar,
SQLITE_DYNAMIC);
if( str.accError!=SQLITE_OK ){
@@ -130068,7 +131877,7 @@ static void replaceFunc(
assert( zRep==sqlite3_value_text(argv[2]) );
nOut = nStr + 1;
assert( nOut<SQLITE_MAX_LENGTH );
- zOut = contextMalloc(context, (i64)nOut);
+ zOut = contextMalloc(context, nOut);
if( zOut==0 ){
return;
}
@@ -130212,13 +132021,13 @@ static void concatFuncCore(
int nSep,
const char *zSep
){
- i64 j, k, n = 0;
+ i64 j, n = 0;
int i;
char *z;
for(i=0; i<argc; i++){
n += sqlite3_value_bytes(argv[i]);
}
- n += (argc-1)*nSep;
+ n += (argc-1)*(i64)nSep;
z = sqlite3_malloc64(n+1);
if( z==0 ){
sqlite3_result_error_nomem(context);
@@ -130226,8 +132035,8 @@ static void concatFuncCore(
}
j = 0;
for(i=0; i<argc; i++){
- k = sqlite3_value_bytes(argv[i]);
- if( k>0 ){
+ if( sqlite3_value_type(argv[i])!=SQLITE_NULL ){
+ int k = sqlite3_value_bytes(argv[i]);
const char *v = (const char*)sqlite3_value_text(argv[i]);
if( v!=0 ){
if( j>0 && nSep>0 ){
@@ -130464,7 +132273,7 @@ static void kahanBabuskaNeumaierInit(
** that it returns NULL if it sums over no inputs. TOTAL returns
** 0.0 in that case. In addition, TOTAL always returns a float where
** SUM might return an integer if it never encounters a floating point
-** value. TOTAL never fails, but SUM might through an exception if
+** value. TOTAL never fails, but SUM might throw an exception if
** it overflows an integer.
*/
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
@@ -130516,7 +132325,10 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
assert( p->cnt>0 );
p->cnt--;
if( !p->approx ){
- p->iSum -= sqlite3_value_int64(argv[0]);
+ if( sqlite3SubInt64(&p->iSum, sqlite3_value_int64(argv[0])) ){
+ p->ovrfl = 1;
+ p->approx = 1;
+ }
}else if( type==SQLITE_INTEGER ){
i64 iVal = sqlite3_value_int64(argv[0]);
if( iVal!=SMALLEST_INT64 ){
@@ -130697,7 +132509,11 @@ static void minMaxFinalize(sqlite3_context *context){
** group_concat(EXPR, ?SEPARATOR?)
** string_agg(EXPR, SEPARATOR)
**
-** The SEPARATOR goes before the EXPR string. This is tragic. The
+** Content is accumulated in GroupConcatCtx.str with the SEPARATOR
+** coming before the EXPR value, except for the first entry which
+** omits the SEPARATOR.
+**
+** It is tragic that the SEPARATOR goes before the EXPR string. The
** groupConcatInverse() implementation would have been easier if the
** SEPARATOR were appended after EXPR. And the order is undocumented,
** so we could change it, in theory. But the old behavior has been
@@ -130801,7 +132617,7 @@ static void groupConcatInverse(
/* pGCC is always non-NULL since groupConcatStep() will have always
** run first to initialize it */
if( ALWAYS(pGCC) ){
- int nVS;
+ int nVS; /* Number of characters to remove */
/* Must call sqlite3_value_text() to convert the argument into text prior
** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */
(void)sqlite3_value_text(argv[0]);
@@ -131179,7 +132995,13 @@ static void signFunc(
** Implementation of fpdecode(x,y,z) function.
**
** x is a real number that is to be decoded. y is the precision.
-** z is the maximum real precision.
+** z is the maximum real precision. Return a string that shows the
+** results of the sqlite3FpDecode() function.
+**
+** Used for testing and debugging only, specifically testing and debugging
+** of the sqlite3FpDecode() function. This SQL function does not appear
+** in production builds. This function is not an API and is subject to
+** modification or removal in future versions of SQLite.
*/
static void fpdecodeFunc(
sqlite3_context *context,
@@ -131195,6 +133017,7 @@ static void fpdecodeFunc(
x = sqlite3_value_double(argv[0]);
y = sqlite3_value_int(argv[1]);
z = sqlite3_value_int(argv[2]);
+ if( z<=0 ) z = 1;
sqlite3FpDecode(&s, x, y, z);
if( s.isSpecial==2 ){
sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN");
@@ -131205,6 +133028,82 @@ static void fpdecodeFunc(
}
#endif /* SQLITE_DEBUG */
+#ifdef SQLITE_DEBUG
+/*
+** Implementation of parseuri(uri,flags) function.
+**
+** Required Arguments:
+** "uri" The URI to parse.
+** "flags" Bitmask of flags, as if to sqlite3_open_v2().
+**
+** Additional arguments beyond the first two make calls to
+** sqlite3_uri_key() for integers and sqlite3_uri_parameter for
+** anything else.
+**
+** The result is a string showing the results of calling sqlite3ParseUri().
+**
+** Used for testing and debugging only, specifically testing and debugging
+** of the sqlite3ParseUri() function. This SQL function does not appear
+** in production builds. This function is not an API and is subject to
+** modification or removal in future versions of SQLite.
+*/
+static void parseuriFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_str *pResult;
+ const char *zVfs;
+ const char *zUri;
+ unsigned int flgs;
+ int rc;
+ sqlite3_vfs *pVfs = 0;
+ char *zFile = 0;
+ char *zErr = 0;
+
+ if( argc<2 ) return;
+ pVfs = sqlite3_vfs_find(0);
+ assert( pVfs );
+ zVfs = pVfs->zName;
+ zUri = (const char*)sqlite3_value_text(argv[0]);
+ if( zUri==0 ) return;
+ flgs = (unsigned int)sqlite3_value_int(argv[1]);
+ rc = sqlite3ParseUri(zVfs, zUri, &flgs, &pVfs, &zFile, &zErr);
+ pResult = sqlite3_str_new(0);
+ if( pResult ){
+ int i;
+ sqlite3_str_appendf(pResult, "rc=%d", rc);
+ sqlite3_str_appendf(pResult, ", flags=0x%x", flgs);
+ sqlite3_str_appendf(pResult, ", vfs=%Q", pVfs ? pVfs->zName: 0);
+ sqlite3_str_appendf(pResult, ", err=%Q", zErr);
+ sqlite3_str_appendf(pResult, ", file=%Q", zFile);
+ if( zFile ){
+ const char *z = zFile;
+ z += sqlite3Strlen30(z)+1;
+ while( z[0] ){
+ sqlite3_str_appendf(pResult, ", %Q", z);
+ z += sqlite3Strlen30(z)+1;
+ }
+ for(i=2; i<argc; i++){
+ const char *zArg;
+ if( sqlite3_value_type(argv[i])==SQLITE_INTEGER ){
+ int k = sqlite3_value_int(argv[i]);
+ sqlite3_str_appendf(pResult, ", '%d:%q'",k,sqlite3_uri_key(zFile, k));
+ }else if( (zArg = (const char*)sqlite3_value_text(argv[i]))!=0 ){
+ sqlite3_str_appendf(pResult, ", '%q:%q'",
+ zArg, sqlite3_uri_parameter(zFile,zArg));
+ }else{
+ sqlite3_str_appendf(pResult, ", NULL");
+ }
+ }
+ }
+ sqlite3_result_text(ctx, sqlite3_str_finish(pResult), -1, sqlite3_free);
+ }
+ sqlite3_free_filename(zFile);
+ sqlite3_free(zErr);
+}
+#endif /* SQLITE_DEBUG */
+
/*
** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table. This occurs at start-time (as
@@ -131239,9 +133138,6 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
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 ),
-#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
@@ -131258,16 +133154,15 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(rtrim, 2, 2, 0, trimFunc ),
FUNCTION(trim, 1, 3, 0, trimFunc ),
FUNCTION(trim, 2, 3, 0, trimFunc ),
- FUNCTION(min, -1, 0, 1, minmaxFunc ),
- FUNCTION(min, 0, 0, 1, 0 ),
+ FUNCTION(min, -3, 0, 1, minmaxFunc ),
WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
- FUNCTION(max, -1, 1, 1, minmaxFunc ),
- FUNCTION(max, 0, 1, 1, 0 ),
+ FUNCTION(max, -3, 1, 1, minmaxFunc ),
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
- FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
+ FUNCTION2(subtype, 1, 0, 0, subtypeFunc,
+ SQLITE_FUNC_TYPEOF|SQLITE_SUBTYPE),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
FUNCTION(instr, 2, 0, 0, instrFunc ),
@@ -131278,6 +133173,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(abs, 1, 0, 0, absFunc ),
#ifdef SQLITE_DEBUG
FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
+ FUNCTION(parseuri, -1, 0, 0, parseuriFunc ),
#endif
#ifndef SQLITE_OMIT_FLOATING_POINT
FUNCTION(round, 1, 0, 0, roundFunc ),
@@ -131288,11 +133184,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION(unhex, 1, 0, 0, unhexFunc ),
FUNCTION(unhex, 2, 0, 0, unhexFunc ),
- FUNCTION(concat, -1, 0, 0, concatFunc ),
- FUNCTION(concat, 0, 0, 0, 0 ),
- FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ),
- FUNCTION(concat_ws, 0, 0, 0, 0 ),
- FUNCTION(concat_ws, 1, 0, 0, 0 ),
+ FUNCTION(concat, -3, 0, 0, concatFunc ),
+ FUNCTION(concat_ws, -4, 0, 0, concatwsFunc ),
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
@@ -131300,7 +133193,9 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
+ FUNCTION(unistr, 1, 0, 0, unistrFunc ),
FUNCTION(quote, 1, 0, 0, quoteFunc ),
+ FUNCTION(unistr_quote, 1, 1, 0, quoteFunc ),
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
VFUNCTION(changes, 0, 0, 0, changes ),
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
@@ -131336,8 +133231,6 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
FUNCTION(unknown, -1, 0, 0, unknownFunc ),
#endif
- FUNCTION(coalesce, 1, 0, 0, 0 ),
- FUNCTION(coalesce, 0, 0, 0, 0 ),
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
MFUNCTION(ceil, 1, xCeil, ceilingFunc ),
MFUNCTION(ceiling, 1, xCeil, ceilingFunc ),
@@ -131372,11 +133265,12 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
MFUNCTION(sqrt, 1, sqrt, math1Func ),
MFUNCTION(radians, 1, degToRad, math1Func ),
MFUNCTION(degrees, 1, radToDeg, math1Func ),
- FUNCTION(pi, 0, 0, 0, piFunc ),
+ MFUNCTION(pi, 0, 0, piFunc ),
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
FUNCTION(sign, 1, 0, 0, signFunc ),
- INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
- INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
+ INLINE_FUNC(coalesce, -4, INLINEFUNC_coalesce, 0 ),
+ INLINE_FUNC(iif, -4, INLINEFUNC_iif, 0 ),
+ INLINE_FUNC(if, -4, INLINEFUNC_iif, 0 ),
};
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
@@ -132451,9 +134345,9 @@ SQLITE_PRIVATE void sqlite3FkCheck(
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pSrc ){
SrcItem *pItem = pSrc->a;
- pItem->pTab = pFKey->pFrom;
+ pItem->pSTab = pFKey->pFrom;
pItem->zName = pFKey->pFrom->zName;
- pItem->pTab->nTabRef++;
+ pItem->pSTab->nTabRef++;
pItem->iCursor = pParse->nTab++;
if( regNew!=0 ){
@@ -132736,7 +134630,8 @@ static Trigger *fkActionTrigger(
SrcList *pSrc;
Expr *pRaise;
- pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
+ pRaise = sqlite3Expr(db, TK_STRING, "FOREIGN KEY constraint failed"),
+ pRaise = sqlite3PExpr(pParse, TK_RAISE, pRaise, 0);
if( pRaise ){
pRaise->affExpr = OE_Abort;
}
@@ -132744,7 +134639,8 @@ static Trigger *fkActionTrigger(
if( pSrc ){
assert( pSrc->nSrc==1 );
pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
- pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
+ assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 );
+ pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
}
pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise),
@@ -133478,8 +135374,11 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
SrcItem *pItem = &pVal->pSrc->a[0];
- sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn);
- sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1);
+ assert( (pItem->fg.isSubquery && pItem->u4.pSubq!=0) || pParse->nErr );
+ if( pItem->fg.isSubquery ){
+ sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->u4.pSubq->regReturn);
+ sqlite3VdbeJumpHere(pParse->pVdbe, pItem->u4.pSubq->addrFillSub - 1);
+ }
}
}
@@ -133583,7 +135482,7 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList
f = (f & pLeft->selFlags);
}
pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0);
- pLeft->selFlags &= ~SF_MultiValue;
+ pLeft->selFlags &= ~(u32)SF_MultiValue;
if( pSelect ){
pSelect->op = TK_ALL;
pSelect->pPrior = pLeft;
@@ -133607,6 +135506,7 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList
if( pRet ){
SelectDest dest;
+ Subquery *pSubq;
pRet->pSrc->nSrc = 1;
pRet->pPrior = pLeft->pPrior;
pRet->op = pLeft->op;
@@ -133616,28 +135516,32 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList
assert( pLeft->pNext==0 );
assert( pRet->pNext==0 );
p = &pRet->pSrc->a[0];
- p->pSelect = pLeft;
p->fg.viaCoroutine = 1;
- p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
- p->regReturn = ++pParse->nMem;
p->iCursor = -1;
+ assert( !p->fg.isIndexedBy && !p->fg.isTabFunc );
p->u1.nRow = 2;
- sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub);
- sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn);
-
- /* Allocate registers for the output of the co-routine. Do so so
- ** that there are two unused registers immediately before those
- ** used by the co-routine. This allows the code in sqlite3Insert()
- ** to use these registers directly, instead of copying the output
- ** of the co-routine to a separate array for processing. */
- dest.iSdst = pParse->nMem + 3;
- dest.nSdst = pLeft->pEList->nExpr;
- pParse->nMem += 2 + dest.nSdst;
-
- pLeft->selFlags |= SF_MultiValue;
- sqlite3Select(pParse, pLeft, &dest);
- p->regResult = dest.iSdst;
- assert( pParse->nErr || dest.iSdst>0 );
+ if( sqlite3SrcItemAttachSubquery(pParse, p, pLeft, 0) ){
+ pSubq = p->u4.pSubq;
+ pSubq->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
+ pSubq->regReturn = ++pParse->nMem;
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine,
+ pSubq->regReturn, 0, pSubq->addrFillSub);
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
+
+ /* Allocate registers for the output of the co-routine. Do so so
+ ** that there are two unused registers immediately before those
+ ** used by the co-routine. This allows the code in sqlite3Insert()
+ ** to use these registers directly, instead of copying the output
+ ** of the co-routine to a separate array for processing. */
+ dest.iSdst = pParse->nMem + 3;
+ dest.nSdst = pLeft->pEList->nExpr;
+ pParse->nMem += 2 + dest.nSdst;
+
+ pLeft->selFlags |= SF_MultiValue;
+ sqlite3Select(pParse, pLeft, &dest);
+ pSubq->regResult = dest.iSdst;
+ assert( pParse->nErr || dest.iSdst>0 );
+ }
pLeft = pRet;
}
}else{
@@ -133647,12 +135551,18 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList
}
if( pParse->nErr==0 ){
+ Subquery *pSubq;
assert( p!=0 );
- if( p->pSelect->pEList->nExpr!=pRow->nExpr ){
- sqlite3SelectWrongNumTermsError(pParse, p->pSelect);
+ assert( p->fg.isSubquery );
+ pSubq = p->u4.pSubq;
+ assert( pSubq!=0 );
+ assert( pSubq->pSelect!=0 );
+ assert( pSubq->pSelect->pEList!=0 );
+ if( pSubq->pSelect->pEList->nExpr!=pRow->nExpr ){
+ sqlite3SelectWrongNumTermsError(pParse, pSubq->pSelect);
}else{
- sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0);
- sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn);
+ sqlite3ExprCodeExprList(pParse, pRow, pSubq->regResult, 0, 0);
+ sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pSubq->regReturn);
}
}
sqlite3ExprListDelete(pParse->db, pRow);
@@ -133806,6 +135716,7 @@ SQLITE_PRIVATE void sqlite3Insert(
int regRowid; /* registers holding insert rowid */
int regData; /* register holding first column to insert */
int *aRegIdx = 0; /* One register allocated to each index */
+ int *aTabColMap = 0; /* Mapping from pTab columns to pCol entries */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to insert into a view */
@@ -133950,31 +135861,25 @@ SQLITE_PRIVATE void sqlite3Insert(
*/
bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
if( pColumn ){
- assert( pColumn->eU4!=EU4_EXPR );
- pColumn->eU4 = EU4_IDX;
+ aTabColMap = sqlite3DbMallocZero(db, pTab->nCol*sizeof(int));
+ if( aTabColMap==0 ) goto insert_cleanup;
for(i=0; i<pColumn->nId; i++){
- pColumn->a[i].u4.idx = -1;
- }
- for(i=0; i<pColumn->nId; i++){
- for(j=0; j<pTab->nCol; j++){
- if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){
- pColumn->a[i].u4.idx = j;
- if( i!=j ) bIdListInOrder = 0;
- if( j==pTab->iPKey ){
- ipkColumn = i; assert( !withoutRowid );
- }
+ j = sqlite3ColumnIndex(pTab, pColumn->a[i].zName);
+ if( j>=0 ){
+ if( aTabColMap[j]==0 ) aTabColMap[j] = i+1;
+ if( i!=j ) bIdListInOrder = 0;
+ 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].zCnName);
- goto insert_cleanup;
- }
-#endif
- break;
+ if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
+ sqlite3ErrorMsg(pParse,
+ "cannot INSERT into generated column \"%s\"",
+ pTab->aCol[j].zCnName);
+ goto insert_cleanup;
}
- }
- if( j>=pTab->nCol ){
+#endif
+ }else{
if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){
ipkColumn = i;
bIdListInOrder = 0;
@@ -134003,9 +135908,14 @@ SQLITE_PRIVATE void sqlite3Insert(
&& pSelect->pPrior==0
){
SrcItem *pItem = &pSelect->pSrc->a[0];
- dest.iSDParm = pItem->regReturn;
- regFromSelect = pItem->regResult;
- nColumn = pItem->pSelect->pEList->nExpr;
+ Subquery *pSubq;
+ assert( pItem->fg.isSubquery );
+ pSubq = pItem->u4.pSubq;
+ dest.iSDParm = pSubq->regReturn;
+ regFromSelect = pSubq->regResult;
+ assert( pSubq->pSelect!=0 );
+ assert( pSubq->pSelect->pEList!=0 );
+ nColumn = pSubq->pSelect->pEList->nExpr;
ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
if( bIdListInOrder && nColumn==pTab->nCol ){
regData = regFromSelect;
@@ -134267,7 +136177,7 @@ SQLITE_PRIVATE void sqlite3Insert(
continue;
}else if( pColumn==0 ){
/* Hidden columns that are not explicitly named in the INSERT
- ** get there default value */
+ ** get their default value */
sqlite3ExprCodeFactorable(pParse,
sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
iRegStore);
@@ -134275,9 +136185,9 @@ SQLITE_PRIVATE void sqlite3Insert(
}
}
if( pColumn ){
- assert( pColumn->eU4==EU4_IDX );
- for(j=0; j<pColumn->nId && pColumn->a[j].u4.idx!=i; j++){}
- if( j>=pColumn->nId ){
+ j = aTabColMap[i];
+ assert( j>=0 && j<=pColumn->nId );
+ if( j==0 ){
/* A column not named in the insert column list gets its
** default value */
sqlite3ExprCodeFactorable(pParse,
@@ -134285,7 +136195,7 @@ SQLITE_PRIVATE void sqlite3Insert(
iRegStore);
continue;
}
- k = j;
+ k = j - 1;
}else if( nColumn==0 ){
/* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */
sqlite3ExprCodeFactorable(pParse,
@@ -134530,7 +136440,10 @@ insert_cleanup:
sqlite3ExprListDelete(db, pList);
sqlite3UpsertDelete(db, pUpsert);
sqlite3SelectDelete(db, pSelect);
- sqlite3IdListDelete(db, pColumn);
+ if( pColumn ){
+ sqlite3IdListDelete(db, pColumn);
+ sqlite3DbFree(db, aTabColMap);
+ }
if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx);
}
@@ -134989,7 +136902,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
** could happen in any order, but they are grouped up front for
** convenience.
**
- ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43
+ ** 2018-08-14: Ticket https://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.
@@ -135925,7 +137838,7 @@ static int xferOptimization(
if( pSelect->pSrc->nSrc!=1 ){
return 0; /* FROM clause must have exactly one term */
}
- if( pSelect->pSrc->a[0].pSelect ){
+ if( pSelect->pSrc->a[0].fg.isSubquery ){
return 0; /* FROM clause cannot contain a subquery */
}
if( pSelect->pWhere ){
@@ -136799,6 +138712,8 @@ struct sqlite3_api_routines {
/* Version 3.44.0 and later */
void *(*get_clientdata)(sqlite3*,const char*);
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
+ /* Version 3.50.0 and later */
+ int (*setlk_timeout)(sqlite3*,int,int);
};
/*
@@ -137132,6 +139047,8 @@ typedef int (*sqlite3_loadext_entry)(
/* Version 3.44.0 and later */
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
+/* Version 3.50.0 and later */
+#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -137653,7 +139570,9 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_stmt_explain,
/* Version 3.44.0 and later */
sqlite3_get_clientdata,
- sqlite3_set_clientdata
+ sqlite3_set_clientdata,
+ /* Version 3.50.0 and later */
+ sqlite3_setlk_timeout
};
/* True if x is the directory separator character
@@ -138175,48 +140094,48 @@ static const char *const pragCName[] = {
/* 13 */ "pk",
/* 14 */ "hidden",
/* table_info reuses 8 */
- /* 15 */ "schema", /* Used by: table_list */
- /* 16 */ "name",
+ /* 15 */ "name", /* Used by: function_list */
+ /* 16 */ "builtin",
/* 17 */ "type",
- /* 18 */ "ncol",
- /* 19 */ "wr",
- /* 20 */ "strict",
- /* 21 */ "seqno", /* Used by: index_xinfo */
- /* 22 */ "cid",
- /* 23 */ "name",
- /* 24 */ "desc",
- /* 25 */ "coll",
- /* 26 */ "key",
- /* 27 */ "name", /* Used by: function_list */
- /* 28 */ "builtin",
- /* 29 */ "type",
- /* 30 */ "enc",
- /* 31 */ "narg",
- /* 32 */ "flags",
- /* 33 */ "tbl", /* Used by: stats */
- /* 34 */ "idx",
- /* 35 */ "wdth",
- /* 36 */ "hght",
- /* 37 */ "flgs",
- /* 38 */ "seq", /* Used by: index_list */
- /* 39 */ "name",
- /* 40 */ "unique",
- /* 41 */ "origin",
- /* 42 */ "partial",
+ /* 18 */ "enc",
+ /* 19 */ "narg",
+ /* 20 */ "flags",
+ /* 21 */ "schema", /* Used by: table_list */
+ /* 22 */ "name",
+ /* 23 */ "type",
+ /* 24 */ "ncol",
+ /* 25 */ "wr",
+ /* 26 */ "strict",
+ /* 27 */ "seqno", /* Used by: index_xinfo */
+ /* 28 */ "cid",
+ /* 29 */ "name",
+ /* 30 */ "desc",
+ /* 31 */ "coll",
+ /* 32 */ "key",
+ /* 33 */ "seq", /* Used by: index_list */
+ /* 34 */ "name",
+ /* 35 */ "unique",
+ /* 36 */ "origin",
+ /* 37 */ "partial",
+ /* 38 */ "tbl", /* Used by: stats */
+ /* 39 */ "idx",
+ /* 40 */ "wdth",
+ /* 41 */ "hght",
+ /* 42 */ "flgs",
/* 43 */ "table", /* Used by: foreign_key_check */
/* 44 */ "rowid",
/* 45 */ "parent",
/* 46 */ "fkid",
- /* index_info reuses 21 */
- /* 47 */ "seq", /* Used by: database_list */
- /* 48 */ "name",
- /* 49 */ "file",
- /* 50 */ "busy", /* Used by: wal_checkpoint */
- /* 51 */ "log",
- /* 52 */ "checkpointed",
- /* collation_list reuses 38 */
+ /* 47 */ "busy", /* Used by: wal_checkpoint */
+ /* 48 */ "log",
+ /* 49 */ "checkpointed",
+ /* 50 */ "seq", /* Used by: database_list */
+ /* 51 */ "name",
+ /* 52 */ "file",
+ /* index_info reuses 27 */
/* 53 */ "database", /* Used by: lock_status */
/* 54 */ "status",
+ /* collation_list reuses 33 */
/* 55 */ "cache_size", /* Used by: default_cache_size */
/* module_list pragma_list reuses 9 */
/* 56 */ "timeout", /* Used by: busy_timeout */
@@ -138309,7 +140228,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "collation_list",
/* ePragTyp: */ PragTyp_COLLATION_LIST,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 38, 2,
+ /* ColNames: */ 33, 2,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
@@ -138344,7 +140263,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 47, 3,
+ /* ColNames: */ 50, 3,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
@@ -138424,7 +140343,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "function_list",
/* ePragTyp: */ PragTyp_FUNCTION_LIST,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 27, 6,
+ /* ColNames: */ 15, 6,
/* iArg: */ 0 },
#endif
#endif
@@ -138453,17 +140372,17 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "index_info",
/* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
- /* ColNames: */ 21, 3,
+ /* ColNames: */ 27, 3,
/* iArg: */ 0 },
{/* zName: */ "index_list",
/* ePragTyp: */ PragTyp_INDEX_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
- /* ColNames: */ 38, 5,
+ /* ColNames: */ 33, 5,
/* iArg: */ 0 },
{/* zName: */ "index_xinfo",
/* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
- /* ColNames: */ 21, 6,
+ /* ColNames: */ 27, 6,
/* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
@@ -138642,7 +140561,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "stats",
/* ePragTyp: */ PragTyp_STATS,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
- /* ColNames: */ 33, 5,
+ /* ColNames: */ 38, 5,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
@@ -138661,7 +140580,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "table_list",
/* ePragTyp: */ PragTyp_TABLE_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1,
- /* ColNames: */ 15, 6,
+ /* ColNames: */ 21, 6,
/* iArg: */ 0 },
{/* zName: */ "table_xinfo",
/* ePragTyp: */ PragTyp_TABLE_INFO,
@@ -138738,7 +140657,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "wal_checkpoint",
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
/* ePragFlg: */ PragFlg_NeedSchema,
- /* ColNames: */ 50, 3,
+ /* ColNames: */ 47, 3,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
@@ -138760,7 +140679,7 @@ static const PragmaName aPragmaName[] = {
** the following macro or to the actual analysis_limit if it is non-zero,
** in order to prevent PRAGMA optimize from running for too long.
**
-** The value of 2000 is chosen emperically so that the worst-case run-time
+** The value of 2000 is chosen empirically so that the worst-case run-time
** for PRAGMA optimize does not exceed 100 milliseconds against a variety
** of test databases on a RaspberryPI-4 compiled using -Os and without
** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of
@@ -139868,12 +141787,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
** in auto-commit mode. */
mask &= ~(SQLITE_ForeignKeys);
}
-#if SQLITE_USER_AUTHENTICATION
- if( db->auth.authLevel==UAUTH_User ){
- /* Do not allow non-admin users to modify the schema arbitrarily */
- mask &= ~(SQLITE_WriteSchema);
- }
-#endif
if( sqlite3GetBoolean(zRight, 0) ){
if( (mask & SQLITE_WriteSchema)==0
@@ -139883,7 +141796,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
}else{
db->flags &= ~mask;
- if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
+ if( mask==SQLITE_DeferFKs ){
+ db->nDeferredImmCons = 0;
+ db->nDeferredCons = 0;
+ }
if( (mask & SQLITE_WriteSchema)!=0
&& sqlite3_stricmp(zRight, "reset")==0
){
@@ -140009,7 +141925,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName);
if( zSql ){
sqlite3_stmt *pDummy = 0;
- (void)sqlite3_prepare(db, zSql, -1, &pDummy, 0);
+ (void)sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_DONT_LOG,
+ &pDummy, 0);
(void)sqlite3_finalize(pDummy);
sqlite3DbFree(db, zSql);
}
@@ -140485,11 +142402,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Make sure sufficient number of registers have been allocated */
sqlite3TouchRegister(pParse, 8+cnt);
+ sqlite3VdbeAddOp3(v, OP_Null, 0, 8, 8+cnt);
sqlite3ClearTempRegCache(pParse);
/* Do the b-tree integrity checks */
sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY);
- sqlite3VdbeChangeP5(v, (u8)i);
+ sqlite3VdbeChangeP5(v, (u16)i);
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
@@ -142109,14 +144027,7 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
#else
encoding = SQLITE_UTF8;
#endif
- if( db->nVdbeActive>0 && encoding!=ENC(db)
- && (db->mDbFlags & DBFLAG_Vacuum)==0
- ){
- rc = SQLITE_LOCKED;
- goto initone_error_out;
- }else{
- sqlite3SetTextEncoding(db, encoding);
- }
+ sqlite3SetTextEncoding(db, encoding);
}else{
/* If opening an attached database, the encoding much match ENC(db) */
if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){
@@ -142810,12 +144721,24 @@ static int sqlite3Prepare16(
if( !sqlite3SafetyCheckOk(db)||zSql==0 ){
return SQLITE_MISUSE_BKPT;
}
+
+ /* Make sure nBytes is non-negative and correct. It should be the
+ ** number of bytes until the end of the input buffer or until the first
+ ** U+0000 character. If the input nBytes is odd, convert it into
+ ** an even number. If the input nBytes is negative, then the input
+ ** must be terminated by at least one U+0000 character */
if( nBytes>=0 ){
int sz;
const char *z = (const char*)zSql;
for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){}
nBytes = sz;
+ }else{
+ int sz;
+ const char *z = (const char*)zSql;
+ for(sz=0; z[sz]!=0 || z[sz+1]!=0; sz += 2){}
+ nBytes = sz;
}
+
sqlite3_mutex_enter(db->mutex);
zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
if( zSql8 ){
@@ -142829,7 +144752,7 @@ static int sqlite3Prepare16(
** the same number of characters into the UTF-16 string.
*/
int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
- *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
+ *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, nBytes, chars_parsed);
}
sqlite3DbFree(db, zSql8);
rc = sqlite3ApiExit(db, rc);
@@ -143045,7 +144968,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = 0;
- if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
+ if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1);
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
pNew->pGroupBy = pGroupBy;
@@ -143210,10 +145133,33 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p
*/
SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){
int i;
- u8 h = sqlite3StrIHash(zCol);
- Column *pCol;
- for(pCol=pTab->aCol, i=0; i<pTab->nCol; pCol++, i++){
- if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i;
+ u8 h;
+ const Column *aCol;
+ int nCol;
+
+ h = sqlite3StrIHash(zCol);
+ aCol = pTab->aCol;
+ nCol = pTab->nCol;
+
+ /* See if the aHx gives us a lucky match */
+ i = pTab->aHx[h % sizeof(pTab->aHx)];
+ assert( i<nCol );
+ if( aCol[i].hName==h
+ && sqlite3StrICmp(aCol[i].zCnName, zCol)==0
+ ){
+ return i;
+ }
+
+ /* No lucky match from the hash table. Do a full search. */
+ i = 0;
+ while( 1 /*exit-by-break*/ ){
+ if( aCol[i].hName==h
+ && sqlite3StrICmp(aCol[i].zCnName, zCol)==0
+ ){
+ return i;
+ }
+ i++;
+ if( i>=nCol ) break;
}
return -1;
}
@@ -143223,11 +145169,13 @@ SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){
*/
SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){
assert( pItem!=0 );
- assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
if( pItem->fg.isNestedFrom ){
ExprList *pResults;
- assert( pItem->pSelect!=0 );
- pResults = pItem->pSelect->pEList;
+ assert( pItem->fg.isSubquery );
+ assert( pItem->u4.pSubq!=0 );
+ assert( pItem->u4.pSubq->pSelect!=0 );
+ pResults = pItem->u4.pSubq->pSelect->pEList;
assert( pResults!=0 );
assert( iCol>=0 && iCol<pResults->nExpr );
pResults->a[iCol].fg.bUsed = 1;
@@ -143261,9 +145209,9 @@ static int tableAndColumnIndex(
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
for(i=iStart; i<=iEnd; i++){
- iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol);
+ iCol = sqlite3ColumnIndex(pSrc->a[i].pSTab, zCol);
if( iCol>=0
- && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
+ && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pSTab->aCol[iCol])==0)
){
if( piTab ){
sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol);
@@ -143392,10 +145340,10 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
pLeft = &pSrc->a[0];
pRight = &pLeft[1];
for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
- Table *pRightTab = pRight->pTab;
+ Table *pRightTab = pRight->pSTab;
u32 joinType;
- if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
+ if( NEVER(pLeft->pSTab==0 || pRightTab==0) ) continue;
joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
/* If this is a NATURAL join, synthesize an appropriate USING clause
@@ -143462,7 +145410,7 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
}
pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iLeftCol);
sqlite3SrcItemColumnUsed(&pSrc->a[iLeft], iLeftCol);
- if( (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
+ if( (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 && pParse->nErr==0 ){
/* This branch runs if the query contains one or more RIGHT or FULL
** JOINs. If only a single table on the left side of this join
** contains the zName column, then this branch is a no-op.
@@ -143478,6 +145426,8 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
*/
ExprList *pFuncArgs = 0; /* Arguments to the coalesce() */
static const Token tkCoalesce = { "coalesce", 8 };
+ assert( pE1!=0 );
+ ExprSetProperty(pE1, EP_CanBeNull);
while( tableAndColumnIndex(pSrc, iLeft+1, i, zName, &iLeft, &iLeftCol,
pRight->fg.isSynthUsing)!=0 ){
if( pSrc->a[iLeft].fg.isUsing==0
@@ -143494,7 +145444,13 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
if( pFuncArgs ){
pFuncArgs = sqlite3ExprListAppend(pParse, pFuncArgs, pE1);
pE1 = sqlite3ExprFunction(pParse, pFuncArgs, &tkCoalesce, 0);
+ if( pE1 ){
+ pE1->affExpr = SQLITE_AFF_DEFER;
+ }
}
+ }else if( (pSrc->a[i+1].fg.jointype & JT_LEFT)!=0 && pParse->nErr==0 ){
+ assert( pE1!=0 );
+ ExprSetProperty(pE1, EP_CanBeNull);
}
pE2 = sqlite3CreateColumnExpr(db, pSrc, i+1, iRightCol);
sqlite3SrcItemColumnUsed(pRight, iRightCol);
@@ -144268,12 +146224,18 @@ static void selectInnerLoop(
** case the order does matter */
pushOntoSorter(
pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
+ pDest->iSDParm2 = 0; /* Signal that any Bloom filter is unpopulated */
}else{
int r1 = sqlite3GetTempReg(pParse);
assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
r1, pDest->zAffSdst, nResultCol);
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
+ if( pDest->iSDParm2 ){
+ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0,
+ regResult, nResultCol);
+ ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER"));
+ }
sqlite3ReleaseTempReg(pParse, r1);
}
break;
@@ -144397,8 +146359,8 @@ static void selectInnerLoop(
** X extra columns.
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
- int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
- KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
+ int nExtra = (N+X)*(sizeof(CollSeq*)+1);
+ KeyInfo *p = sqlite3DbMallocRawNN(db, SZ_KEYINFO(0) + nExtra);
if( p ){
p->aSortFlags = (u8*)&p->aColl[N+X];
p->nKeyField = (u16)N;
@@ -144406,7 +146368,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
p->enc = ENC(db);
p->db = db;
p->nRef = 1;
- memset(&p[1], 0, nExtra);
+ memset(p->aColl, 0, nExtra);
}else{
return (KeyInfo*)sqlite3OomFault(db);
}
@@ -144815,8 +146777,12 @@ static const char *columnTypeImpl(
SrcList *pTabList = pNC->pSrcList;
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
if( j<pTabList->nSrc ){
- pTab = pTabList->a[j].pTab;
- pS = pTabList->a[j].pSelect;
+ pTab = pTabList->a[j].pSTab;
+ if( pTabList->a[j].fg.isSubquery ){
+ pS = pTabList->a[j].u4.pSubq->pSelect;
+ }else{
+ pS = 0;
+ }
}else{
pNC = pNC->pNext;
}
@@ -145383,7 +147349,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
p->iLimit = iLimit = ++pParse->nMem;
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
- if( sqlite3ExprIsInteger(pLimit->pLeft, &n) ){
+ if( sqlite3ExprIsInteger(pLimit->pLeft, &n, pParse) ){
sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit);
VdbeComment((v, "LIMIT counter"));
if( n==0 ){
@@ -145863,7 +147829,7 @@ static int multiSelect(
p->pPrior = pPrior;
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
if( p->pLimit
- && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit)
+ && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse)
&& nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
){
p->nSelectRow = sqlite3LogEst((u64)nLimit);
@@ -146103,6 +148069,7 @@ static int multiSelect(
multi_select_end:
pDest->iSdst = dest.iSdst;
pDest->nSdst = dest.nSdst;
+ pDest->iSDParm2 = dest.iSDParm2;
if( pDelete ){
sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete);
}
@@ -146207,6 +148174,11 @@ static int generateOutputSubroutine(
r1, pDest->zAffSdst, pIn->nSdst);
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1,
pIn->iSdst, pIn->nSdst);
+ if( pDest->iSDParm2>0 ){
+ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0,
+ pIn->iSdst, pIn->nSdst);
+ ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER"));
+ }
sqlite3ReleaseTempReg(pParse, r1);
break;
}
@@ -146785,32 +148757,32 @@ static Expr *substExpr(
if( pSubst->isOuterJoin ){
ExprSetProperty(pNew, EP_CanBeNull);
}
- if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
- sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
- pExpr->flags & (EP_OuterON|EP_InnerON));
- }
- sqlite3ExprDelete(db, pExpr);
- pExpr = pNew;
- if( pExpr->op==TK_TRUEFALSE ){
- pExpr->u.iValue = sqlite3ExprTruthValue(pExpr);
- pExpr->op = TK_INTEGER;
- ExprSetProperty(pExpr, EP_IntValue);
+ if( pNew->op==TK_TRUEFALSE ){
+ pNew->u.iValue = sqlite3ExprTruthValue(pNew);
+ pNew->op = TK_INTEGER;
+ ExprSetProperty(pNew, EP_IntValue);
}
/* 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. */
{
- CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
+ CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pNew);
CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse,
pSubst->pCList->a[iColumn].pExpr
);
- if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){
- pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
+ if( pNat!=pColl || (pNew->op!=TK_COLUMN && pNew->op!=TK_COLLATE) ){
+ pNew = sqlite3ExprAddCollateString(pSubst->pParse, pNew,
(pColl ? pColl->zName : "BINARY")
);
}
}
- ExprClearProperty(pExpr, EP_Collate);
+ ExprClearProperty(pNew, EP_Collate);
+ if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
+ sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
+ pExpr->flags & (EP_OuterON|EP_InnerON));
+ }
+ sqlite3ExprDelete(db, pExpr);
+ pExpr = pNew;
}
}
}else{
@@ -146863,7 +148835,9 @@ static void substSelect(
pSrc = p->pSrc;
assert( pSrc!=0 );
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
- substSelect(pSubst, pItem->pSelect, 1);
+ if( pItem->fg.isSubquery ){
+ substSelect(pSubst, pItem->u4.pSubq->pSelect, 1);
+ }
if( pItem->fg.isTabFunc ){
substExprList(pSubst, pItem->u1.pFuncArg);
}
@@ -146894,7 +148868,7 @@ static void recomputeColumnsUsed(
SrcItem *pSrcItem /* Which FROM clause item to recompute */
){
Walker w;
- if( NEVER(pSrcItem->pTab==0) ) return;
+ if( NEVER(pSrcItem->pSTab==0) ) return;
memset(&w, 0, sizeof(w));
w.xExprCallback = recomputeColumnsUsedExpr;
w.xSelectCallback = sqlite3SelectWalkNoop;
@@ -146934,8 +148908,10 @@ static void srclistRenumberCursors(
aCsrMap[pItem->iCursor+1] = pParse->nTab++;
}
pItem->iCursor = aCsrMap[pItem->iCursor+1];
- for(p=pItem->pSelect; p; p=p->pPrior){
- srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
+ if( pItem->fg.isSubquery ){
+ for(p=pItem->u4.pSubq->pSelect; p; p=p->pPrior){
+ srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
+ }
}
}
}
@@ -147082,9 +149058,9 @@ static int compoundHasDifferentAffinities(Select *p){
** from 2015-02-09.)
**
** (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
+** (3a) the subquery may not be a join
+** (**) Was (3b): "the FROM clause of the subquery may not contain
+** a virtual table"
** (**) Was: "The outer query may not have a GROUP BY." This case
** is now managed correctly
** (3d) the outer query may not be DISTINCT.
@@ -147246,7 +149222,8 @@ static int flattenSubquery(
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
pSubitem = &pSrc->a[iFrom];
iParent = pSubitem->iCursor;
- pSub = pSubitem->pSelect;
+ assert( pSubitem->fg.isSubquery );
+ pSub = pSubitem->u4.pSubq->pSelect;
assert( pSub!=0 );
#ifndef SQLITE_OMIT_WINDOWFUNC
@@ -147299,7 +149276,7 @@ static int flattenSubquery(
*/
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
if( pSubSrc->nSrc>1 /* (3a) */
- || IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
+ /**** || IsVirtual(pSubSrc->a[0].pSTab) (3b)-omitted */
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
){
@@ -147385,14 +149362,18 @@ static int flattenSubquery(
pParse->zAuthContext = zSavedAuthContext;
/* Delete the transient structures associated with the subquery */
- pSub1 = pSubitem->pSelect;
- sqlite3DbFree(db, pSubitem->zDatabase);
+
+ if( ALWAYS(pSubitem->fg.isSubquery) ){
+ pSub1 = sqlite3SubqueryDetach(db, pSubitem);
+ }else{
+ pSub1 = 0;
+ }
+ assert( pSubitem->fg.isSubquery==0 );
+ assert( pSubitem->fg.fixedSchema==0 );
sqlite3DbFree(db, pSubitem->zName);
sqlite3DbFree(db, pSubitem->zAlias);
- pSubitem->zDatabase = 0;
pSubitem->zName = 0;
pSubitem->zAlias = 0;
- pSubitem->pSelect = 0;
assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 );
/* If the sub-query is a compound SELECT statement, then (by restrictions
@@ -147433,8 +149414,8 @@ static int flattenSubquery(
ExprList *pOrderBy = p->pOrderBy;
Expr *pLimit = p->pLimit;
Select *pPrior = p->pPrior;
- Table *pItemTab = pSubitem->pTab;
- pSubitem->pTab = 0;
+ Table *pItemTab = pSubitem->pSTab;
+ pSubitem->pSTab = 0;
p->pOrderBy = 0;
p->pPrior = 0;
p->pLimit = 0;
@@ -147442,7 +149423,7 @@ static int flattenSubquery(
p->pLimit = pLimit;
p->pOrderBy = pOrderBy;
p->op = TK_ALL;
- pSubitem->pTab = pItemTab;
+ pSubitem->pSTab = pItemTab;
if( pNew==0 ){
p->pPrior = pPrior;
}else{
@@ -147457,11 +149438,14 @@ static int flattenSubquery(
TREETRACE(0x4,pParse,p,("compound-subquery flattener"
" creates %u as peer\n",pNew->selId));
}
- assert( pSubitem->pSelect==0 );
+ assert( pSubitem->fg.isSubquery==0 );
}
sqlite3DbFree(db, aCsrMap);
if( db->mallocFailed ){
- pSubitem->pSelect = pSub1;
+ assert( pSubitem->fg.fixedSchema==0 );
+ assert( pSubitem->fg.isSubquery==0 );
+ assert( pSubitem->u4.zDatabase==0 );
+ sqlite3SrcItemAttachSubquery(pParse, pSubitem, pSub1, 0);
return 1;
}
@@ -147472,8 +149456,8 @@ static int flattenSubquery(
**
** pSubitem->pTab is always non-NULL by test restrictions and tests above.
*/
- if( ALWAYS(pSubitem->pTab!=0) ){
- Table *pTabToDel = pSubitem->pTab;
+ if( ALWAYS(pSubitem->pSTab!=0) ){
+ Table *pTabToDel = pSubitem->pSTab;
if( pTabToDel->nTabRef==1 ){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel);
@@ -147481,7 +149465,7 @@ static int flattenSubquery(
}else{
pTabToDel->nTabRef--;
}
- pSubitem->pTab = 0;
+ pSubitem->pSTab = 0;
}
/* The following loop runs once for each term in a compound-subquery
@@ -147535,13 +149519,16 @@ static int flattenSubquery(
/* Transfer the FROM clause terms from the subquery into the
** outer query.
*/
+ iNewParent = pSubSrc->a[0].iCursor;
for(i=0; i<nSubSrc; i++){
SrcItem *pItem = &pSrc->a[i+iFrom];
- if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
assert( pItem->fg.isTabFunc==0 );
+ assert( pItem->fg.isSubquery
+ || pItem->fg.fixedSchema
+ || pItem->u4.zDatabase==0 );
+ if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
*pItem = pSubSrc->a[i];
pItem->fg.jointype |= ltorj;
- iNewParent = pSubSrc->a[i].iCursor;
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
}
pSrc->a[iFrom].fg.jointype &= JT_LTORJ;
@@ -147581,6 +149568,7 @@ static int flattenSubquery(
pWhere = pSub->pWhere;
pSub->pWhere = 0;
if( isOuterJoin>0 ){
+ assert( pSubSrc->nSrc==1 );
sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON);
}
if( pWhere ){
@@ -147692,7 +149680,8 @@ static void constInsert(
return; /* Already present. Return without doing anything. */
}
}
- if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
+ assert( SQLITE_AFF_NONE<SQLITE_AFF_BLOB );
+ if( sqlite3ExprAffinity(pColumn)<=SQLITE_AFF_BLOB ){
pConst->bHasAffBlob = 1;
}
@@ -147767,7 +149756,8 @@ static int propagateConstantExprRewriteOne(
if( pColumn==pExpr ) continue;
if( pColumn->iTable!=pExpr->iTable ) continue;
if( pColumn->iColumn!=pExpr->iColumn ) continue;
- if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
+ assert( SQLITE_AFF_NONE<SQLITE_AFF_BLOB );
+ if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)<=SQLITE_AFF_BLOB ){
break;
}
/* A match is found. Add the EP_FixedCol property */
@@ -147957,7 +149947,8 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
**
** NAME AMBIGUITY
**
-** This optimization is called the "WHERE-clause push-down optimization".
+** This optimization is called the "WHERE-clause push-down optimization"
+** or sometimes the "predicate push-down optimization".
**
** Do not confuse this optimization with another unrelated optimization
** with a similar name: The "MySQL push-down optimization" causes WHERE
@@ -148221,10 +150212,10 @@ static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
if( pItem->fg.isCorrelated || pItem->fg.isCte ){
return 0;
}
- assert( pItem->pTab!=0 );
- pTab = pItem->pTab;
- assert( pItem->pSelect!=0 );
- pSub = pItem->pSelect;
+ assert( pItem->pSTab!=0 );
+ pTab = pItem->pSTab;
+ assert( pItem->fg.isSubquery );
+ pSub = pItem->u4.pSubq->pSelect;
assert( pSub->pEList->nExpr==pTab->nCol );
for(pX=pSub; pX; pX=pX->pPrior){
if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
@@ -148353,13 +150344,13 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
if( p->pWhere
|| p->pEList->nExpr!=1
|| p->pSrc->nSrc!=1
- || p->pSrc->a[0].pSelect
+ || p->pSrc->a[0].fg.isSubquery
|| pAggInfo->nFunc!=1
|| p->pHaving
){
return 0;
}
- pTab = p->pSrc->a[0].pTab;
+ pTab = p->pSrc->a[0].pSTab;
assert( pTab!=0 );
assert( !IsView(pTab) );
if( !IsOrdinaryTable(pTab) ) return 0;
@@ -148384,7 +150375,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
** pFrom->pIndex and return SQLITE_OK.
*/
SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
- Table *pTab = pFrom->pTab;
+ Table *pTab = pFrom->pSTab;
char *zIndexedBy = pFrom->u1.zIndexedBy;
Index *pIdx;
assert( pTab!=0 );
@@ -148419,7 +150410,7 @@ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
** above that generates the code for a compound SELECT with an ORDER BY clause
** uses a merge algorithm that requires the same collating sequence on the
** result columns as on the ORDER BY clause. See ticket
-** http://www.sqlite.org/src/info/6709574d2a
+** http://sqlite.org/src/info/6709574d2a
**
** This transformation is only needed for EXCEPT, INTERSECT, and UNION.
** The UNION ALL operator works fine with multiSelectOrderBy() even when
@@ -148461,7 +150452,11 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
if( pNew==0 ) return WRC_Abort;
memset(&dummy, 0, sizeof(dummy));
pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0);
- if( pNewSrc==0 ) return WRC_Abort;
+ assert( pNewSrc!=0 || pParse->nErr );
+ if( pParse->nErr ){
+ sqlite3SrcListDelete(db, pNewSrc);
+ return WRC_Abort;
+ }
*pNew = *p;
p->pSrc = pNewSrc;
p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
@@ -148476,7 +150471,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
#ifndef SQLITE_OMIT_WINDOWFUNC
p->pWinDefn = 0;
#endif
- p->selFlags &= ~SF_Compound;
+ p->selFlags &= ~(u32)SF_Compound;
assert( (p->selFlags & SF_Converted)==0 );
p->selFlags |= SF_Converted;
assert( pNew->pPrior!=0 );
@@ -148516,7 +150511,7 @@ static struct Cte *searchWith(
){
const char *zName = pItem->zName;
With *p;
- assert( pItem->zDatabase==0 );
+ assert( pItem->fg.fixedSchema || pItem->u4.zDatabase==0 );
assert( zName!=0 );
for(p=pWith; p; p=p->pOuter){
int i;
@@ -148586,7 +150581,7 @@ static int resolveFromTermToCte(
Cte *pCte; /* Matched CTE (or NULL if no match) */
With *pWith; /* The matching WITH */
- assert( pFrom->pTab==0 );
+ assert( pFrom->pSTab==0 );
if( pParse->pWith==0 ){
/* There are no WITH clauses in the stack. No match is possible */
return 0;
@@ -148596,7 +150591,8 @@ static int resolveFromTermToCte(
** go no further. */
return 0;
}
- if( pFrom->zDatabase!=0 ){
+ assert( pFrom->fg.hadSchema==0 || pFrom->fg.notCte!=0 );
+ if( pFrom->fg.fixedSchema==0 && pFrom->u4.zDatabase!=0 ){
/* The FROM term contains a schema qualifier (ex: main.t1) and so
** it cannot possibly be a CTE reference. */
return 0;
@@ -148632,7 +150628,7 @@ static int resolveFromTermToCte(
}
if( cannotBeFunction(pParse, pFrom) ) return 2;
- assert( pFrom->pTab==0 );
+ assert( pFrom->pSTab==0 );
pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return 2;
pCteUse = pCte->pUse;
@@ -148646,26 +150642,29 @@ static int resolveFromTermToCte(
}
pCteUse->eM10d = pCte->eM10d;
}
- pFrom->pTab = pTab;
+ pFrom->pSTab = pTab;
pTab->nTabRef = 1;
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
pTab->iPKey = -1;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
- pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
+ sqlite3SrcItemAttachSubquery(pParse, pFrom, pCte->pSelect, 1);
if( db->mallocFailed ) return 2;
- pFrom->pSelect->selFlags |= SF_CopyCte;
- assert( pFrom->pSelect );
+ assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
+ pSel = pFrom->u4.pSubq->pSelect;
+ assert( pSel!=0 );
+ pSel->selFlags |= SF_CopyCte;
if( pFrom->fg.isIndexedBy ){
sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy);
return 2;
}
+ assert( !pFrom->fg.isIndexedBy );
pFrom->fg.isCte = 1;
pFrom->u2.pCteUse = pCteUse;
pCteUse->nUse++;
/* Check if this is a recursive CTE. */
- pRecTerm = pSel = pFrom->pSelect;
+ pRecTerm = pSel;
bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
while( bMayRecursive && pRecTerm->op==pSel->op ){
int i;
@@ -148673,11 +150672,13 @@ static int resolveFromTermToCte(
assert( pRecTerm->pPrior!=0 );
for(i=0; i<pSrc->nSrc; i++){
SrcItem *pItem = &pSrc->a[i];
- if( pItem->zDatabase==0
- && pItem->zName!=0
+ if( pItem->zName!=0
+ && !pItem->fg.hadSchema
+ && ALWAYS( !pItem->fg.isSubquery )
+ && (pItem->fg.fixedSchema || pItem->u4.zDatabase==0)
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName)
){
- pItem->pTab = pTab;
+ pItem->pSTab = pTab;
pTab->nTabRef++;
pItem->fg.isRecursive = 1;
if( pRecTerm->selFlags & SF_Recursive ){
@@ -148779,11 +150780,14 @@ SQLITE_PRIVATE void sqlite3SelectPopWith(Walker *pWalker, Select *p){
** SQLITE_NOMEM.
*/
SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
- Select *pSel = pFrom->pSelect;
+ Select *pSel;
Table *pTab;
+ assert( pFrom->fg.isSubquery );
+ assert( pFrom->u4.pSubq!=0 );
+ pSel = pFrom->u4.pSubq->pSelect;
assert( pSel );
- pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
+ pFrom->pSTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
if( pTab==0 ) return SQLITE_NOMEM;
pTab->nTabRef = 1;
if( pFrom->zAlias ){
@@ -148883,7 +150887,7 @@ static int selectExpander(Walker *pWalker, Select *p){
pEList = p->pEList;
if( pParse->pWith && (p->selFlags & SF_View) ){
if( p->pWith==0 ){
- p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With));
+ p->pWith = (With*)sqlite3DbMallocZero(db, SZ_WITH(1) );
if( p->pWith==0 ){
return WRC_Abort;
}
@@ -148903,33 +150907,35 @@ 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->pTab ) continue;
+ assert( pFrom->fg.isRecursive==0 || pFrom->pSTab!=0 );
+ if( pFrom->pSTab ) continue;
assert( pFrom->fg.isRecursive==0 );
if( pFrom->zName==0 ){
#ifndef SQLITE_OMIT_SUBQUERY
- Select *pSel = pFrom->pSelect;
+ Select *pSel;
+ assert( pFrom->fg.isSubquery && pFrom->u4.pSubq!=0 );
+ pSel = pFrom->u4.pSubq->pSelect;
/* A sub-query in the FROM clause of a SELECT */
assert( pSel!=0 );
- assert( pFrom->pTab==0 );
+ assert( pFrom->pSTab==0 );
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
#endif
#ifndef SQLITE_OMIT_CTE
}else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){
if( rc>1 ) return WRC_Abort;
- pTab = pFrom->pTab;
+ pTab = pFrom->pSTab;
assert( pTab!=0 );
#endif
}else{
/* An ordinary table or view name in the FROM clause */
- assert( pFrom->pTab==0 );
- pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
+ assert( pFrom->pSTab==0 );
+ pFrom->pSTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
if( pTab==0 ) return WRC_Abort;
if( pTab->nTabRef>=0xffff ){
sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
pTab->zName);
- pFrom->pTab = 0;
+ pFrom->pSTab = 0;
return WRC_Abort;
}
pTab->nTabRef++;
@@ -148941,7 +150947,7 @@ static int selectExpander(Walker *pWalker, Select *p){
i16 nCol;
u8 eCodeOrig = pWalker->eCode;
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
- assert( pFrom->pSelect==0 );
+ assert( pFrom->fg.isSubquery==0 );
if( IsView(pTab) ){
if( (db->flags & SQLITE_EnableView)==0
&& pTab->pSchema!=db->aDb[1].pSchema
@@ -148949,7 +150955,7 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
pTab->zName);
}
- pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0);
+ sqlite3SrcItemAttachSubquery(pParse, pFrom, pTab->u.view.pSelect, 1);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( ALWAYS(IsVirtual(pTab))
@@ -148965,7 +150971,9 @@ static int selectExpander(Walker *pWalker, Select *p){
nCol = pTab->nCol;
pTab->nCol = -1;
pWalker->eCode = 1; /* Turn on Select.selId renumbering */
- sqlite3WalkSelect(pWalker, pFrom->pSelect);
+ if( pFrom->fg.isSubquery ){
+ sqlite3WalkSelect(pWalker, pFrom->u4.pSubq->pSelect);
+ }
pWalker->eCode = eCodeOrig;
pTab->nCol = nCol;
}
@@ -149052,7 +151060,7 @@ static int selectExpander(Walker *pWalker, Select *p){
}
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
int nAdd; /* Number of cols including rowid */
- Table *pTab = pFrom->pTab; /* Table for this data source */
+ Table *pTab = pFrom->pSTab; /* Table for this data source */
ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
char *zTabName; /* AS name for this data source */
const char *zSchemaName = 0; /* Schema name for this data source */
@@ -149063,10 +151071,11 @@ static int selectExpander(Walker *pWalker, Select *p){
zTabName = pTab->zName;
}
if( db->mallocFailed ) break;
- assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) );
+ assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom) );
if( pFrom->fg.isNestedFrom ){
- assert( pFrom->pSelect!=0 );
- pNestedFrom = pFrom->pSelect->pEList;
+ assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
+ assert( pFrom->u4.pSubq->pSelect!=0 );
+ pNestedFrom = pFrom->u4.pSubq->pSelect->pEList;
assert( pNestedFrom!=0 );
assert( pNestedFrom->nExpr==pTab->nCol );
assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
@@ -149305,14 +151314,12 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
assert( (p->selFlags & SF_Resolved) );
pTabList = p->pSrc;
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
- Table *pTab = pFrom->pTab;
+ Table *pTab = pFrom->pSTab;
assert( pTab!=0 );
- if( (pTab->tabFlags & TF_Ephemeral)!=0 ){
+ if( (pTab->tabFlags & TF_Ephemeral)!=0 && pFrom->fg.isSubquery ){
/* A sub-query in the FROM clause of a SELECT */
- Select *pSel = pFrom->pSelect;
- if( pSel ){
- sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
- }
+ Select *pSel = pFrom->u4.pSubq->pSelect;
+ sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
}
}
}
@@ -149626,6 +151633,7 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
+ if( pParse->nErr ) return;
pList = pF->pFExpr->x.pList;
if( pF->iOBTab>=0 ){
/* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs
@@ -149666,7 +151674,7 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
}
sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, (u8)nArg);
+ sqlite3VdbeChangeP5(v, (u16)nArg);
sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, iTop);
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
@@ -149829,12 +151837,13 @@ static void updateAccumulator(
}
sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, (u8)nArg);
+ sqlite3VdbeChangeP5(v, (u16)nArg);
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
}
if( addrNext ){
sqlite3VdbeResolveLabel(v, addrNext);
}
+ if( pParse->nErr ) return;
}
if( regHit==0 && pAggInfo->nAccumulator ){
regHit = regAcc;
@@ -149844,6 +151853,7 @@ static void updateAccumulator(
}
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i));
+ if( pParse->nErr ) return;
}
pAggInfo->directMode = 0;
@@ -149959,25 +151969,28 @@ static SrcItem *isSelfJoinView(
int iFirst, int iEnd /* Range of FROM-clause entries to search. */
){
SrcItem *pItem;
- assert( pThis->pSelect!=0 );
- if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
+ Select *pSel;
+ assert( pThis->fg.isSubquery );
+ pSel = pThis->u4.pSubq->pSelect;
+ assert( pSel!=0 );
+ if( pSel->selFlags & SF_PushDown ) return 0;
while( iFirst<iEnd ){
Select *pS1;
pItem = &pTabList->a[iFirst++];
- if( pItem->pSelect==0 ) continue;
+ if( !pItem->fg.isSubquery ) 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;
+ assert( pItem->pSTab!=0 );
+ assert( pThis->pSTab!=0 );
+ if( pItem->pSTab->pSchema!=pThis->pSTab->pSchema ) continue;
if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
- pS1 = pItem->pSelect;
- if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){
+ pS1 = pItem->u4.pSubq->pSelect;
+ if( pItem->pSTab->pSchema==0 && pSel->selId!=pS1->selId ){
/* The query flattener left two different CTE tables with identical
** names in the same FROM clause. */
continue;
}
- if( pItem->pSelect->selFlags & SF_PushDown ){
+ if( pS1->selFlags & SF_PushDown ){
/* The view was modified by some other optimization such as
** pushDownWhereTerms() */
continue;
@@ -150013,6 +152026,7 @@ static void agginfoFree(sqlite3 *db, void *pArg){
** * 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.
+** * None of the subqueries are DISTINCT (forumpost/a860f5fb2e 2025-03-10)
**
** Return TRUE if the optimization is undertaken.
*/
@@ -150021,6 +152035,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
Expr *pExpr;
Expr *pCount;
sqlite3 *db;
+ SrcItem *pFrom;
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;
@@ -150035,17 +152050,22 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
- pSub = p->pSrc->a[0].pSelect;
- if( pSub==0 ) return 0; /* The FROM is a subquery */
+ pFrom = p->pSrc->a;
+ if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */
+ pSub = pFrom->u4.pSubq->pSelect;
if( pSub->pPrior==0 ) return 0; /* Must be a compound */
if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
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 */
+ if( pSub->selFlags & (SF_Aggregate|SF_Distinct) ){
+ testcase( pSub->selFlags & SF_Aggregate );
+ testcase( pSub->selFlags & SF_Distinct );
+ return 0; /* Not an aggregate nor DISTINCT */
+ }
assert( pSub->pHaving==0 ); /* Due to the previous */
- pSub = pSub->pPrior; /* Repeat over compound */
+ pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub );
/* If we reach this point then it is OK to perform the transformation */
@@ -150053,17 +152073,16 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
db = pParse->db;
pCount = pExpr;
pExpr = 0;
- pSub = p->pSrc->a[0].pSelect;
- p->pSrc->a[0].pSelect = 0;
+ pSub = sqlite3SubqueryDetach(db, pFrom);
sqlite3SrcListDelete(db, p->pSrc);
- p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
+ p->pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1);
while( pSub ){
Expr *pTerm;
pPrior = pSub->pPrior;
pSub->pPrior = 0;
pSub->pNext = 0;
pSub->selFlags |= SF_Aggregate;
- pSub->selFlags &= ~SF_Compound;
+ pSub->selFlags &= ~(u32)SF_Compound;
pSub->nSelectRow = 0;
sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList);
pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
@@ -150078,7 +152097,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
pSub = pPrior;
}
p->pEList->a[0].pExpr = pExpr;
- p->selFlags &= ~SF_Aggregate;
+ p->selFlags &= ~(u32)SF_Aggregate;
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x200 ){
@@ -150099,12 +152118,12 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
for(i=0; i<pSrc->nSrc; i++){
SrcItem *p1 = &pSrc->a[i];
if( p1==p0 ) continue;
- if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
+ if( p0->pSTab==p1->pSTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
return 1;
}
- if( p1->pSelect
- && (p1->pSelect->selFlags & SF_NestedFrom)!=0
- && sameSrcAlias(p0, p1->pSelect->pSrc)
+ if( p1->fg.isSubquery
+ && (p1->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0
+ && sameSrcAlias(p0, p1->u4.pSubq->pSelect->pSrc)
){
return 1;
}
@@ -150169,13 +152188,13 @@ static int fromClauseTermCanBeCoroutine(
if( i==0 ) break;
i--;
pItem--;
- if( pItem->pSelect!=0 ) return 0; /* (1c-i) */
+ if( pItem->fg.isSubquery ) return 0; /* (1c-i) */
}
return 1;
}
/*
-** Generate code for the SELECT statement given in the p argument.
+** Generate byte-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.
@@ -150186,6 +152205,40 @@ static int fromClauseTermCanBeCoroutine(
**
** This routine does NOT free the Select structure passed in. The
** calling function needs to do that.
+**
+** This is a long function. The following is an outline of the processing
+** steps, with tags referencing various milestones:
+**
+** * Resolve names and similar preparation tag-select-0100
+** * Scan of the FROM clause tag-select-0200
+** + OUTER JOIN strength reduction tag-select-0220
+** + Sub-query ORDER BY removal tag-select-0230
+** + Query flattening tag-select-0240
+** * Separate subroutine for compound-SELECT tag-select-0300
+** * WHERE-clause constant propagation tag-select-0330
+** * Count()-of-VIEW optimization tag-select-0350
+** * Scan of the FROM clause again tag-select-0400
+** + Authorize unreferenced tables tag-select-0410
+** + Predicate push-down optimization tag-select-0420
+** + Omit unused subquery columns optimization tag-select-0440
+** + Generate code to implement subqueries tag-select-0480
+** - Co-routines tag-select-0482
+** - Reuse previously computed CTE tag-select-0484
+** - REuse previously computed VIEW tag-select-0486
+** - Materialize a VIEW or CTE tag-select-0488
+** * DISTINCT ORDER BY -> GROUP BY optimization tag-select-0500
+** * Set up for ORDER BY tag-select-0600
+** * Create output table tag-select-0630
+** * Prepare registers for LIMIT tag-select-0650
+** * Setup for DISTINCT tag-select-0680
+** * Generate code for non-aggregate and non-GROUP BY tag-select-0700
+** * Generate code for aggregate and/or GROUP BY tag-select-0800
+** + GROUP BY queries tag-select-0810
+** + non-GROUP BY queries tag-select-0820
+** - Special case of count() w/o GROUP BY tag-select-0821
+** - General case of non-GROUP BY aggregates tag-select-0822
+** * Sort results, as needed tag-select-0900
+** * Internal self-checks tag-select-1000
*/
SQLITE_PRIVATE int sqlite3Select(
Parse *pParse, /* The parser context */
@@ -150229,6 +152282,7 @@ SQLITE_PRIVATE int sqlite3Select(
}
#endif
+ /* tag-select-0100 */
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
@@ -150250,7 +152304,7 @@ SQLITE_PRIVATE int sqlite3Select(
testcase( pParse->earlyCleanup );
p->pOrderBy = 0;
}
- p->selFlags &= ~SF_Distinct;
+ p->selFlags &= ~(u32)SF_Distinct;
p->selFlags |= SF_NoopOrderBy;
}
sqlite3SelectPrep(pParse, p, 0);
@@ -150280,7 +152334,7 @@ SQLITE_PRIVATE int sqlite3Select(
if( sameSrcAlias(p0, p->pSrc) ){
sqlite3ErrorMsg(pParse,
"target object/alias may not appear in FROM clause: %s",
- p0->zAlias ? p0->zAlias : p0->pTab->zName
+ p0->zAlias ? p0->zAlias : p0->pSTab->zName
);
goto select_end;
}
@@ -150289,7 +152343,7 @@ SQLITE_PRIVATE int sqlite3Select(
** and leaving this flag set can cause errors if a compound sub-query
** in p->pSrc is flattened into this query and this function called
** again as part of compound SELECT processing. */
- p->selFlags &= ~SF_UFSrcCheck;
+ p->selFlags &= ~(u32)SF_UFSrcCheck;
}
if( pDest->eDest==SRT_Output ){
@@ -150315,12 +152369,13 @@ SQLITE_PRIVATE int sqlite3Select(
/* Try to do various optimizations (flattening subqueries, and strength
** reduction of join operators) in the FROM clause up into the main query
+ ** tag-select-0200
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
SrcItem *pItem = &pTabList->a[i];
- Select *pSub = pItem->pSelect;
- Table *pTab = pItem->pTab;
+ Select *pSub = pItem->fg.isSubquery ? pItem->u4.pSubq->pSelect : 0;
+ Table *pTab = pItem->pSTab;
/* The expander should have already created transient Table objects
** even for FROM clause elements such as subqueries that do not correspond
@@ -150337,6 +152392,7 @@ SQLITE_PRIVATE int sqlite3Select(
** way that the i-th table cannot be the NULL row of a join, then
** perform the appropriate simplification. This is called
** "OUTER JOIN strength reduction" in the SQLite documentation.
+ ** tag-select-0220
*/
if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
&& sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor,
@@ -150407,7 +152463,8 @@ SQLITE_PRIVATE int sqlite3Select(
if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
assert( pSub->pGroupBy==0 );
- /* If a FROM-clause subquery has an ORDER BY clause that is not
+ /* tag-select-0230:
+ ** If a FROM-clause subquery has an ORDER BY clause that is not
** really doing anything, then delete it now so that it does not
** interfere with query flattening. See the discussion at
** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a
@@ -150426,13 +152483,16 @@ SQLITE_PRIVATE int sqlite3Select(
** (a) The outer query has a different ORDER BY clause
** (b) The subquery is part of a join
** See forum post 062d576715d277c8
+ ** (6) The subquery is not a recursive CTE. ORDER BY has a different
+ ** meaning for recursive CTEs and this optimization does not
+ ** apply.
**
** Also retain the ORDER BY if the OmitOrderBy optimization is disabled.
*/
if( pSub->pOrderBy!=0
&& (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */
&& pSub->pLimit==0 /* Condition (1) */
- && (pSub->selFlags & SF_OrderByReqd)==0 /* Condition (2) */
+ && (pSub->selFlags & (SF_OrderByReqd|SF_Recursive))==0 /* (2) and (6) */
&& (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */
&& OptimizationEnabled(db, SQLITE_OmitOrderBy)
){
@@ -150470,6 +152530,7 @@ SQLITE_PRIVATE int sqlite3Select(
continue;
}
+ /* tag-select-0240 */
if( flattenSubquery(pParse, p, i, isAgg) ){
if( pParse->nErr ) goto select_end;
/* This subquery can be absorbed into its parent. */
@@ -150485,7 +152546,7 @@ SQLITE_PRIVATE int sqlite3Select(
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/* Handle compound SELECT statements using the separate multiSelect()
- ** procedure.
+ ** procedure. tag-select-0300
*/
if( p->pPrior ){
rc = multiSelect(pParse, p, pDest);
@@ -150501,9 +152562,9 @@ SQLITE_PRIVATE int sqlite3Select(
#endif
/* Do the WHERE-clause constant propagation optimization if this is
- ** a join. No need to speed time on this operation for non-join queries
+ ** a join. No need to spend time on this operation for non-join queries
** as the equivalent optimization will be handled by query planner in
- ** sqlite3WhereBegin().
+ ** sqlite3WhereBegin(). tag-select-0330
*/
if( p->pWhere!=0
&& p->pWhere->op==TK_AND
@@ -150520,6 +152581,7 @@ SQLITE_PRIVATE int sqlite3Select(
TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
}
+ /* tag-select-0350 */
if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
&& countOfViewOptimization(pParse, p)
){
@@ -150527,20 +152589,26 @@ SQLITE_PRIVATE int sqlite3Select(
pTabList = p->pSrc;
}
- /* For each term in the FROM clause, do two things:
- ** (1) Authorized unreferenced tables
- ** (2) Generate code for all sub-queries
+ /* Loop over all terms in the FROM clause and do two things for each term:
+ **
+ ** (1) Authorize unreferenced tables
+ ** (2) Generate code for all sub-queries
+ **
+ ** tag-select-0400
*/
for(i=0; i<pTabList->nSrc; i++){
SrcItem *pItem = &pTabList->a[i];
SrcItem *pPrior;
SelectDest dest;
+ Subquery *pSubq;
Select *pSub;
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
const char *zSavedAuthContext;
#endif
- /* Issue SQLITE_READ authorizations with a fake column name for any
+ /* Authorized unreferenced tables. tag-select-0410
+ **
+ ** 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:
@@ -150557,17 +152625,28 @@ SQLITE_PRIVATE int sqlite3Select(
** string for the fake column name seems safer.
*/
if( pItem->colUsed==0 && pItem->zName!=0 ){
- sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
+ const char *zDb;
+ if( pItem->fg.fixedSchema ){
+ int iDb = sqlite3SchemaToIndex(pParse->db, pItem->u4.pSchema);
+ zDb = db->aDb[iDb].zDbSName;
+ }else if( pItem->fg.isSubquery ){
+ zDb = 0;
+ }else{
+ zDb = pItem->u4.zDatabase;
+ }
+ sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", zDb);
}
#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 || pItem->addrFillSub!=0 ) continue;
+ if( pItem->fg.isSubquery==0 ) continue;
+ pSubq = pItem->u4.pSubq;
+ assert( pSubq!=0 );
+ pSub = pSubq->pSelect;
/* The code for a subquery should only be generated once. */
- assert( pItem->addrFillSub==0 );
+ if( pSubq->addrFillSub!=0 ) continue;
/* Increment Parse.nHeight by the height of the largest expression
** tree referred to by this, the parent select. The child select
@@ -150580,6 +152659,7 @@ 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.
+ ** This is the "predicate push-down optimization". tag-select-0420
*/
if( OptimizationEnabled(db, SQLITE_PushDown)
&& (pItem->fg.isCte==0
@@ -150593,13 +152673,14 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3TreeViewSelect(0, p, 0);
}
#endif
- assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 );
+ assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 );
}else{
- TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
+ TREETRACE(0x4000,pParse,p,("WHERE-clause push-down not possible\n"));
}
/* Convert unused result columns of the subquery into simple NULL
** expressions, to avoid unneeded searching and computation.
+ ** tag-select-0440
*/
if( OptimizationEnabled(db, SQLITE_NullUnusedCols)
&& disableUnusedSubqueryResultColumns(pItem)
@@ -150617,32 +152698,33 @@ SQLITE_PRIVATE int sqlite3Select(
zSavedAuthContext = pParse->zAuthContext;
pParse->zAuthContext = pItem->zName;
- /* Generate code to implement the subquery
+ /* Generate byte-code to implement the subquery tag-select-0480
*/
if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){
/* Implement a co-routine that will return a single row of the result
- ** set on each invocation.
+ ** set on each invocation. tag-select-0482
*/
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
- pItem->regReturn = ++pParse->nMem;
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
+ pSubq->regReturn = ++pParse->nMem;
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, pSubq->regReturn, 0, addrTop);
VdbeComment((v, "%!S", pItem));
- pItem->addrFillSub = addrTop;
- sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
+ pSubq->addrFillSub = addrTop;
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem));
sqlite3Select(pParse, pSub, &dest);
- pItem->pTab->nRowLogEst = pSub->nSelectRow;
+ pItem->pSTab->nRowLogEst = pSub->nSelectRow;
pItem->fg.viaCoroutine = 1;
- pItem->regResult = dest.iSdst;
- sqlite3VdbeEndCoroutine(v, pItem->regReturn);
+ pSubq->regResult = dest.iSdst;
+ sqlite3VdbeEndCoroutine(v, pSubq->regReturn);
+ VdbeComment((v, "end %!S", pItem));
sqlite3VdbeJumpHere(v, addrTop-1);
sqlite3ClearTempRegCache(pParse);
}else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
/* This is a CTE for which materialization code has already been
** generated. Invoke the subroutine to compute the materialization,
- ** the make the pItem->iCursor be a copy of the ephemeral table that
- ** holds the result of the materialization. */
+ ** then make the pItem->iCursor be a copy of the ephemeral table that
+ ** holds the result of the materialization. tag-select-0484 */
CteUse *pCteUse = pItem->u2.pCteUse;
sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
if( pItem->iCursor!=pCteUse->iCur ){
@@ -150652,25 +152734,30 @@ SQLITE_PRIVATE int sqlite3Select(
pSub->nSelectRow = pCteUse->nRowEst;
}else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
/* This view has already been materialized by a prior entry in
- ** this same FROM clause. Reuse it. */
- if( pPrior->addrFillSub ){
- sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
+ ** this same FROM clause. Reuse it. tag-select-0486 */
+ Subquery *pPriorSubq;
+ assert( pPrior->fg.isSubquery );
+ pPriorSubq = pPrior->u4.pSubq;
+ assert( pPriorSubq!=0 );
+ if( pPriorSubq->addrFillSub ){
+ sqlite3VdbeAddOp2(v, OP_Gosub, pPriorSubq->regReturn,
+ pPriorSubq->addrFillSub);
}
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
- pSub->nSelectRow = pPrior->pSelect->nSelectRow;
+ pSub->nSelectRow = pPriorSubq->pSelect->nSelectRow;
}else{
/* Materialize the view. If the view is not correlated, generate a
** subroutine to do the materialization so that subsequent uses of
- ** the same view can reuse the materialization. */
+ ** the same view can reuse the materialization. tag-select-0488 */
int topAddr;
int onceAddr = 0;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
int addrExplain;
#endif
- pItem->regReturn = ++pParse->nMem;
+ pSubq->regReturn = ++pParse->nMem;
topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
- pItem->addrFillSub = topAddr+1;
+ pSubq->addrFillSub = topAddr+1;
pItem->fg.isMaterialized = 1;
if( pItem->fg.isCorrelated==0 ){
/* If the subquery is not correlated and if we are not inside of
@@ -150685,17 +152772,17 @@ SQLITE_PRIVATE int sqlite3Select(
ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
sqlite3Select(pParse, pSub, &dest);
- pItem->pTab->nRowLogEst = pSub->nSelectRow;
+ pItem->pSTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
- sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
+ sqlite3VdbeAddOp2(v, OP_Return, pSubq->regReturn, topAddr+1);
VdbeComment((v, "end %!S", pItem));
sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
sqlite3VdbeJumpHere(v, topAddr);
sqlite3ClearTempRegCache(pParse);
if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
CteUse *pCteUse = pItem->u2.pCteUse;
- pCteUse->addrM9e = pItem->addrFillSub;
- pCteUse->regRtn = pItem->regReturn;
+ pCteUse->addrM9e = pSubq->addrFillSub;
+ pCteUse->regRtn = pSubq->regReturn;
pCteUse->iCur = pItem->iCursor;
pCteUse->nRowEst = pSub->nSelectRow;
}
@@ -150721,7 +152808,9 @@ SQLITE_PRIVATE int sqlite3Select(
}
#endif
- /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
+ /* tag-select-0500
+ **
+ ** 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:
**
@@ -150738,12 +152827,18 @@ SQLITE_PRIVATE int sqlite3Select(
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
+ && OptimizationEnabled(db, SQLITE_GroupByOrder)
#ifndef SQLITE_OMIT_WINDOWFUNC
&& p->pWin==0
#endif
){
- p->selFlags &= ~SF_Distinct;
+ p->selFlags &= ~(u32)SF_Distinct;
pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
+ if( pGroupBy ){
+ for(i=0; i<pGroupBy->nExpr; i++){
+ pGroupBy->a[i].u.x.iOrderByCol = i+1;
+ }
+ }
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
@@ -150765,7 +152860,7 @@ SQLITE_PRIVATE int sqlite3Select(
** If that is the case, then the OP_OpenEphemeral instruction will be
** changed to an OP_Noop once we figure out that the sorting index is
** not needed. The sSort.addrSortIndex variable is used to facilitate
- ** that change.
+ ** that change. tag-select-0600
*/
if( sSort.pOrderBy ){
KeyInfo *pKeyInfo;
@@ -150782,6 +152877,7 @@ SQLITE_PRIVATE int sqlite3Select(
}
/* If the output is destined for a temporary table, open that table.
+ ** tag-select-0630
*/
if( pDest->eDest==SRT_EphemTab ){
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr);
@@ -150799,7 +152895,7 @@ SQLITE_PRIVATE int sqlite3Select(
}
}
- /* Set the limiter.
+ /* Set the limiter. tag-select-0650
*/
iEnd = sqlite3VdbeMakeLabel(pParse);
if( (p->selFlags & SF_FixedLimit)==0 ){
@@ -150811,7 +152907,7 @@ SQLITE_PRIVATE int sqlite3Select(
sSort.sortFlags |= SORTFLAG_UseSorter;
}
- /* Open an ephemeral index to use for the distinct set.
+ /* Open an ephemeral index to use for the distinct set. tag-select-0680
*/
if( p->selFlags & SF_Distinct ){
sDistinct.tabTnct = pParse->nTab++;
@@ -150826,7 +152922,7 @@ SQLITE_PRIVATE int sqlite3Select(
}
if( !isAgg && pGroupBy==0 ){
- /* No aggregate functions and no GROUP BY clause */
+ /* No aggregate functions and no GROUP BY clause. tag-select-0700 */
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
| (p->selFlags & SF_FixedLimit);
#ifndef SQLITE_OMIT_WINDOWFUNC
@@ -150845,6 +152941,12 @@ SQLITE_PRIVATE int sqlite3Select(
if( pWInfo==0 ) goto select_end;
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
+ if( pDest->eDest<=SRT_DistQueue && pDest->eDest>=SRT_DistFifo ){
+ /* TUNING: For a UNION CTE, because UNION is implies DISTINCT,
+ ** reduce the estimated output row count by 8 (LogEst 30).
+ ** Search for tag-20250414a to see other cases */
+ p->nSelectRow -= 30;
+ }
}
if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
@@ -150899,8 +153001,8 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3WhereEnd(pWInfo);
}
}else{
- /* This case when there exist aggregate functions or a GROUP BY clause
- ** or both */
+ /* This case is for when there exist aggregate functions or a GROUP BY
+ ** clause or both. tag-select-0800 */
NameContext sNC; /* Name context for processing aggregate information */
int iAMem; /* First Mem address for storing current GROUP BY */
int iBMem; /* First Mem address for previous GROUP BY */
@@ -151019,7 +153121,7 @@ SQLITE_PRIVATE int sqlite3Select(
/* Processing for aggregates with GROUP BY is very different and
- ** much more complex than aggregates without a GROUP BY.
+ ** much more complex than aggregates without a GROUP BY. tag-select-0810
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
@@ -151206,12 +153308,29 @@ SQLITE_PRIVATE int sqlite3Select(
sortOut, sortPTab);
}
for(j=0; j<pGroupBy->nExpr; j++){
+ int iOrderByCol = pGroupBy->a[j].u.x.iOrderByCol;
+
if( groupBySort ){
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
}else{
pAggInfo->directMode = 1;
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
}
+
+ if( iOrderByCol ){
+ Expr *pX = p->pEList->a[iOrderByCol-1].pExpr;
+ Expr *pBase = sqlite3ExprSkipCollateAndLikely(pX);
+ while( ALWAYS(pBase!=0) && pBase->op==TK_IF_NULL_ROW ){
+ pX = pBase->pLeft;
+ pBase = sqlite3ExprSkipCollateAndLikely(pX);
+ }
+ if( ALWAYS(pBase!=0)
+ && pBase->op!=TK_AGG_COLUMN
+ && pBase->op!=TK_REGISTER
+ ){
+ sqlite3ExprToRegister(pX, iAMem+j);
+ }
+ }
}
sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
(char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
@@ -151227,9 +153346,9 @@ SQLITE_PRIVATE int sqlite3Select(
** and resets the aggregate accumulator registers in preparation
** for the next GROUP BY batch.
*/
- sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr);
sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow);
VdbeComment((v, "output one row"));
+ sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr);
sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeCoverage(v);
VdbeComment((v, "check abort flag"));
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
@@ -151303,9 +153422,12 @@ SQLITE_PRIVATE int sqlite3Select(
}
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
else {
+ /* Aggregate functions without GROUP BY. tag-select-0820 */
Table *pTab;
if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
- /* If isSimpleCount() returns a pointer to a Table structure, then
+ /* tag-select-0821
+ **
+ ** If isSimpleCount() returns a pointer to a Table structure, then
** the SQL statement is of the form:
**
** SELECT count(*) FROM <tbl>
@@ -151364,6 +153486,8 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
explainSimpleCount(pParse, pTab, pBest);
}else{
+ /* The general case of an aggregate query without GROUP BY
+ ** tag-select-0822 */
int regAcc = 0; /* "populate accumulators" flag */
ExprList *pDistinct = 0;
u16 distFlag = 0;
@@ -151452,7 +153576,7 @@ SQLITE_PRIVATE int sqlite3Select(
}
/* If there is an ORDER BY clause, then we need to sort the results
- ** and send them to the callback one by one.
+ ** and send them to the callback one by one. tag-select-0900
*/
if( sSort.pOrderBy ){
assert( p->pEList==pEList );
@@ -151475,6 +153599,7 @@ select_end:
assert( db->mallocFailed==0 || pParse->nErr!=0 );
sqlite3ExprListDelete(db, pMinMaxOrderBy);
#ifdef SQLITE_DEBUG
+ /* Internal self-checks. tag-select-1000 */
if( pAggInfo && !db->mallocFailed ){
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x20 ){
@@ -151782,7 +153907,8 @@ SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
assert( pParse->db->pVtabCtx==0 );
#endif
assert( pParse->bReturning );
- assert( &(pParse->u1.pReturning->retTrig) == pTrig );
+ assert( !pParse->isCreate );
+ assert( &(pParse->u1.d.pReturning->retTrig) == pTrig );
pTrig->table = pTab->zName;
pTrig->pTabSchema = pTab->pSchema;
pTrig->pNext = pList;
@@ -151864,8 +153990,10 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
** name on pTableName if we are reparsing out of the schema table
*/
if( db->init.busy && iDb!=1 ){
- sqlite3DbFree(db, pTableName->a[0].zDatabase);
- pTableName->a[0].zDatabase = 0;
+ assert( pTableName->a[0].fg.fixedSchema==0 );
+ assert( pTableName->a[0].fg.isSubquery==0 );
+ sqlite3DbFree(db, pTableName->a[0].u4.zDatabase);
+ pTableName->a[0].u4.zDatabase = 0;
}
/* If the trigger name was unqualified, and the table is a temp table,
@@ -152343,7 +154471,8 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr)
}
assert( pName->nSrc==1 );
- zDb = pName->a[0].zDatabase;
+ assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 );
+ zDb = pName->a[0].u4.zDatabase;
zName = pName->a[0].zName;
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
@@ -152580,7 +154709,9 @@ SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(
Schema *pSchema = pStep->pTrig->pSchema;
pSrc->a[0].zName = zName;
if( pSchema!=db->aDb[1].pSchema ){
- pSrc->a[0].pSchema = pSchema;
+ assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 );
+ pSrc->a[0].u4.pSchema = pSchema;
+ pSrc->a[0].fg.fixedSchema = 1;
}
if( pStep->pFrom ){
SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
@@ -152693,7 +154824,7 @@ static int sqlite3ReturningSubqueryCorrelated(Walker *pWalker, Select *pSelect){
pSrc = pSelect->pSrc;
assert( pSrc!=0 );
for(i=0; i<pSrc->nSrc; i++){
- if( pSrc->a[i].pTab==pWalker->u.pTab ){
+ if( pSrc->a[i].pSTab==pWalker->u.pTab ){
testcase( pSelect->selFlags & SF_Correlated );
pSelect->selFlags |= SF_Correlated;
pWalker->eCode = 1;
@@ -152745,7 +154876,8 @@ static void codeReturningTrigger(
ExprList *pNew;
Returning *pReturning;
Select sSelect;
- SrcList sFrom;
+ SrcList *pFrom;
+ u8 fromSpace[SZ_SRCLIST_1];
assert( v!=0 );
if( !pParse->bReturning ){
@@ -152754,19 +154886,21 @@ static void codeReturningTrigger(
return;
}
assert( db->pParse==pParse );
- pReturning = pParse->u1.pReturning;
+ assert( !pParse->isCreate );
+ pReturning = pParse->u1.d.pReturning;
if( pTrigger != &(pReturning->retTrig) ){
/* This RETURNING trigger is for a different statement */
return;
}
memset(&sSelect, 0, sizeof(sSelect));
- memset(&sFrom, 0, sizeof(sFrom));
+ pFrom = (SrcList*)fromSpace;
+ memset(pFrom, 0, SZ_SRCLIST_1);
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
- sSelect.pSrc = &sFrom;
- sFrom.nSrc = 1;
- sFrom.a[0].pTab = pTab;
- sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
- sFrom.a[0].iCursor = -1;
+ sSelect.pSrc = pFrom;
+ pFrom->nSrc = 1;
+ pFrom->a[0].pSTab = pTab;
+ pFrom->a[0].zName = pTab->zName; /* tag-20240424-1 */
+ pFrom->a[0].iCursor = -1;
sqlite3SelectPrep(pParse, &sSelect, 0);
if( pParse->nErr==0 ){
assert( db->mallocFailed==0 );
@@ -152984,6 +155118,8 @@ static TriggerPrg *codeRowTrigger(
sSubParse.eTriggerOp = pTrigger->op;
sSubParse.nQueryLoop = pParse->nQueryLoop;
sSubParse.prepFlags = pParse->prepFlags;
+ sSubParse.oldmask = 0;
+ sSubParse.newmask = 0;
v = sqlite3GetVdbe(&sSubParse);
if( v ){
@@ -153116,7 +155252,7 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
** invocation is disallowed if (a) the sub-program is really a trigger,
** not a foreign key action, and (b) the flag to enable recursive triggers
** is clear. */
- sqlite3VdbeChangeP5(v, (u8)bRecursive);
+ sqlite3VdbeChangeP5(v, (u16)bRecursive);
}
}
@@ -153475,7 +155611,7 @@ static void updateFromSelect(
Expr *pLimit2 = 0;
ExprList *pOrderBy2 = 0;
sqlite3 *db = pParse->db;
- Table *pTab = pTabList->a[0].pTab;
+ Table *pTab = pTabList->a[0].pSTab;
SrcList *pSrc;
Expr *pWhere2;
int eDest;
@@ -153499,8 +155635,8 @@ static void updateFromSelect(
if( pSrc ){
assert( pSrc->a[0].fg.notCte );
pSrc->a[0].iCursor = -1;
- pSrc->a[0].pTab->nTabRef--;
- pSrc->a[0].pTab = 0;
+ pSrc->a[0].pSTab->nTabRef--;
+ pSrc->a[0].pSTab = 0;
}
if( pPk ){
for(i=0; i<pPk->nKeyCol; i++){
@@ -153738,38 +155874,32 @@ SQLITE_PRIVATE void sqlite3Update(
*/
chngRowid = chngPk = 0;
for(i=0; i<pChanges->nExpr; i++){
- u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName);
/* 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( pTab->aCol[j].hName==hCol
- && sqlite3StrICmp(pTab->aCol[j].zCnName, 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;
- }
+ j = sqlite3ColumnIndex(pTab, pChanges->a[i].zEName);
+ if( j>=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].zCnName);
- goto update_cleanup;
- }
-#endif
- aXRef[j] = i;
- break;
+ 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].zCnName);
+ goto update_cleanup;
}
- }
- if( j>=pTab->nCol ){
+#endif
+ aXRef[j] = i;
+ }else{
if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){
j = -1;
chngRowid = 1;
@@ -154748,7 +156878,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
int nClause = 0; /* Counter of ON CONFLICT clauses */
assert( pTabList->nSrc==1 );
- assert( pTabList->a[0].pTab!=0 );
+ assert( pTabList->a[0].pSTab!=0 );
assert( pUpsert!=0 );
assert( pUpsert->pUpsertTarget!=0 );
@@ -154767,7 +156897,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
if( rc ) return rc;
/* Check to see if the conflict target matches the rowid. */
- pTab = pTabList->a[0].pTab;
+ pTab = pTabList->a[0].pSTab;
pTarget = pUpsert->pUpsertTarget;
iCursor = pTabList->a[0].iCursor;
if( HasRowid(pTab)
@@ -155092,7 +157222,7 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){
#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).
+ ** occurred on 2016-08-19 (https://sqlite.org/src/info/083f9e6270).
** The buggy behavior is required for binary compatibility with some
** legacy applications. */
iDb = sqlite3FindDb(pParse->db, pNm);
@@ -155138,6 +157268,9 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
const char *zDbMain; /* Schema name of database to vacuum */
const char *zOut; /* Name of output file */
u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
+ u64 iRandom; /* Random value used for zDbVacuum[] */
+ char zDbVacuum[42]; /* Name of the ATTACH-ed database used for vacuum */
+
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -155168,7 +157301,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_mTrace = db->mTrace;
- db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_Comments;
db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder
| SQLITE_Defensive | SQLITE_CountRows);
@@ -155178,27 +157311,29 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
pMain = db->aDb[iDb].pBt;
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
- /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
+ /* Attach the temporary database as 'vacuum_XXXXXX'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash
** occurs anyway. The integrity of the database is maintained by a
** (possibly synchronous) transaction opened on the main database before
** sqlite3BtreeCopyFile() is called.
**
** An optimization would be to use a non-journaled pager.
- ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
+ ** (Later:) I tried setting "PRAGMA vacuum_XXXXXX.journal_mode=OFF" but
** that actually made the VACUUM run slower. Very little journalling
** actually occurs when doing a vacuum since the vacuum_db is initially
** empty. Only the journal header is written. Apparently it takes more
** time to parse and run the PRAGMA to turn journalling off than it does
** to write the journal header file.
*/
+ sqlite3_randomness(sizeof(iRandom),&iRandom);
+ sqlite3_snprintf(sizeof(zDbVacuum), zDbVacuum, "vacuum_%016llx", iRandom);
nDb = db->nDb;
- rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
+ rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS %s", zOut, zDbVacuum);
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 );
+ assert( strcmp(pDb->zDbSName,zDbVacuum)==0 );
pTemp = pDb->pBt;
if( pOut ){
sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
@@ -155275,11 +157410,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
** the contents to the temporary database.
*/
rc = execSqlF(db, pzErrMsg,
- "SELECT'INSERT INTO vacuum_db.'||quote(name)"
+ "SELECT'INSERT INTO %s.'||quote(name)"
"||' SELECT*FROM\"%w\".'||quote(name)"
- "FROM vacuum_db.sqlite_schema "
+ "FROM %s.sqlite_schema "
"WHERE type='table'AND coalesce(rootpage,1)>0",
- zDbMain
+ zDbVacuum, zDbMain, zDbVacuum
);
assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
db->mDbFlags &= ~DBFLAG_Vacuum;
@@ -155291,11 +157426,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
** from the schema table.
*/
rc = execSqlF(db, pzErrMsg,
- "INSERT INTO vacuum_db.sqlite_schema"
+ "INSERT INTO %s.sqlite_schema"
" SELECT*FROM \"%w\".sqlite_schema"
" WHERE type IN('view','trigger')"
" OR(type='table'AND rootpage=0)",
- zDbMain
+ zDbVacuum, zDbMain
);
if( rc ) goto end_of_vacuum;
@@ -155871,11 +158006,12 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
** 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
+ ** The VM register number pParse->u1.cr.regRowid holds the rowid of an
** entry in the sqlite_schema table that was created for this vtab
** by sqlite3StartTable().
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( pParse->isCreate );
sqlite3NestedParse(pParse,
"UPDATE %Q." LEGACY_SCHEMA_TABLE " "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
@@ -155884,7 +158020,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
pTab->zName,
pTab->zName,
zStmt,
- pParse->regRowid
+ pParse->u1.cr.regRowid
);
v = sqlite3GetVdbe(pParse);
sqlite3ChangeCookie(pParse, iDb);
@@ -156222,7 +158358,9 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
z = (const unsigned char*)zCreateTable;
for(i=0; aKeyword[i]; i++){
int tokenType = 0;
- do{ z += sqlite3GetToken(z, &tokenType); }while( tokenType==TK_SPACE );
+ do{
+ z += sqlite3GetToken(z, &tokenType);
+ }while( tokenType==TK_SPACE || tokenType==TK_COMMENT );
if( tokenType!=aKeyword[i] ){
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "syntax error");
return SQLITE_ERROR;
@@ -156259,6 +158397,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
Table *pNew = sParse.pNewTable;
Index *pIdx;
pTab->aCol = pNew->aCol;
+ assert( IsOrdinaryTable(pNew) );
sqlite3ExprListDelete(db, pNew->u.tab.pDfltList);
pTab->nNVCol = pTab->nCol = pNew->nCol;
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
@@ -156933,11 +159072,13 @@ struct WhereLoop {
u16 nTop; /* Size of TOP vector */
u16 nDistinctCol; /* Index columns used to sort for DISTINCT */
Index *pIndex; /* Index used, or NULL */
+ ExprList *pOrderBy; /* ORDER BY clause if this is really a subquery */
} btree;
struct { /* Information for virtual tables */
int idxNum; /* Index number */
u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */
u32 bOmitOffset : 1; /* True to let virtual table handle offset */
+ u32 bIdxNumHex : 1; /* Show idxNum as hex in EXPLAIN QUERY PLAN */
i8 isOrdered; /* True if satisfies ORDER BY */
u16 omitMask; /* Terms that may be omitted */
char *idxStr; /* Index identifier string */
@@ -156950,6 +159091,10 @@ struct WhereLoop {
/**** whereLoopXfer() copies fields above ***********************/
# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot)
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
+#ifdef WHERETRACE_ENABLED
+ LogEst rStarDelta; /* Cost delta due to star-schema heuristic. Not
+ ** initialized unless pWInfo->bStarUsed */
+#endif
WhereTerm **aLTerm; /* WhereTerms used */
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */
@@ -156998,7 +159143,7 @@ struct WherePath {
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
LogEst nRow; /* Estimated number of rows generated by this path */
LogEst rCost; /* Total cost of this path */
- LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */
+ LogEst rUnsort; /* Total cost of this path ignoring sorting costs */
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
};
@@ -157271,8 +159416,13 @@ struct WhereInfo {
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) */
+ unsigned sorted :1; /* True if really sorted (not just grouped) */
+ unsigned bStarDone :1; /* True if check for star-query is complete */
+ unsigned bStarUsed :1; /* True if star-query heuristic is used */
LogEst nRowOut; /* Estimated number of output rows */
+#ifdef WHERETRACE_ENABLED
+ LogEst rTotalCost; /* Total cost of the solution */
+#endif
int iTop; /* The very beginning of the WHERE loop */
int iEndWhere; /* End of the WHERE clause itself */
WhereLoop *pLoops; /* List of all WhereLoop objects */
@@ -157280,10 +159430,15 @@ struct WhereInfo {
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
WhereClause sWC; /* Decomposition of the WHERE clause */
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
- WhereLevel a[1]; /* Information about each nest loop in WHERE */
+ WhereLevel a[FLEXARRAY]; /* Information about each nest loop in WHERE */
};
/*
+** The size (in bytes) of a WhereInfo object that holds N WhereLevels.
+*/
+#define SZ_WHEREINFO(N) ROUND8(offsetof(WhereInfo,a)+(N)*sizeof(WhereLevel))
+
+/*
** Private interfaces - callable only by other where.c routines.
**
** where.c:
@@ -157318,9 +159473,17 @@ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter(
const WhereInfo *pWInfo, /* WHERE clause */
const WhereLevel *pLevel /* Bloom filter on this level */
);
+SQLITE_PRIVATE void sqlite3WhereAddExplainText(
+ Parse *pParse, /* Parse context */
+ int addr,
+ SrcList *pTabList, /* Table list this loop refers to */
+ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
+ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
+);
#else
# define sqlite3WhereExplainOneScan(u,v,w,x) 0
# define sqlite3WhereExplainBloomFilter(u,v,w) 0
+# define sqlite3WhereAddExplainText(u,v,w,x,y)
#endif /* SQLITE_OMIT_EXPLAIN */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
@@ -157423,7 +159586,8 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */
- /* 0x02000000 -- available for reuse */
+#define WHERE_COROUTINE 0x02000000 /* Implemented by co-routine.
+ ** NB: False-negatives are possible */
#define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */
#endif /* !defined(SQLITE_WHEREINT_H) */
@@ -157521,38 +159685,38 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
}
/*
-** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
-** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
-** was 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.
-** Otherwise, if no OP_Explain is coded, zero is returned.
+** This function sets the P4 value of an existing OP_Explain opcode to
+** text describing the loop in pLevel. If the OP_Explain opcode already has
+** a P4 value, it is freed before it is overwritten.
*/
-SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
+SQLITE_PRIVATE void sqlite3WhereAddExplainText(
Parse *pParse, /* Parse context */
+ int addr, /* Address of OP_Explain opcode */
SrcList *pTabList, /* Table list this loop refers to */
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
){
- int ret = 0;
#if !defined(SQLITE_DEBUG)
if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
+ VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe, addr);
+
SrcItem *pItem = &pTabList->a[pLevel->iFrom];
- Vdbe *v = pParse->pVdbe; /* VM being constructed */
sqlite3 *db = pParse->db; /* Database handle */
int isSearch; /* True for a SEARCH. False for SCAN. */
WhereLoop *pLoop; /* The controlling WhereLoop object */
u32 flags; /* Flags that describe this loop */
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
char *zMsg; /* Text to add to EQP output */
+#endif
StrAccum str; /* EQP output string */
char zBuf[100]; /* Initial space for EQP output string */
+ if( db->mallocFailed ) return;
+
pLoop = pLevel->pWLoop;
flags = pLoop->wsFlags;
- if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0;
isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
|| ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
@@ -157568,7 +159732,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
assert( pLoop->u.btree.pIndex!=0 );
pIdx = pLoop->u.btree.pIndex;
assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
- if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
+ if( !HasRowid(pItem->pSTab) && IsPrimaryKeyIndex(pIdx) ){
if( isSearch ){
zFmt = "PRIMARY KEY";
}
@@ -157576,7 +159740,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
}else if( flags & WHERE_AUTO_INDEX ){
zFmt = "AUTOMATIC COVERING INDEX";
- }else if( flags & WHERE_IDX_ONLY ){
+ }else if( flags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){
zFmt = "COVERING INDEX %s";
}else{
zFmt = "INDEX %s";
@@ -157611,7 +159775,9 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
- sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s",
+ sqlite3_str_appendall(&str, " VIRTUAL TABLE INDEX ");
+ sqlite3_str_appendf(&str,
+ pLoop->u.vtab.bIdxNumHex ? "0x%x:%s" : "%d:%s",
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
}
#endif
@@ -157626,10 +159792,50 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
sqlite3_str_append(&str, " (~1 row)", 9);
}
#endif
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
zMsg = sqlite3StrAccumFinish(&str);
sqlite3ExplainBreakpoint("",zMsg);
- ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
- pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
+#endif
+
+ assert( pOp->opcode==OP_Explain );
+ assert( pOp->p4type==P4_DYNAMIC || pOp->p4.z==0 );
+ sqlite3DbFree(db, pOp->p4.z);
+ pOp->p4type = P4_DYNAMIC;
+ pOp->p4.z = sqlite3StrAccumFinish(&str);
+ }
+}
+
+
+/*
+** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
+** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
+** was 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.
+** Otherwise, if no OP_Explain is coded, zero is returned.
+*/
+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 */
+ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
+){
+ int ret = 0;
+#if !defined(SQLITE_DEBUG)
+ if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
+#endif
+ {
+ if( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0
+ && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
+ ){
+ Vdbe *v = pParse->pVdbe;
+ int addr = sqlite3VdbeCurrentAddr(v);
+ ret = sqlite3VdbeAddOp3(
+ v, OP_Explain, addr, pParse->addrExplain, pLevel->pWLoop->rRun
+ );
+ sqlite3WhereAddExplainText(pParse, addr, pTabList, pLevel, wctrlFlags);
+ }
}
return ret;
}
@@ -157664,7 +159870,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter(
sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
pLoop = pLevel->pWLoop;
if( pLoop->wsFlags & WHERE_IPK ){
- const Table *pTab = pItem->pTab;
+ const Table *pTab = pItem->pSTab;
if( pTab->iPKey>=0 ){
sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
}else{
@@ -157727,8 +159933,11 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
}
}else{
- int addr = pSrclist->a[pLvl->iFrom].addrFillSub;
- VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
+ int addr;
+ VdbeOp *pOp;
+ assert( pSrclist->a[pLvl->iFrom].fg.isSubquery );
+ addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub;
+ pOp = sqlite3VdbeGetOp(v, addr-1);
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
@@ -157871,11 +160080,44 @@ static void updateRangeAffinityStr(
}
}
+/*
+** The pOrderBy->a[].u.x.iOrderByCol values might be incorrect because
+** columns might have been rearranged in the result set. This routine
+** fixes them up.
+**
+** pEList is the new result set. The pEList->a[].u.x.iOrderByCol values
+** contain the *old* locations of each expression. This is a temporary
+** use of u.x.iOrderByCol, not its intended use. The caller must reset
+** u.x.iOrderByCol back to zero for all entries in pEList before the
+** caller returns.
+**
+** This routine changes pOrderBy->a[].u.x.iOrderByCol values from
+** pEList->a[N].u.x.iOrderByCol into N+1. (The "+1" is because of the 1-based
+** indexing used by iOrderByCol.) Or if no match, iOrderByCol is set to zero.
+*/
+static void adjustOrderByCol(ExprList *pOrderBy, ExprList *pEList){
+ int i, j;
+ if( pOrderBy==0 ) return;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ int t = pOrderBy->a[i].u.x.iOrderByCol;
+ if( t==0 ) continue;
+ for(j=0; j<pEList->nExpr; j++){
+ if( pEList->a[j].u.x.iOrderByCol==t ){
+ pOrderBy->a[i].u.x.iOrderByCol = j+1;
+ break;
+ }
+ }
+ if( j>=pEList->nExpr ){
+ pOrderBy->a[i].u.x.iOrderByCol = 0;
+ }
+ }
+}
+
/*
** 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
+** RHS. 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
@@ -157934,6 +160176,7 @@ static Expr *removeUnindexableInClauseTerms(
if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
pOrigRhs->a[iField].pExpr = 0;
+ if( pRhs ) pRhs->a[pRhs->nExpr-1].u.x.iOrderByCol = iField+1;
if( pOrigLhs ){
assert( pOrigLhs->a[iField].pExpr!=0 );
pLhs = sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr);
@@ -157947,6 +160190,7 @@ static Expr *removeUnindexableInClauseTerms(
pNew->pLeft->x.pList = pLhs;
}
pSelect->pEList = pRhs;
+ pSelect->selId = ++pParse->nSelect; /* Req'd for SubrtnSig validity */
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
@@ -157956,18 +160200,16 @@ static Expr *removeUnindexableInClauseTerms(
sqlite3ExprDelete(db, pNew->pLeft);
pNew->pLeft = p;
}
- 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 either the ORDER BY clause or the GROUP BY clause contains
+ ** references to result-set columns, those references might now be
+ ** obsolete. So fix them up.
+ */
+ assert( pRhs!=0 || db->mallocFailed );
+ if( pRhs ){
+ adjustOrderByCol(pSelect->pOrderBy, pRhs);
+ adjustOrderByCol(pSelect->pGroupBy, pRhs);
+ for(i=0; i<pRhs->nExpr; i++) pRhs->a[i].u.x.iOrderByCol = 0;
}
#if 0
@@ -157982,6 +160224,147 @@ static Expr *removeUnindexableInClauseTerms(
}
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
+** Generate code for a single X IN (....) term of the WHERE clause.
+**
+** This is a special-case of codeEqualityTerm() that works for IN operators
+** only. It is broken out into a subroutine because this case is
+** uncommon and by splitting it off into a subroutine, the common case
+** runs faster.
+**
+** The current value for the constraint is left in register iTarget.
+** This routine sets up a loop that will iterate over all values of X.
+*/
+static SQLITE_NOINLINE void codeINTerm(
+ Parse *pParse, /* The parsing context */
+ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
+ WhereLevel *pLevel, /* The level of the FROM clause we are working on */
+ int iEq, /* Index of the equality term within this level */
+ int bRev, /* True for reverse-order IN operations */
+ int iTarget /* Attempt to leave results in this register */
+){
+ Expr *pX = pTerm->pExpr;
+ int eType = IN_INDEX_NOOP;
+ int iTab;
+ struct InLoop *pIn;
+ WhereLoop *pLoop = pLevel->pWLoop;
+ Vdbe *v = pParse->pVdbe;
+ int i;
+ int nEq = 0;
+ int *aiMap = 0;
+
+ if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
+ && pLoop->u.btree.pIndex!=0
+ && pLoop->u.btree.pIndex->aSortOrder[iEq]
+ ){
+ testcase( iEq==0 );
+ testcase( bRev );
+ bRev = !bRev;
+ }
+ assert( pX->op==TK_IN );
+
+ for(i=0; i<iEq; i++){
+ if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
+ disableTerm(pLevel, pTerm);
+ return;
+ }
+ }
+ for(i=iEq;i<pLoop->nLTerm; i++){
+ assert( pLoop->aLTerm[i]!=0 );
+ if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
+ }
+
+ iTab = 0;
+ if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
+ }else{
+ Expr *pExpr = pTerm->pExpr;
+ if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
+ sqlite3 *db = pParse->db;
+ pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
+ if( !db->mallocFailed ){
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
+ pExpr->iTable = iTab;
+ }
+ sqlite3ExprDelete(db, pX);
+ }else{
+ int n = sqlite3ExprVectorSize(pX->pLeft);
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
+ }
+ pX = pExpr;
+ }
+
+ if( eType==IN_INDEX_INDEX_DESC ){
+ testcase( bRev );
+ bRev = !bRev;
+ }
+ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
+ VdbeCoverageIf(v, bRev);
+ VdbeCoverageIf(v, !bRev);
+
+ assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
+ pLoop->wsFlags |= WHERE_IN_ABLE;
+ if( pLevel->u.in.nIn==0 ){
+ pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse);
+ }
+ if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){
+ pLoop->wsFlags |= WHERE_IN_EARLYOUT;
+ }
+
+ i = pLevel->u.in.nIn;
+ pLevel->u.in.nIn += nEq;
+ pLevel->u.in.aInLoop =
+ sqlite3WhereRealloc(pTerm->pWC->pWInfo,
+ pLevel->u.in.aInLoop,
+ sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
+ pIn = pLevel->u.in.aInLoop;
+ if( pIn ){
+ int iMap = 0; /* Index in aiMap[] */
+ pIn += i;
+ for(i=iEq;i<pLoop->nLTerm; i++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ int iOut = iTarget + i - iEq;
+ if( eType==IN_INDEX_ROWID ){
+ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut);
+ }else{
+ int iCol = aiMap ? aiMap[iMap++] : 0;
+ pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
+ }
+ sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
+ if( i==iEq ){
+ pIn->iCur = iTab;
+ pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
+ if( iEq>0 ){
+ pIn->iBase = iTarget - i;
+ pIn->nPrefix = i;
+ }else{
+ pIn->nPrefix = 0;
+ }
+ }else{
+ pIn->eEndLoopOp = OP_Noop;
+ }
+ pIn++;
+ }
+ }
+ testcase( iEq>0
+ && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0
+ && (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 );
+ if( iEq>0
+ && (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0
+ ){
+ sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq);
+ }
+ }else{
+ pLevel->u.in.nIn = 0;
+ }
+ sqlite3DbFree(pParse->db, aiMap);
+}
+#endif
+
+
/*
** 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
@@ -158006,7 +160389,6 @@ static int codeEqualityTerm(
int iTarget /* Attempt to leave results in this register */
){
Expr *pX = pTerm->pExpr;
- Vdbe *v = pParse->pVdbe;
int iReg; /* Register holding results */
assert( pLevel->pWLoop->aLTerm[iEq]==pTerm );
@@ -158015,125 +160397,12 @@ static int codeEqualityTerm(
iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
}else if( pX->op==TK_ISNULL ){
iReg = iTarget;
- sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Null, 0, iReg);
#ifndef SQLITE_OMIT_SUBQUERY
}else{
- int eType = IN_INDEX_NOOP;
- int iTab;
- struct InLoop *pIn;
- WhereLoop *pLoop = pLevel->pWLoop;
- int i;
- int nEq = 0;
- int *aiMap = 0;
-
- if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
- && pLoop->u.btree.pIndex!=0
- && pLoop->u.btree.pIndex->aSortOrder[iEq]
- ){
- testcase( iEq==0 );
- testcase( bRev );
- bRev = !bRev;
- }
assert( pX->op==TK_IN );
iReg = iTarget;
-
- for(i=0; i<iEq; i++){
- if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
- disableTerm(pLevel, pTerm);
- return iTarget;
- }
- }
- for(i=iEq;i<pLoop->nLTerm; i++){
- assert( pLoop->aLTerm[i]!=0 );
- if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
- }
-
- iTab = 0;
- if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
- }else{
- Expr *pExpr = pTerm->pExpr;
- if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
- sqlite3 *db = pParse->db;
- pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
- if( !db->mallocFailed ){
- aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
- pExpr->iTable = iTab;
- }
- sqlite3ExprDelete(db, pX);
- }else{
- int n = sqlite3ExprVectorSize(pX->pLeft);
- aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
- }
- pX = pExpr;
- }
-
- if( eType==IN_INDEX_INDEX_DESC ){
- testcase( bRev );
- bRev = !bRev;
- }
- sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
- VdbeCoverageIf(v, bRev);
- VdbeCoverageIf(v, !bRev);
-
- assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
- pLoop->wsFlags |= WHERE_IN_ABLE;
- if( pLevel->u.in.nIn==0 ){
- pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse);
- }
- if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){
- pLoop->wsFlags |= WHERE_IN_EARLYOUT;
- }
-
- i = pLevel->u.in.nIn;
- pLevel->u.in.nIn += nEq;
- pLevel->u.in.aInLoop =
- sqlite3WhereRealloc(pTerm->pWC->pWInfo,
- pLevel->u.in.aInLoop,
- sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
- pIn = pLevel->u.in.aInLoop;
- if( pIn ){
- int iMap = 0; /* Index in aiMap[] */
- pIn += i;
- for(i=iEq;i<pLoop->nLTerm; i++){
- if( pLoop->aLTerm[i]->pExpr==pX ){
- int iOut = iReg + i - iEq;
- if( eType==IN_INDEX_ROWID ){
- pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut);
- }else{
- int iCol = aiMap ? aiMap[iMap++] : 0;
- pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
- }
- sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
- if( i==iEq ){
- pIn->iCur = iTab;
- pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
- if( iEq>0 ){
- pIn->iBase = iReg - i;
- pIn->nPrefix = i;
- }else{
- pIn->nPrefix = 0;
- }
- }else{
- pIn->eEndLoopOp = OP_Noop;
- }
- pIn++;
- }
- }
- testcase( iEq>0
- && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0
- && (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 );
- if( iEq>0
- && (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0
- ){
- sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq);
- }
- }else{
- pLevel->u.in.nIn = 0;
- }
- sqlite3DbFree(pParse->db, aiMap);
+ codeINTerm(pParse, pTerm, pLevel, iEq, bRev, iTarget);
#endif
}
@@ -158805,7 +161074,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
iCur = pTabItem->iCursor;
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
- VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
+ VdbeModuleComment((v, "Begin WHERE-loop%d: %s",
+ iLevel, pTabItem->pSTab->zName));
#if WHERETRACE_ENABLED /* 0x4001 */
if( sqlite3WhereTrace & 0x1 ){
sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
@@ -158860,11 +161130,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
/* 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);
+ int regYield;
+ Subquery *pSubq;
+ assert( pTabItem->fg.isSubquery && pTabItem->u4.pSubq!=0 );
+ pSubq = pTabItem->u4.pSubq;
+ regYield = pSubq->regReturn;
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->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->pSTab->zName));
pLevel->op = OP_Goto;
}else
@@ -158909,6 +161183,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
+ /* The instruction immediately prior to OP_VFilter must be an OP_Integer
+ ** that sets the "argc" value for xVFilter. This is necessary for
+ ** resolveP2() to work correctly. See tag-20250207a. */
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
pLoop->u.vtab.idxStr,
pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC);
@@ -159499,12 +161776,13 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( pLevel->iLeftJoin==0 ){
/* 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.
+ ** the partial index. This optimization does not work on an outer join,
+ ** as shown by:
**
- ** 2019-11-02 ticket 623eff57e76d45f6: This optimization does not work
- ** for a LEFT JOIN.
+ ** 2019-11-02 ticket 623eff57e76d45f6 (LEFT JOIN)
+ ** 2025-05-29 forum post 7dee41d32506c4ae (RIGHT JOIN)
*/
- if( pIdx->pPartIdxWhere ){
+ if( pIdx->pPartIdxWhere && pLevel->pRJ==0 ){
whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC);
}
}else{
@@ -159593,7 +161871,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int untestedTerms = 0; /* Some terms not completely tested */
int ii; /* Loop counter */
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
- Table *pTab = pTabItem->pTab;
+ Table *pTab = pTabItem->pSTab;
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
@@ -159611,8 +161889,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
- pOrTab = sqlite3DbMallocRawNN(db,
- sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
+ pOrTab = sqlite3DbMallocRawNN(db, SZ_SRCLIST(nNotReady+1));
if( pOrTab==0 ) return notReady;
pOrTab->nAlloc = (u8)(nNotReady + 1);
pOrTab->nSrc = pOrTab->nAlloc;
@@ -159663,7 +161940,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
**
** This optimization also only applies if the (x1 OR x2 OR ...) term
** is not contained in the ON clause of a LEFT JOIN.
- ** See ticket http://www.sqlite.org/src/info/f2369304e4
+ ** See ticket http://sqlite.org/src/info/f2369304e4
**
** 2022-02-04: Do not push down slices of a row-value comparison.
** In other words, "w" or "y" may not be a slice of a vector. Otherwise,
@@ -160052,7 +162329,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** least once. This is accomplished by storing the PK for the row in
** both the iMatch index and the regBloom Bloom filter.
*/
- pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab;
+ pTab = pWInfo->pTabList->a[pLevel->iFrom].pSTab;
if( HasRowid(pTab) ){
r = sqlite3GetTempRange(pParse, 2);
sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
@@ -160155,11 +162432,12 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
WhereInfo *pSubWInfo;
WhereLoop *pLoop = pLevel->pWLoop;
SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
- SrcList sFrom;
+ SrcList *pFrom;
+ u8 fromSpace[SZ_SRCLIST_1];
Bitmask mAll = 0;
int k;
- ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName));
+ ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName));
sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
pRJ->regReturn);
for(k=0; k<iLevel; k++){
@@ -160169,9 +162447,13 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom];
mAll |= pWInfo->a[k].pWLoop->maskSelf;
if( pRight->fg.viaCoroutine ){
+ Subquery *pSubq;
+ assert( pRight->fg.isSubquery && pRight->u4.pSubq!=0 );
+ pSubq = pRight->u4.pSubq;
+ assert( pSubq->pSelect!=0 && pSubq->pSelect->pEList!=0 );
sqlite3VdbeAddOp3(
- v, OP_Null, 0, pRight->regResult,
- pRight->regResult + pRight->pSelect->pEList->nExpr-1
+ v, OP_Null, 0, pSubq->regResult,
+ pSubq->regResult + pSubq->pSelect->pEList->nExpr-1
);
}
sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
@@ -160195,13 +162477,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
}
}
- sFrom.nSrc = 1;
- sFrom.nAlloc = 1;
- memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem));
- sFrom.a[0].fg.jointype = 0;
+ pFrom = (SrcList*)fromSpace;
+ pFrom->nSrc = 1;
+ pFrom->nAlloc = 1;
+ memcpy(&pFrom->a[0], pTabItem, sizeof(SrcItem));
+ pFrom->a[0].fg.jointype = 0;
assert( pParse->withinRJSubrtn < 100 );
pParse->withinRJSubrtn++;
- pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0,
+ pSubWInfo = sqlite3WhereBegin(pParse, pFrom, pSubWhere, 0, 0, 0,
WHERE_RIGHT_JOIN, 0);
if( pSubWInfo ){
int iCur = pLevel->iTabCur;
@@ -160209,7 +162492,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
int nPk;
int jmp;
int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
- Table *pTab = pTabItem->pTab;
+ Table *pTab = pTabItem->pSTab;
if( HasRowid(pTab) ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
nPk = 1;
@@ -160342,7 +162625,12 @@ static int allowedOp(int op){
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
assert( TK_GE==TK_EQ+4 );
- return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS;
+ assert( TK_IN<TK_EQ );
+ assert( TK_IS<TK_EQ );
+ assert( TK_ISNULL<TK_EQ );
+ if( op>TK_GE ) return 0;
+ if( op>=TK_EQ ) return 1;
+ return op==TK_IN || op==TK_ISNULL || op==TK_IS;
}
/*
@@ -160375,15 +162663,16 @@ static u16 exprCommute(Parse *pParse, Expr *pExpr){
static u16 operatorMask(int op){
u16 c;
assert( allowedOp(op) );
- if( op==TK_IN ){
+ if( op>=TK_EQ ){
+ assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff );
+ c = (u16)(WO_EQ<<(op-TK_EQ));
+ }else if( op==TK_IN ){
c = WO_IN;
}else if( op==TK_ISNULL ){
c = WO_ISNULL;
- }else if( op==TK_IS ){
- c = WO_IS;
}else{
- assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff );
- c = (u16)(WO_EQ<<(op-TK_EQ));
+ assert( op==TK_IS );
+ c = WO_IS;
}
assert( op!=TK_ISNULL || c==WO_ISNULL );
assert( op!=TK_IN || c==WO_IN );
@@ -160454,12 +162743,28 @@ static int isLikeOrGlob(
z = (u8*)pRight->u.zToken;
}
if( z ){
-
- /* Count the number of prefix characters prior to the first wildcard */
+ /* Count the number of prefix bytes prior to the first wildcard,
+ ** U+fffd character, or malformed utf-8. If the underlying database
+ ** has a UTF16LE encoding, then only consider ASCII characters. Note that
+ ** the encoding of z[] is UTF8 - we are dealing with only UTF8 here in this
+ ** code, but the database engine itself might be processing content using a
+ ** different encoding. */
cnt = 0;
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
cnt++;
- if( c==wc[3] && z[cnt]!=0 ) cnt++;
+ if( c==wc[3] && z[cnt]>0 && z[cnt]<0x80 ){
+ cnt++;
+ }else if( c>=0x80 ){
+ const u8 *z2 = z+cnt-1;
+ if( c==0xff || sqlite3Utf8Read(&z2)==0xfffd /* bad utf-8 */
+ || ENC(db)==SQLITE_UTF16LE
+ ){
+ cnt--;
+ break;
+ }else{
+ cnt = (int)(z2-z);
+ }
+ }
}
/* The optimization is possible only if (1) the pattern does not begin
@@ -160470,11 +162775,11 @@ static int isLikeOrGlob(
** 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>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
+ if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && ALWAYS(255!=(u8)z[cnt-1]) ){
Expr *pPrefix;
/* A "complete" match if the pattern ends with "*" or "%" */
- *pisComplete = c==wc[0] && z[cnt+1]==0;
+ *pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE;
/* Get the pattern prefix. Remove all escapes from the prefix. */
pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
@@ -160670,6 +162975,13 @@ static int isAuxiliaryVtabOperator(
}
}
}
+ }else if( pExpr->op>=TK_EQ ){
+ /* Comparison operators are a common case. Save a few comparisons for
+ ** that common case by terminating early. */
+ assert( TK_NE < TK_EQ );
+ assert( TK_ISNOT < TK_EQ );
+ assert( TK_NOTNULL < TK_EQ );
+ return 0;
}else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
int res = 0;
Expr *pLeft = pExpr->pLeft;
@@ -161143,30 +163455,42 @@ static void exprAnalyzeOrTerm(
** 1. The SQLITE_Transitive optimization must be enabled
** 2. Must be either an == or an IS operator
** 3. Not originating in the ON clause of an OUTER JOIN
-** 4. The affinities of A and B must be compatible
-** 5a. Both operands use the same collating sequence OR
-** 5b. The overall collating sequence is BINARY
+** 4. The operator is not IS or else the query does not contain RIGHT JOIN
+** 5. The affinities of A and B must be compatible
+** 6a. Both operands use the same collating sequence OR
+** 6b. The overall collating sequence is BINARY
** If this routine returns TRUE, that means that the RHS can be substituted
** for the LHS anyplace else in the WHERE clause where the LHS column occurs.
** This is an optimization. No harm comes from returning 0. But if 1 is
** returned when it should not be, then incorrect answers might result.
*/
-static int termIsEquivalence(Parse *pParse, Expr *pExpr){
+static int termIsEquivalence(Parse *pParse, Expr *pExpr, SrcList *pSrc){
char aff1, aff2;
CollSeq *pColl;
- if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
- if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
- if( ExprHasProperty(pExpr, EP_OuterON) ) return 0;
+ if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; /* (1) */
+ if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; /* (2) */
+ if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* (3) */
+ assert( pSrc!=0 );
+ if( pExpr->op==TK_IS
+ && pSrc->nSrc
+ && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0
+ ){
+ return 0; /* (4) */
+ }
aff1 = sqlite3ExprAffinity(pExpr->pLeft);
aff2 = sqlite3ExprAffinity(pExpr->pRight);
if( aff1!=aff2
&& (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2))
){
- return 0;
+ return 0; /* (5) */
}
pColl = sqlite3ExprCompareCollSeq(pParse, pExpr);
- if( sqlite3IsBinary(pColl) ) return 1;
- return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
+ if( !sqlite3IsBinary(pColl)
+ && !sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight)
+ ){
+ return 0; /* (6) */
+ }
+ return 1;
}
/*
@@ -161186,7 +163510,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
if( ALWAYS(pSrc!=0) ){
int i;
for(i=0; i<pSrc->nSrc; i++){
- mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
+ if( pSrc->a[i].fg.isSubquery ){
+ mask |= exprSelectUsage(pMaskSet, pSrc->a[i].u4.pSubq->pSelect);
+ }
if( pSrc->a[i].fg.isUsing==0 ){
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
}
@@ -161224,7 +163550,7 @@ static SQLITE_NOINLINE int exprMightBeIndexed2(
int iCur;
do{
iCur = pFrom->a[j].iCursor;
- for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ for(pIdx=pFrom->a[j].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr==0 ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
@@ -161268,7 +163594,7 @@ static int exprMightBeIndexed(
for(i=0; i<pFrom->nSrc; i++){
Index *pIdx;
- for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ for(pIdx=pFrom->a[i].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr ){
return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
}
@@ -161429,8 +163755,8 @@ static void exprAnalyze(
if( op==TK_IS ) pNew->wtFlags |= TERM_IS;
pTerm = &pWC->a[idxTerm];
pTerm->wtFlags |= TERM_COPIED;
-
- if( termIsEquivalence(pParse, pDup) ){
+ assert( pWInfo->pTabList!=0 );
+ if( termIsEquivalence(pParse, pDup, pWInfo->pTabList) ){
pTerm->eOperator |= WO_EQUIV;
eExtraOp = WO_EQUIV;
}
@@ -161596,9 +163922,8 @@ static void exprAnalyze(
}
if( !db->mallocFailed ){
- u8 c, *pC; /* Last character before the first wildcard */
+ u8 *pC; /* Last character before the first wildcard */
pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
- c = *pC;
if( noCase ){
/* The point is to increment the last character before the first
** wildcard. But if we increment '@', that will push it into the
@@ -161606,10 +163931,17 @@ static void exprAnalyze(
** inequality. To avoid this, make sure to also run the full
** LIKE on all candidate expressions by clearing the isComplete flag
*/
- if( c=='A'-1 ) isComplete = 0;
- c = sqlite3UpperToLower[c];
+ if( *pC=='A'-1 ) isComplete = 0;
+ *pC = sqlite3UpperToLower[*pC];
+ }
+
+ /* Increment the value of the last utf8 character in the prefix. */
+ while( *pC==0xBF && pC>(u8*)pStr2->u.zToken ){
+ *pC = 0x80;
+ pC--;
}
- *pC = c + 1;
+ assert( *pC!=0xFF ); /* isLikeOrGlob() guarantees this */
+ (*pC)++;
}
zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY;
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
@@ -161811,7 +164143,7 @@ static void whereAddLimitExpr(
Expr *pNew;
int iVal = 0;
- if( sqlite3ExprIsInteger(pExpr, &iVal) && iVal>=0 ){
+ if( sqlite3ExprIsInteger(pExpr, &iVal, pParse) && iVal>=0 ){
Expr *pVal = sqlite3Expr(db, TK_INTEGER, 0);
if( pVal==0 ) return;
ExprSetProperty(pVal, EP_IntValue);
@@ -161856,7 +164188,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Selec
assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
if( p->pGroupBy==0
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
- && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
+ && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pSTab)) /* 3 */
){
ExprList *pOrderBy = p->pOrderBy;
int iCsr = p->pSrc->a[0].iCursor;
@@ -162077,7 +164409,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
Expr *pColRef;
Expr *pTerm;
if( pItem->fg.isTabFunc==0 ) return;
- pTab = pItem->pTab;
+ pTab = pItem->pSTab;
assert( pTab!=0 );
pArgs = pItem->u1.pFuncArg;
if( pArgs==0 ) return;
@@ -162152,11 +164484,16 @@ struct HiddenIndexInfo {
int eDistinct; /* Value to return from sqlite3_vtab_distinct() */
u32 mIn; /* Mask of terms that are <col> IN (...) */
u32 mHandleIn; /* Terms that vtab will handle as <col> IN (...) */
- sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST
- ** because extra space is allocated to hold up
- ** to nTerm such values */
+ sqlite3_value *aRhs[FLEXARRAY]; /* RHS values for constraints. MUST BE LAST
+ ** Extra space is allocated to hold up
+ ** to nTerm such values */
};
+/* Size (in bytes) of a HiddenIndeInfo object sufficient to hold as
+** many as N constraints */
+#define SZ_HIDDENINDEXINFO(N) \
+ (offsetof(HiddenIndexInfo,aRhs) + (N)*sizeof(sqlite3_value*))
+
/* Forward declaration of methods */
static int whereLoopResize(sqlite3*, WhereLoop*, int);
@@ -162761,7 +165098,7 @@ static int isDistinctRedundant(
** clause is redundant. */
if( pTabList->nSrc!=1 ) return 0;
iBase = pTabList->a[0].iCursor;
- pTab = pTabList->a[0].pTab;
+ pTab = pTabList->a[0].pSTab;
/* 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
@@ -162836,6 +165173,12 @@ static void translateColumnToCopy(
VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart);
int iEnd = sqlite3VdbeCurrentAddr(v);
if( pParse->db->mallocFailed ) return;
+#ifdef SQLITE_DEBUG
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
+ printf("CHECKING for column-to-copy on cursor %d for %d..%d\n",
+ iTabCur, iStart, iEnd);
+ }
+#endif
for(; iStart<iEnd; iStart++, pOp++){
if( pOp->p1!=iTabCur ) continue;
if( pOp->opcode==OP_Column ){
@@ -162950,13 +165293,52 @@ static int constraintCompatibleWithOuterJoin(
return 0;
}
if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0
- && ExprHasProperty(pTerm->pExpr, EP_InnerON)
+ && NEVER(ExprHasProperty(pTerm->pExpr, EP_InnerON))
){
return 0;
}
return 1;
}
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+/*
+** Return true if column iCol of table pTab seem like it might be a
+** good column to use as part of a query-time index.
+**
+** Current algorithm (subject to improvement!):
+**
+** 1. If iCol is already the left-most column of some other index,
+** then return false.
+**
+** 2. If iCol is part of an existing index that has an aiRowLogEst of
+** more than 20, then return false.
+**
+** 3. If no disqualifying conditions above are found, return true.
+**
+** 2025-01-03: I experimented with a new rule that returns false if the
+** the datatype of the column is "BOOLEAN". This did not improve
+** performance on any queries at hand, but it did burn CPU cycles, so the
+** idea was not committed.
+*/
+static SQLITE_NOINLINE int columnIsGoodIndexCandidate(
+ const Table *pTab,
+ int iCol
+){
+ const Index *pIdx;
+ for(pIdx = pTab->pIndex; pIdx!=0; pIdx=pIdx->pNext){
+ int j;
+ for(j=0; j<pIdx->nKeyCol; j++){
+ if( pIdx->aiColumn[j]==iCol ){
+ if( j==0 ) return 0;
+ if( pIdx->hasStat1 && pIdx->aiRowLogEst[j+1]>20 ) return 0;
+ break;
+ }
+ }
+ }
+ return 1;
+}
+#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
+
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -162971,6 +165353,8 @@ static int termCanDriveIndex(
const Bitmask notReady /* Tables in outer loops of the join */
){
char aff;
+ int leftCol;
+
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
assert( (pSrc->fg.jointype & JT_RIGHT)==0 );
@@ -162981,11 +165365,12 @@ static int termCanDriveIndex(
}
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
- if( pTerm->u.x.leftColumn<0 ) return 0;
- aff = pSrc->pTab->aCol[pTerm->u.x.leftColumn].affinity;
+ leftCol = pTerm->u.x.leftColumn;
+ if( leftCol<0 ) return 0;
+ aff = pSrc->pSTab->aCol[leftCol].affinity;
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
testcase( pTerm->pExpr->op==TK_IS );
- return 1;
+ return columnIsGoodIndexCandidate(pSrc->pSTab, leftCol);
}
#endif
@@ -163018,7 +165403,7 @@ static void explainAutomaticIndex(
sqlite3_str *pStr = sqlite3_str_new(pParse->db);
sqlite3_str_appendf(pStr,"CREATE AUTOMATIC INDEX ON %s(", pTab->zName);
assert( pIdx->nColumn>1 );
- assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID );
+ assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID || !HasRowid(pTab) );
for(ii=0; ii<(pIdx->nColumn-1); ii++){
const char *zName = 0;
int iCol = pIdx->aiColumn[ii];
@@ -163093,7 +165478,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
nKeyCol = 0;
pTabList = pWC->pWInfo->pTabList;
pSrc = &pTabList->a[pLevel->iFrom];
- pTable = pSrc->pTab;
+ pTable = pSrc->pSTab;
pWCEnd = &pWC->a[pWC->nTerm];
pLoop = pLevel->pWLoop;
idxCols = 0;
@@ -163149,6 +165534,19 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
}else{
extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
}
+ if( !HasRowid(pTable) ){
+ /* For WITHOUT ROWID tables, ensure that all PRIMARY KEY columns are
+ ** either in the idxCols mask or in the extraCols mask */
+ for(i=0; i<pTable->nCol; i++){
+ if( (pTable->aCol[i].colFlags & COLFLAG_PRIMKEY)==0 ) continue;
+ if( i>=BMS-1 ){
+ extraCols |= MASKBIT(BMS-1);
+ break;
+ }
+ if( idxCols & MASKBIT(i) ) continue;
+ extraCols |= MASKBIT(i);
+ }
+ }
mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
@@ -163160,7 +165558,10 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
}
/* Construct the Index object to describe this index */
- pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed);
+ assert( nKeyCol <= pTable->nCol + MAX(0, pTable->nCol - BMS + 1) );
+ /* ^-- This guarantees that the number of index columns will fit in the u16 */
+ pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable),
+ 0, &zNotUsed);
if( pIdx==0 ) goto end_auto_index_create;
pLoop->u.btree.pIndex = pIdx;
pIdx->zName = "auto-index";
@@ -163216,8 +165617,10 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
}
}
assert( n==nKeyCol );
- pIdx->aiColumn[n] = XN_ROWID;
- pIdx->azColl[n] = sqlite3StrBINARY;
+ if( HasRowid(pTable) ){
+ pIdx->aiColumn[n] = XN_ROWID;
+ pIdx->azColl[n] = sqlite3StrBINARY;
+ }
/* Create the automatic index */
explainAutomaticIndex(pParse, pIdx, pPartial!=0, &addrExp);
@@ -163235,12 +165638,17 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
/* Fill the automatic index with content */
assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
if( pSrc->fg.viaCoroutine ){
- int regYield = pSrc->regReturn;
+ int regYield;
+ Subquery *pSubq;
+ assert( pSrc->fg.isSubquery );
+ pSubq = pSrc->u4.pSubq;
+ assert( pSubq!=0 );
+ regYield = pSubq->regReturn;
addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub);
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v);
- VdbeComment((v, "next row of %s", pSrc->pTab->zName));
+ VdbeComment((v, "next row of %s", pSrc->pSTab->zName));
}else{
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
}
@@ -163262,11 +165670,12 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
if( pSrc->fg.viaCoroutine ){
+ assert( pSrc->fg.isSubquery && pSrc->u4.pSubq!=0 );
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
testcase( pParse->db->mallocFailed );
assert( pLevel->iIdxCur>0 );
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
- pSrc->regResult, pLevel->iIdxCur);
+ pSrc->u4.pSubq->regResult, pLevel->iIdxCur);
sqlite3VdbeGoto(v, addrTop);
pSrc->fg.viaCoroutine = 0;
}else{
@@ -163357,7 +165766,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
iSrc = pLevel->iFrom;
pItem = &pTabList->a[iSrc];
assert( pItem!=0 );
- pTab = pItem->pTab;
+ pTab = pItem->pSTab;
assert( pTab!=0 );
sz = sqlite3LogEstToInt(pTab->nRowLogEst);
if( sz<10000 ){
@@ -163388,7 +165797,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
int r1 = sqlite3GetTempRange(pParse, n);
int jj;
for(jj=0; jj<n; jj++){
- assert( pIdx->pTable==pItem->pTab );
+ assert( pIdx->pTable==pItem->pSTab );
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
}
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
@@ -163427,6 +165836,20 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
+** Return term iTerm of the WhereClause passed as the first argument. Terms
+** are numbered from 0 upwards, starting with the terms in pWC->a[], then
+** those in pWC->pOuter->a[] (if any), and so on.
+*/
+static WhereTerm *termFromWhereClause(WhereClause *pWC, int iTerm){
+ WhereClause *p;
+ for(p=pWC; p; p=p->pOuter){
+ if( iTerm<p->nTerm ) return &p->a[iTerm];
+ iTerm -= p->nTerm;
+ }
+ return 0;
+}
+
+/*
** 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 freeIndexInfo().
@@ -163452,9 +165875,10 @@ static sqlite3_index_info *allocateIndexInfo(
const Table *pTab;
int eDistinct = 0;
ExprList *pOrderBy = pWInfo->pOrderBy;
+ WhereClause *p;
assert( pSrc!=0 );
- pTab = pSrc->pTab;
+ pTab = pSrc->pSTab;
assert( pTab!=0 );
assert( IsVirtual(pTab) );
@@ -163462,28 +165886,30 @@ static sqlite3_index_info *allocateIndexInfo(
** Mark each term with the TERM_OK flag. Set nTerm to the number of
** terms found.
*/
- for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- pTerm->wtFlags &= ~TERM_OK;
- if( pTerm->leftCursor != pSrc->iCursor ) continue;
- if( pTerm->prereqRight & mUnusable ) continue;
- assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
- testcase( pTerm->eOperator & WO_IN );
- testcase( pTerm->eOperator & WO_ISNULL );
- testcase( pTerm->eOperator & WO_IS );
- testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
- if( pTerm->wtFlags & TERM_VNULL ) continue;
+ for(p=pWC, nTerm=0; p; p=p->pOuter){
+ for(i=0, pTerm=p->a; i<p->nTerm; i++, pTerm++){
+ pTerm->wtFlags &= ~TERM_OK;
+ if( pTerm->leftCursor != pSrc->iCursor ) continue;
+ if( pTerm->prereqRight & mUnusable ) continue;
+ assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
+ testcase( pTerm->eOperator & WO_IN );
+ testcase( pTerm->eOperator & WO_ISNULL );
+ testcase( pTerm->eOperator & WO_IS );
+ testcase( pTerm->eOperator & WO_ALL );
+ if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
+ if( pTerm->wtFlags & TERM_VNULL ) continue;
- assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
- assert( pTerm->u.x.leftColumn>=XN_ROWID );
- assert( pTerm->u.x.leftColumn<pTab->nCol );
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
- && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
- ){
- continue;
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
+ assert( pTerm->u.x.leftColumn>=XN_ROWID );
+ assert( pTerm->u.x.leftColumn<pTab->nCol );
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ continue;
+ }
+ nTerm++;
+ pTerm->wtFlags |= TERM_OK;
}
- nTerm++;
- pTerm->wtFlags |= TERM_OK;
}
/* If the ORDER BY clause contains only columns in the current
@@ -163545,8 +165971,8 @@ static sqlite3_index_info *allocateIndexInfo(
*/
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
- + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden)
- + sizeof(sqlite3_value*)*nTerm );
+ + sizeof(*pIdxOrderBy)*nOrderBy
+ + SZ_HIDDENINDEXINFO(nTerm) );
if( pIdxInfo==0 ){
sqlite3ErrorMsg(pParse, "out of memory");
return 0;
@@ -163558,53 +165984,69 @@ static sqlite3_index_info *allocateIndexInfo(
pIdxInfo->aConstraint = pIdxCons;
pIdxInfo->aOrderBy = pIdxOrderBy;
pIdxInfo->aConstraintUsage = pUsage;
+ pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
+ if( HasRowid(pTab)==0 ){
+ /* Ensure that all bits associated with PK columns are set. This is to
+ ** ensure they are available for cases like RIGHT joins or OR loops. */
+ Index *pPk = sqlite3PrimaryKeyIndex((Table*)pTab);
+ assert( pPk!=0 );
+ for(i=0; i<pPk->nKeyCol; i++){
+ int iCol = pPk->aiColumn[i];
+ assert( iCol>=0 );
+ if( iCol>=BMS-1 ) iCol = BMS-1;
+ pIdxInfo->colUsed |= MASKBIT(iCol);
+ }
+ }
pHidden->pWC = pWC;
pHidden->pParse = pParse;
pHidden->eDistinct = eDistinct;
pHidden->mIn = 0;
- for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- u16 op;
- if( (pTerm->wtFlags & TERM_OK)==0 ) continue;
- pIdxCons[j].iColumn = pTerm->u.x.leftColumn;
- pIdxCons[j].iTermOffset = i;
- op = pTerm->eOperator & WO_ALL;
- if( op==WO_IN ){
- if( (pTerm->wtFlags & TERM_SLICE)==0 ){
- pHidden->mIn |= SMASKBIT32(j);
- }
- op = WO_EQ;
- }
- 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;
+ for(p=pWC, i=j=0; p; p=p->pOuter){
+ int nLast = i+p->nTerm;;
+ for(pTerm=p->a; i<nLast; i++, pTerm++){
+ u16 op;
+ if( (pTerm->wtFlags & TERM_OK)==0 ) continue;
+ pIdxCons[j].iColumn = pTerm->u.x.leftColumn;
+ pIdxCons[j].iTermOffset = i;
+ op = pTerm->eOperator & WO_ALL;
+ if( op==WO_IN ){
+ if( (pTerm->wtFlags & TERM_SLICE)==0 ){
+ pHidden->mIn |= SMASKBIT32(j);
+ }
+ op = WO_EQ;
+ }
+ 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++;
+ j++;
+ }
}
assert( j==nTerm );
pIdxInfo->nConstraint = j;
@@ -163625,6 +166067,17 @@ static sqlite3_index_info *allocateIndexInfo(
}
/*
+** Free and zero the sqlite3_index_info.idxStr value if needed.
+*/
+static void freeIdxStr(sqlite3_index_info *pIdxInfo){
+ if( pIdxInfo->needToFreeIdxStr ){
+ sqlite3_free(pIdxInfo->idxStr);
+ pIdxInfo->idxStr = 0;
+ pIdxInfo->needToFreeIdxStr = 0;
+ }
+}
+
+/*
** Free an sqlite3_index_info structure allocated by allocateIndexInfo()
** and possibly modified by xBestIndex methods.
*/
@@ -163639,6 +166092,7 @@ static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){
sqlite3ValueFree(pHidden->aRhs[i]); /* IMP: R-14553-25174 */
pHidden->aRhs[i] = 0;
}
+ freeIdxStr(pIdxInfo);
sqlite3DbFree(db, pIdxInfo);
}
@@ -163659,9 +166113,11 @@ static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){
** that this is required.
*/
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
- sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
int rc;
+ sqlite3_vtab *pVtab;
+ assert( IsVirtual(pTab) );
+ pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
whereTraceIndexInfoInputs(p, pTab);
pParse->db->nSchemaLock++;
rc = pVtab->pModule->xBestIndex(pVtab, p);
@@ -164353,7 +166809,7 @@ static int whereInScanEst(
#endif /* SQLITE_ENABLE_STAT4 */
-#ifdef WHERETRACE_ENABLED
+#if defined(WHERETRACE_ENABLED) || defined(SQLITE_DEBUG)
/*
** Print the content of a WhereTerm object
*/
@@ -164397,6 +166853,9 @@ SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
}
}
+SQLITE_PRIVATE void sqlite3ShowWhereTerm(WhereTerm *pTerm){
+ sqlite3WhereTermPrint(pTerm, 0);
+}
#endif
#ifdef WHERETRACE_ENABLED
@@ -164428,17 +166887,19 @@ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31
*/
SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
+ WhereInfo *pWInfo;
if( pWC ){
- WhereInfo *pWInfo = pWC->pWInfo;
+ pWInfo = pWC->pWInfo;
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
- Table *pTab = pItem->pTab;
+ Table *pTab = pItem->pSTab;
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
sqlite3DebugPrintf(" %12s",
pItem->zAlias ? pItem->zAlias : pTab->zName);
}else{
+ pWInfo = 0;
sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d",
p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab);
}
@@ -164470,7 +166931,12 @@ SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause
}else{
sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm);
}
- sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
+ if( pWInfo && pWInfo->bStarUsed && p->rStarDelta!=0 ){
+ sqlite3DebugPrintf(" cost %d,%d,%d delta=%d\n",
+ p->rSetup, p->rRun, p->nOut, p->rStarDelta);
+ }else{
+ sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
+ }
if( p->nLTerm && (sqlite3WhereTrace & 0x4000)!=0 ){
int i;
for(i=0; i<p->nLTerm; i++){
@@ -164604,7 +167070,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
** and Y has additional constraints that might speed the search that X lacks
** but the cost of running X is not more than the cost of running Y.
**
-** In other words, return true if the cost relationwship between X and Y
+** In other words, return true if the cost relationship between X and Y
** is inverted and needs to be adjusted.
**
** Case 1:
@@ -164990,7 +167456,7 @@ static void whereLoopOutputAdjust(
Expr *pRight = pTerm->pExpr->pRight;
int k = 0;
testcase( pTerm->pExpr->op==TK_IS );
- if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
+ if( sqlite3ExprIsInteger(pRight, &k, 0) && k>=(-1) && k<=1 ){
k = 10;
}else{
k = 20;
@@ -165142,11 +167608,8 @@ static int whereLoopAddBtreeIndex(
assert( pNew->u.btree.nBtm==0 );
opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
}
- if( pProbe->bUnordered || pProbe->bLowQual ){
- if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
- if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){
- opMask &= ~(WO_EQ|WO_IN|WO_IS);
- }
+ if( pProbe->bUnordered ){
+ opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
}
assert( pNew->u.btree.nEq<pProbe->nColumn );
@@ -165287,7 +167750,7 @@ static int whereLoopAddBtreeIndex(
|| (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
){
if( iCol==XN_ROWID || pProbe->uniqNotNull
- || (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ)
+ || (pProbe->nKeyCol==1 && pProbe->onError && (eOp & WO_EQ))
){
pNew->wsFlags |= WHERE_ONEROW;
}else{
@@ -165420,7 +167883,7 @@ static int whereLoopAddBtreeIndex(
** 2. Stepping forward in the index pNew->nOut times to find all
** additional matching entries.
*/
- assert( pSrc->pTab->szTabRow>0 );
+ assert( pSrc->pSTab->szTabRow>0 );
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
/* The pProbe->szIdxRow is low for an IPK table since the interior
** pages are small. Thus szIdxRow gives a good estimate of seek cost.
@@ -165428,7 +167891,7 @@ static int whereLoopAddBtreeIndex(
** under-estimate the scanning cost. */
rCostIdx = pNew->nOut + 16;
}else{
- rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
+ rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pSTab->szTabRow;
}
rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx);
@@ -165459,7 +167922,7 @@ static int whereLoopAddBtreeIndex(
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
&& pNew->u.btree.nEq<pProbe->nColumn
&& (pNew->u.btree.nEq<pProbe->nKeyCol ||
- pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY)
+ (pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY && !pProbe->bIdxRowid))
){
if( pNew->u.btree.nEq>3 ){
sqlite3ProgressCheck(pParse);
@@ -165582,13 +168045,13 @@ static int whereUsablePartialIndex(
if( !whereUsablePartialIndex(iTab,jointype,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;
pExpr = pTerm->pExpr;
if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab)
&& ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON))
&& sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
+ && !sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, -1)
&& (pTerm->wtFlags & TERM_VNULL)==0
){
return 1;
@@ -165893,9 +168356,9 @@ static int whereLoopAddBtree(
pWInfo = pBuilder->pWInfo;
pTabList = pWInfo->pTabList;
pSrc = pTabList->a + pNew->iTab;
- pTab = pSrc->pTab;
+ pTab = pSrc->pSTab;
pWC = pBuilder->pWC;
- assert( !IsVirtual(pSrc->pTab) );
+ assert( !IsVirtual(pSrc->pSTab) );
if( pSrc->fg.isIndexedBy ){
assert( pSrc->fg.isCte==0 );
@@ -165920,7 +168383,7 @@ static int whereLoopAddBtree(
sPk.idxType = SQLITE_IDXTYPE_IPK;
aiRowEstPk[0] = pTab->nRowLogEst;
aiRowEstPk[1] = 0;
- pFirst = pSrc->pTab->pIndex;
+ pFirst = pSrc->pSTab->pIndex;
if( pSrc->fg.notIndexed==0 ){
/* The real indices of the table are only considered if the
** NOT INDEXED qualifier is omitted from the FROM clause */
@@ -165937,7 +168400,6 @@ static int whereLoopAddBtree(
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
&& !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */
&& !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */
- && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */
&& !pSrc->fg.isCorrelated /* Not a correlated subquery */
&& !pSrc->fg.isRecursive /* Not a recursive common table expression. */
&& (pSrc->fg.jointype & JT_RIGHT)==0 /* Not the right tab of a RIGHT JOIN */
@@ -166010,6 +168472,7 @@ static int whereLoopAddBtree(
pNew->prereq = mPrereq;
pNew->nOut = rSize;
pNew->u.btree.pIndex = pProbe;
+ pNew->u.btree.pOrderBy = 0;
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
/* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
@@ -166039,6 +168502,10 @@ static int whereLoopAddBtree(
#endif
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize);
+ if( pSrc->fg.isSubquery ){
+ if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
+ pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
+ }
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
@@ -166080,7 +168547,7 @@ static int whereLoopAddBtree(
&& (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700))
){
WHERETRACE(0x200,
- ("-> %s a covering index according to bitmasks\n",
+ ("-> %s is a covering index according to bitmasks\n",
pProbe->zName, m==0 ? "is" : "is not"));
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
}
@@ -166241,7 +168708,7 @@ static int whereLoopAddVirtualOne(
** arguments mUsable and mExclude. */
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
for(i=0; i<nConstraint; i++, pIdxCons++){
- WhereTerm *pTerm = &pWC->a[pIdxCons->iTermOffset];
+ WhereTerm *pTerm = termFromWhereClause(pWC, pIdxCons->iTermOffset);
pIdxCons->usable = 0;
if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
&& (pTerm->eOperator & mExclude)==0
@@ -166260,11 +168727,10 @@ static int whereLoopAddVirtualOne(
pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
pIdxInfo->estimatedRows = 25;
pIdxInfo->idxFlags = 0;
- pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
pHidden->mHandleIn = 0;
/* Invoke the virtual table xBestIndex() method */
- rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
+ rc = vtabBestIndex(pParse, pSrc->pSTab, pIdxInfo);
if( rc ){
if( rc==SQLITE_CONSTRAINT ){
/* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
@@ -166272,6 +168738,7 @@ static int whereLoopAddVirtualOne(
** Make no entries in the loop table.
*/
WHERETRACE(0xffffffff, (" ^^^^--- non-viable plan rejected!\n"));
+ freeIdxStr(pIdxInfo);
return SQLITE_OK;
}
return rc;
@@ -166289,18 +168756,17 @@ static int whereLoopAddVirtualOne(
int j = pIdxCons->iTermOffset;
if( iTerm>=nConstraint
|| j<0
- || j>=pWC->nTerm
+ || (pTerm = termFromWhereClause(pWC, j))==0
|| pNew->aLTerm[iTerm]!=0
|| pIdxCons->usable==0
){
- sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
- testcase( pIdxInfo->needToFreeIdxStr );
+ sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
+ freeIdxStr(pIdxInfo);
return SQLITE_ERROR;
}
testcase( iTerm==nConstraint-1 );
testcase( j==0 );
testcase( j==pWC->nTerm-1 );
- pTerm = &pWC->a[j];
pNew->prereq |= pTerm->prereqRight;
assert( iTerm<pNew->nLSlot );
pNew->aLTerm[iTerm] = pTerm;
@@ -166345,11 +168811,7 @@ static int whereLoopAddVirtualOne(
** the plan cannot be used. In these cases set variable *pbRetryLimit
** to true to tell the caller to retry with LIMIT and OFFSET
** disabled. */
- if( pIdxInfo->needToFreeIdxStr ){
- sqlite3_free(pIdxInfo->idxStr);
- pIdxInfo->idxStr = 0;
- pIdxInfo->needToFreeIdxStr = 0;
- }
+ freeIdxStr(pIdxInfo);
*pbRetryLimit = 1;
return SQLITE_OK;
}
@@ -166361,8 +168823,8 @@ static int whereLoopAddVirtualOne(
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 );
+ sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
+ freeIdxStr(pIdxInfo);
return SQLITE_ERROR;
}
}
@@ -166373,6 +168835,7 @@ static int whereLoopAddVirtualOne(
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
pIdxInfo->nOrderBy : 0);
+ pNew->u.vtab.bIdxNumHex = (pIdxInfo->idxFlags&SQLITE_INDEX_SCAN_HEX)!=0;
pNew->rSetup = 0;
pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
@@ -166417,7 +168880,7 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int
if( iCons>=0 && iCons<pIdxInfo->nConstraint ){
CollSeq *pC = 0;
int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset;
- Expr *pX = pHidden->pWC->a[iTerm].pExpr;
+ Expr *pX = termFromWhereClause(pHidden->pWC, iTerm)->pExpr;
if( pX->pLeft ){
pC = sqlite3ExprCompareCollSeq(pHidden->pParse, pX);
}
@@ -166463,7 +168926,9 @@ SQLITE_API int sqlite3_vtab_rhs_value(
rc = SQLITE_MISUSE_BKPT; /* EV: R-30545-25046 */
}else{
if( pH->aRhs[iCons]==0 ){
- WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset];
+ WhereTerm *pTerm = termFromWhereClause(
+ pH->pWC, pIdxInfo->aConstraint[iCons].iTermOffset
+ );
rc = sqlite3ValueFromExpr(
pH->pParse->db, pTerm->pExpr->pRight, ENC(pH->pParse->db),
SQLITE_AFF_BLOB, &pH->aRhs[iCons]
@@ -166561,7 +169026,7 @@ static int whereLoopAddVirtual(
pWC = pBuilder->pWC;
pNew = pBuilder->pNew;
pSrc = &pWInfo->pTabList->a[pNew->iTab];
- assert( IsVirtual(pSrc->pTab) );
+ assert( IsVirtual(pSrc->pSTab) );
p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit);
if( p==0 ) return SQLITE_NOMEM_BKPT;
pNew->rSetup = 0;
@@ -166575,7 +169040,7 @@ static int whereLoopAddVirtual(
}
/* First call xBestIndex() with all constraints usable. */
- WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
+ WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pSTab->zName));
WHERETRACE(0x800, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
@@ -166619,9 +169084,8 @@ static int whereLoopAddVirtual(
Bitmask mNext = ALLBITS;
assert( mNext>0 );
for(i=0; i<nConstraint; i++){
- Bitmask mThis = (
- pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq
- );
+ int iTerm = p->aConstraint[i].iTermOffset;
+ Bitmask mThis = termFromWhereClause(pWC, iTerm)->prereqRight & ~mPrereq;
if( mThis>mPrev && mThis<mNext ) mNext = mThis;
}
mPrev = mNext;
@@ -166657,9 +169121,8 @@ static int whereLoopAddVirtual(
}
}
- if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
freeIndexInfo(pParse->db, p);
- WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc));
+ WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pSTab->zName, rc));
return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -166731,7 +169194,7 @@ static int whereLoopAddOr(
}
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( IsVirtual(pItem->pTab) ){
+ if( IsVirtual(pItem->pSTab) ){
rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
}else
#endif
@@ -166845,7 +169308,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
mPrereq = 0;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( IsVirtual(pItem->pTab) ){
+ if( IsVirtual(pItem->pSTab) ){
SrcItem *p;
for(p=&pItem[1]; p<pEnd; p++){
if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
@@ -166877,6 +169340,97 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
return rc;
}
+/* Implementation of the order-by-subquery optimization:
+**
+** WhereLoop pLoop, which the iLoop-th term of the nested loop, is really
+** a subquery or CTE that has an ORDER BY clause. See if any of the terms
+** in the subquery ORDER BY clause will satisfy pOrderBy from the outer
+** query. Mark off all satisfied terms (by setting bits in *pOBSat) and
+** return TRUE if they do. If not, return false.
+**
+** Example:
+**
+** CREATE TABLE t1(a,b,c, PRIMARY KEY(a,b));
+** CREATE TABLE t2(x,y);
+** WITH t3(p,q) AS MATERIALIZED (SELECT x+y, x-y FROM t2 ORDER BY x+y)
+** SELECT * FROM t3 JOIN t1 ON a=q ORDER BY p, b;
+**
+** The CTE named "t3" comes out in the natural order of "p", so the first
+** first them of "ORDER BY p,b" is satisfied by a sequential scan of "t3"
+** and sorting only needs to occur on the second term "b".
+**
+** Limitations:
+**
+** (1) The optimization is not applied if the outer ORDER BY contains
+** a COLLATE clause. The optimization might be applied if the
+** outer ORDER BY uses NULLS FIRST, NULLS LAST, ASC, and/or DESC as
+** long as the subquery ORDER BY does the same. But if the
+** outer ORDER BY uses COLLATE, even a redundant COLLATE, the
+** optimization is bypassed.
+**
+** (2) The subquery ORDER BY terms must exactly match subquery result
+** columns, including any COLLATE annotations. This routine relies
+** on iOrderByCol to do matching between order by terms and result
+** columns, and iOrderByCol will not be set if the result column
+** and ORDER BY collations differ.
+**
+** (3) The subquery and outer ORDER BY can be in opposite directions as
+** long as the subquery is materialized. If the subquery is
+** implemented as a co-routine, the sort orders must be in the same
+** direction because there is no way to run a co-routine backwards.
+*/
+static SQLITE_NOINLINE int wherePathMatchSubqueryOB(
+ WhereInfo *pWInfo, /* The WHERE clause */
+ WhereLoop *pLoop, /* The nested loop term that is a subquery */
+ int iLoop, /* Which level of the nested loop. 0==outermost */
+ int iCur, /* Cursor used by the this loop */
+ ExprList *pOrderBy, /* The ORDER BY clause on the whole query */
+ Bitmask *pRevMask, /* When loops need to go in reverse order */
+ Bitmask *pOBSat /* Which terms of pOrderBy are satisfied so far */
+){
+ int iOB; /* Index into pOrderBy->a[] */
+ int jSub; /* Index into pSubOB->a[] */
+ u8 rev = 0; /* True if iOB and jSub sort in opposite directions */
+ u8 revIdx = 0; /* Sort direction for jSub */
+ Expr *pOBExpr; /* Current term of outer ORDER BY */
+ ExprList *pSubOB; /* Complete ORDER BY on the subquery */
+
+ pSubOB = pLoop->u.btree.pOrderBy;
+ assert( pSubOB!=0 );
+ for(iOB=0; (MASKBIT(iOB) & *pOBSat)!=0; iOB++){}
+ for(jSub=0; jSub<pSubOB->nExpr && iOB<pOrderBy->nExpr; jSub++, iOB++){
+ if( pSubOB->a[jSub].u.x.iOrderByCol==0 ) break;
+ pOBExpr = pOrderBy->a[iOB].pExpr;
+ if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) break;
+ if( pOBExpr->iTable!=iCur ) break;
+ if( pOBExpr->iColumn!=pSubOB->a[jSub].u.x.iOrderByCol-1 ) break;
+ if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
+ u8 sfOB = pOrderBy->a[iOB].fg.sortFlags; /* sortFlags for iOB */
+ u8 sfSub = pSubOB->a[jSub].fg.sortFlags; /* sortFlags for jSub */
+ if( (sfSub & KEYINFO_ORDER_BIGNULL) != (sfOB & KEYINFO_ORDER_BIGNULL) ){
+ break;
+ }
+ revIdx = sfSub & KEYINFO_ORDER_DESC;
+ if( jSub>0 ){
+ if( (rev^revIdx)!=(sfOB & KEYINFO_ORDER_DESC) ){
+ break;
+ }
+ }else{
+ rev = revIdx ^ (sfOB & KEYINFO_ORDER_DESC);
+ if( rev ){
+ if( (pLoop->wsFlags & WHERE_COROUTINE)!=0 ){
+ /* Cannot run a co-routine in reverse order */
+ break;
+ }
+ *pRevMask |= MASKBIT(iLoop);
+ }
+ }
+ }
+ *pOBSat |= MASKBIT(iOB);
+ }
+ return jSub>0;
+}
+
/*
** 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
@@ -167022,9 +169576,18 @@ static i8 wherePathSatisfiesOrderBy(
if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){
if( pLoop->wsFlags & WHERE_IPK ){
+ if( pLoop->u.btree.pOrderBy
+ && OptimizationEnabled(db, SQLITE_OrderBySubq)
+ && wherePathMatchSubqueryOB(pWInfo,pLoop,iLoop,iCur,
+ pOrderBy,pRevMask, &obSat)
+ ){
+ nColumn = 0;
+ isOrderDistinct = 0;
+ }else{
+ nColumn = 1;
+ }
pIndex = 0;
nKeyCol = 0;
- nColumn = 1;
}else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){
return 0;
}else{
@@ -167034,7 +169597,7 @@ static i8 wherePathSatisfiesOrderBy(
assert( pIndex->aiColumn[nColumn-1]==XN_ROWID
|| !HasRowid(pIndex->pTable));
/* All relevant terms of the index must also be non-NULL in order
- ** for isOrderDistinct to be true. So the isOrderDistint value
+ ** for isOrderDistinct to be true. So the isOrderDistinct value
** computed here might be a false positive. Corrections will be
** made at tag-20210426-1 below */
isOrderDistinct = IsUniqueIndex(pIndex)
@@ -167119,7 +169682,7 @@ 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 having been satisfied.
*/
isMatch = 0;
for(i=0; bOnce && i<nOrderBy; i++){
@@ -167327,6 +169890,216 @@ static LogEst whereSortingCost(
}
/*
+** Compute the maximum number of paths in the solver algorithm, for
+** queries that have three or more terms in the FROM clause. Queries with
+** two or fewer FROM clause terms are handled by the caller.
+**
+** Query planning is NP-hard. We must limit the number of paths at
+** each step of the solver search algorithm to avoid exponential behavior.
+**
+** The value returned is a tuning parameter. Currently the value is:
+**
+** 18 for star queries
+** 12 otherwise
+**
+** For the purposes of this heuristic, a star-query is defined as a query
+** with a large central table that is joined using an INNER JOIN,
+** not CROSS or OUTER JOINs, against four or more smaller tables.
+** The central table is called the "fact" table. The smaller tables
+** that get joined are "dimension tables". Also, any table that is
+** self-joined cannot be a dimension table; we assume that dimension
+** tables may only be joined against fact tables.
+**
+** SIDE EFFECT: (and really the whole point of this subroutine)
+**
+** If pWInfo describes a star-query, then the cost for SCANs of dimension
+** WhereLoops is increased to be slightly larger than the cost of a SCAN
+** in the fact table. Only SCAN costs are increased. SEARCH costs are
+** unchanged. This heuristic helps keep fact tables in outer loops. Without
+** this heuristic, paths with fact tables in outer loops tend to get pruned
+** by the mxChoice limit on the number of paths, resulting in poor query
+** plans. See the starschema1.test test module for examples of queries
+** that need this heuristic to find good query plans.
+**
+** This heuristic can be completely disabled, so that no query is
+** considered a star-query, using SQLITE_TESTCTRL_OPTIMIZATION to
+** disable the SQLITE_StarQuery optimization. In the CLI, the command
+** to do that is: ".testctrl opt -starquery".
+**
+** HISTORICAL NOTES:
+**
+** This optimization was first added on 2024-05-09 by check-in 38db9b5c83d.
+** The original optimization reduced the cost and output size estimate for
+** fact tables to help them move to outer loops. But months later (as people
+** started upgrading) performance regression reports started caming in,
+** including:
+**
+** forum post b18ef983e68d06d1 (2024-12-21)
+** forum post 0025389d0860af82 (2025-01-14)
+** forum post d87570a145599033 (2025-01-17)
+**
+** To address these, the criteria for a star-query was tightened to exclude
+** cases where the fact and dimensions are separated by an outer join, and
+** the affect of star-schema detection was changed to increase the rRun cost
+** on just full table scans of dimension tables, rather than reducing costs
+** in the all access methods of the fact table.
+*/
+static int computeMxChoice(WhereInfo *pWInfo){
+ int nLoop = pWInfo->nLevel; /* Number of terms in the join */
+ WhereLoop *pWLoop; /* For looping over WhereLoops */
+
+#ifdef SQLITE_DEBUG
+ /* The star-query detection code below makes use of the following
+ ** properties of the WhereLoop list, so verify them before
+ ** continuing:
+ ** (1) .maskSelf is the bitmask corresponding to .iTab
+ ** (2) The WhereLoop list is in ascending .iTab order
+ */
+ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
+ assert( pWLoop->maskSelf==MASKBIT(pWLoop->iTab) );
+ assert( pWLoop->pNextLoop==0 || pWLoop->iTab<=pWLoop->pNextLoop->iTab );
+ }
+#endif /* SQLITE_DEBUG */
+
+ if( nLoop>=5
+ && !pWInfo->bStarDone
+ && OptimizationEnabled(pWInfo->pParse->db, SQLITE_StarQuery)
+ ){
+ SrcItem *aFromTabs; /* All terms of the FROM clause */
+ int iFromIdx; /* Term of FROM clause is the candidate fact-table */
+ Bitmask m; /* Bitmask for candidate fact-table */
+ Bitmask mSelfJoin = 0; /* Tables that cannot be dimension tables */
+ WhereLoop *pStart; /* Where to start searching for dimension-tables */
+
+ pWInfo->bStarDone = 1; /* Only do this computation once */
+
+ /* Look for fact tables with four or more dimensions where the
+ ** dimension tables are not separately from the fact tables by an outer
+ ** or cross join. Adjust cost weights if found.
+ */
+ assert( !pWInfo->bStarUsed );
+ aFromTabs = pWInfo->pTabList->a;
+ pStart = pWInfo->pLoops;
+ for(iFromIdx=0, m=1; iFromIdx<nLoop; iFromIdx++, m<<=1){
+ int nDep = 0; /* Number of dimension tables */
+ LogEst mxRun; /* Maximum SCAN cost of a fact table */
+ Bitmask mSeen = 0; /* Mask of dimension tables */
+ SrcItem *pFactTab; /* The candidate fact table */
+
+ pFactTab = aFromTabs + iFromIdx;
+ if( (pFactTab->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){
+ /* If the candidate fact-table is the right table of an outer join
+ ** restrict the search for dimension-tables to be tables to the right
+ ** of the fact-table. */
+ if( iFromIdx+4 > nLoop ) break; /* Impossible to reach nDep>=4 */
+ while( pStart && pStart->iTab<=iFromIdx ){
+ pStart = pStart->pNextLoop;
+ }
+ }
+ for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){
+ if( (aFromTabs[pWLoop->iTab].fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){
+ /* Fact-tables and dimension-tables cannot be separated by an
+ ** outer join (at least for the definition of fact- and dimension-
+ ** used by this heuristic). */
+ break;
+ }
+ if( (pWLoop->prereq & m)!=0 /* pWInfo depends on iFromIdx */
+ && (pWLoop->maskSelf & mSeen)==0 /* pWInfo not already a dependency */
+ && (pWLoop->maskSelf & mSelfJoin)==0 /* Not a self-join */
+ ){
+ if( aFromTabs[pWLoop->iTab].pSTab==pFactTab->pSTab ){
+ mSelfJoin |= m;
+ }else{
+ nDep++;
+ mSeen |= pWLoop->maskSelf;
+ }
+ }
+ }
+ if( nDep<=3 ) continue;
+
+ /* If we reach this point, it means that pFactTab is a fact table
+ ** with four or more dimensions connected by inner joins. Proceed
+ ** to make cost adjustments. */
+
+#ifdef WHERETRACE_ENABLED
+ /* Make sure rStarDelta values are initialized */
+ if( !pWInfo->bStarUsed ){
+ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
+ pWLoop->rStarDelta = 0;
+ }
+ }
+#endif
+ pWInfo->bStarUsed = 1;
+
+ /* Compute the maximum cost of any WhereLoop for the
+ ** fact table plus one epsilon */
+ mxRun = LOGEST_MIN;
+ for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){
+ if( pWLoop->iTab<iFromIdx ) continue;
+ if( pWLoop->iTab>iFromIdx ) break;
+ if( pWLoop->rRun>mxRun ) mxRun = pWLoop->rRun;
+ }
+ if( ALWAYS(mxRun<LOGEST_MAX) ) mxRun++;
+
+ /* Increase the cost of table scans for dimension tables to be
+ ** slightly more than the maximum cost of the fact table */
+ for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){
+ if( (pWLoop->maskSelf & mSeen)==0 ) continue;
+ if( pWLoop->nLTerm ) continue;
+ if( pWLoop->rRun<mxRun ){
+#ifdef WHERETRACE_ENABLED /* 0x80000 */
+ if( sqlite3WhereTrace & 0x80000 ){
+ SrcItem *pDim = aFromTabs + pWLoop->iTab;
+ sqlite3DebugPrintf(
+ "Increase SCAN cost of dimension %s(%d) of fact %s(%d) to %d\n",
+ pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab,
+ pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName,
+ iFromIdx, mxRun
+ );
+ }
+ pWLoop->rStarDelta = mxRun - pWLoop->rRun;
+#endif /* WHERETRACE_ENABLED */
+ pWLoop->rRun = mxRun;
+ }
+ }
+ }
+#ifdef WHERETRACE_ENABLED /* 0x80000 */
+ if( (sqlite3WhereTrace & 0x80000)!=0 && pWInfo->bStarUsed ){
+ sqlite3DebugPrintf("WhereLoops changed by star-query heuristic:\n");
+ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
+ if( pWLoop->rStarDelta ){
+ sqlite3WhereLoopPrint(pWLoop, &pWInfo->sWC);
+ }
+ }
+ }
+#endif
+ }
+ return pWInfo->bStarUsed ? 18 : 12;
+}
+
+/*
+** Two WhereLoop objects, pCandidate and pBaseline, are known to have the
+** same cost. Look deep into each to see if pCandidate is even slightly
+** better than pBaseline. Return false if it is, if pCandidate is is preferred.
+** Return true if pBaseline is preferred or if we cannot tell the difference.
+**
+** Result Meaning
+** -------- ----------------------------------------------------------
+** true We cannot tell the difference in pCandidate and pBaseline
+** false pCandidate seems like a better choice than pBaseline
+*/
+static SQLITE_NOINLINE int whereLoopIsNoBetter(
+ const WhereLoop *pCandidate,
+ const WhereLoop *pBaseline
+){
+ if( (pCandidate->wsFlags & WHERE_INDEXED)==0 ) return 1;
+ if( (pBaseline->wsFlags & WHERE_INDEXED)==0 ) return 1;
+ if( pCandidate->u.btree.pIndex->szIdxRow <
+ pBaseline->u.btree.pIndex->szIdxRow ) return 0;
+ return 1;
+}
+
+/*
** Given the list of WhereLoop objects at pWInfo->pLoops, this routine
** attempts to find the lowest cost path that visits each WhereLoop
** once. This path is then loaded into the pWInfo->a[].pWLoop fields.
@@ -167347,7 +170120,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int mxI = 0; /* Index of next entry to replace */
int nOrderBy; /* Number of ORDER BY clause terms */
LogEst mxCost = 0; /* Maximum cost of a set of paths */
- LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */
+ LogEst mxUnsort = 0; /* Maximum unsorted cost of a set of path */
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
WherePath *aFrom; /* All nFrom paths at the previous level */
WherePath *aTo; /* The nTo best paths at the current level */
@@ -167361,13 +170134,27 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pParse = pWInfo->pParse;
nLoop = pWInfo->nLevel;
- /* TUNING: For simple queries, only the best path is tracked.
- ** For 2-way joins, the 5 best paths are followed.
- ** For joins of 3 or more tables, track the 10 best paths */
- mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10);
- assert( nLoop<=pWInfo->pTabList->nSrc );
WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d, nQueryLoop=%d)\n",
nRowEst, pParse->nQueryLoop));
+ /* TUNING: mxChoice is the maximum number of possible paths to preserve
+ ** at each step. Based on the number of loops in the FROM clause:
+ **
+ ** nLoop mxChoice
+ ** ----- --------
+ ** 1 1 // the most common case
+ ** 2 5
+ ** 3+ 12 or 18 // see computeMxChoice()
+ */
+ if( nLoop<=1 ){
+ mxChoice = 1;
+ }else if( nLoop==2 ){
+ mxChoice = 5;
+ }else if( pParse->nErr ){
+ mxChoice = 1;
+ }else{
+ mxChoice = computeMxChoice(pWInfo);
+ }
+ assert( nLoop<=pWInfo->pTabList->nSrc );
/* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this
** case the purpose of this call is to estimate the number of rows returned
@@ -167432,7 +170219,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
LogEst rCost; /* Cost of path (pFrom+pWLoop) */
- LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
+ LogEst rUnsort; /* Unsorted cost of (pFrom+pWLoop) */
i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */
Bitmask maskNew; /* Mask of src visited by (..) */
Bitmask revMask; /* Mask of rev-order loops for (..) */
@@ -167450,8 +170237,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* 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);
+ rUnsort = pWLoop->rRun + pFrom->nRow;
+ if( pWLoop->rSetup ){
+ rUnsort = sqlite3LogEstAdd(pWLoop->rSetup, rUnsort);
+ }
+ rUnsort = sqlite3LogEstAdd(rUnsort, pFrom->rUnsort);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
isOrdered = pFrom->isOrdered;
@@ -167473,15 +170263,15 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** extra encouragement 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]) + 3;
+ rCost = sqlite3LogEstAdd(rUnsort, aSortCost[isOrdered]) + 3;
WHERETRACE(0x002,
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy,
- rUnsorted, rCost));
+ rUnsort, rCost));
}else{
- rCost = rUnsorted;
- rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
+ rCost = rUnsort;
+ rUnsort -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
/* Check to see if pWLoop should be added to the set of
@@ -167495,6 +170285,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** to (pTo->isOrdered==(-1))==(isOrdered==(-1))" for the range
** of legal values for isOrdered, -1..64.
*/
+ testcase( nTo==0 );
for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
if( pTo->maskLoop==maskNew
&& ((pTo->isOrdered^isOrdered)&0x80)==0
@@ -167506,7 +170297,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( jj>=nTo ){
/* None of the existing best-so-far paths match the candidate. */
if( nTo>=mxChoice
- && (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted))
+ && (rCost>mxCost || (rCost==mxCost && rUnsort>=mxUnsort))
){
/* The current candidate is no better than any of the mxChoice
** paths currently in the best-so-far buffer. So discard
@@ -167514,7 +170305,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
@@ -167533,7 +170324,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
@@ -167544,24 +170335,23 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** 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)
+ ** (pTo->rCost,pTo->nRow,pTo->rUnsort) <= (rCost,nOut,rUnsort)
*/
- if( pTo->rCost<rCost
- || (pTo->rCost==rCost
- && (pTo->nRow<nOut
- || (pTo->nRow==nOut && pTo->rUnsorted<=rUnsorted)
- )
- )
+ if( (pTo->rCost<rCost)
+ || (pTo->rCost==rCost && pTo->nRow<nOut)
+ || (pTo->rCost==rCost && pTo->nRow==nOut && pTo->rUnsort<rUnsort)
+ || (pTo->rCost==rCost && pTo->nRow==nOut && pTo->rUnsort==rUnsort
+ && whereLoopIsNoBetter(pWLoop, pTo->aLoop[iLoop]) )
){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Skip %s cost=%-3d,%3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort,
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsort, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
/* Discard the candidate path from further consideration */
@@ -167575,11 +170365,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
"Update %s cost=%-3d,%3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort,
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsort, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
}
@@ -167588,20 +170378,20 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pTo->revLoop = revMask;
pTo->nRow = nOut;
pTo->rCost = rCost;
- pTo->rUnsorted = rUnsorted;
+ pTo->rUnsort = rUnsort;
pTo->isOrdered = isOrdered;
memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
pTo->aLoop[iLoop] = pWLoop;
if( nTo>=mxChoice ){
mxI = 0;
mxCost = aTo[0].rCost;
- mxUnsorted = aTo[0].nRow;
+ mxUnsort = aTo[0].nRow;
for(jj=1, pTo=&aTo[1]; jj<mxChoice; jj++, pTo++){
if( pTo->rCost>mxCost
- || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted)
+ || (pTo->rCost==mxCost && pTo->rUnsort>mxUnsort)
){
mxCost = pTo->rCost;
- mxUnsorted = pTo->rUnsorted;
+ mxUnsort = pTo->rUnsort;
mxI = jj;
}
}
@@ -167611,17 +170401,32 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
#ifdef WHERETRACE_ENABLED /* >=2 */
if( sqlite3WhereTrace & 0x02 ){
+ LogEst rMin, rFloor = 0;
+ int nDone = 0;
+ int nProgress;
sqlite3DebugPrintf("---- after round %d ----\n", iLoop);
- for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
- sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
- wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?');
- if( pTo->isOrdered>0 ){
- sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
- }else{
- sqlite3DebugPrintf("\n");
+ do{
+ nProgress = 0;
+ rMin = 0x7fff;
+ for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
+ if( pTo->rCost>rFloor && pTo->rCost<rMin ) rMin = pTo->rCost;
+ }
+ for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
+ if( pTo->rCost==rMin ){
+ sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
+ wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
+ pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?');
+ if( pTo->isOrdered>0 ){
+ sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
+ }else{
+ sqlite3DebugPrintf("\n");
+ }
+ nDone++;
+ nProgress++;
+ }
}
- }
+ rFloor = rMin;
+ }while( nDone<nTo && nProgress>0 );
}
#endif
@@ -167716,6 +170521,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
pWInfo->nRowOut = pFrom->nRow;
+#ifdef WHERETRACE_ENABLED
+ pWInfo->rTotalCost = pFrom->rCost;
+#endif
/* Free temporary memory and return success */
sqlite3StackFreeNN(pParse->db, pSpace);
@@ -167826,7 +170634,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
assert( pWInfo->pTabList->nSrc>=1 );
pItem = pWInfo->pTabList->a;
- pTab = pItem->pTab;
+ pTab = pItem->pSTab;
if( IsVirtual(pTab) ) return 0;
if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){
testcase( pItem->fg.isIndexedBy );
@@ -168016,6 +170824,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
WhereTerm *pTerm, *pEnd;
SrcItem *pItem;
WhereLoop *pLoop;
+ Bitmask m1;
pLoop = pWInfo->a[i].pWLoop;
pItem = &pWInfo->pTabList->a[pLoop->iTab];
if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ) continue;
@@ -168036,13 +170845,16 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
}
if( hasRightJoin
&& ExprHasProperty(pTerm->pExpr, EP_InnerON)
- && pTerm->pExpr->w.iJoin==pItem->iCursor
+ && NEVER(pTerm->pExpr->w.iJoin==pItem->iCursor)
){
break; /* restriction (5) */
}
}
if( pTerm<pEnd ) continue;
- WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId));
+ WHERETRACE(0xffffffff,("-> omit unused FROM-clause term %c\n",pLoop->cId));
+ m1 = MASKBIT(i)-1;
+ testcase( ((pWInfo->revMask>>1) & ~m1)!=0 );
+ pWInfo->revMask = (m1 & pWInfo->revMask) | ((pWInfo->revMask>>1) & ~m1);
notReady &= ~pLoop->maskSelf;
for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
@@ -168089,7 +170901,7 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
WhereLoop *pLoop = pWInfo->a[i].pWLoop;
const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
- Table *pTab = pItem->pTab;
+ Table *pTab = pItem->pSTab;
if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
pTab->tabFlags |= TF_MaybeReanalyze;
if( i>=1
@@ -168113,58 +170925,6 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
}
/*
-** Expression Node callback for sqlite3ExprCanReturnSubtype().
-**
-** Only a function call is able to return a subtype. So if the node
-** is not a function call, return WRC_Prune immediately.
-**
-** A function call is able to return a subtype if it has the
-** SQLITE_RESULT_SUBTYPE property.
-**
-** Assume that every function is able to pass-through a subtype from
-** one of its argument (using sqlite3_result_value()). Most functions
-** are not this way, but we don't have a mechanism to distinguish those
-** that are from those that are not, so assume they all work this way.
-** That means that if one of its arguments is another function and that
-** other function is able to return a subtype, then this function is
-** able to return a subtype.
-*/
-static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
- int n;
- FuncDef *pDef;
- sqlite3 *db;
- if( pExpr->op!=TK_FUNCTION ){
- return WRC_Prune;
- }
- assert( ExprUseXList(pExpr) );
- db = pWalker->pParse->db;
- n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
- pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
- if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
- pWalker->eCode = 1;
- return WRC_Prune;
- }
- return WRC_Continue;
-}
-
-/*
-** Return TRUE if expression pExpr is able to return a subtype.
-**
-** A TRUE return does not guarantee that a subtype will be returned.
-** It only indicates that a subtype return is possible. False positives
-** are acceptable as they only disable an optimization. False negatives,
-** on the other hand, can lead to incorrect answers.
-*/
-static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
- Walker w;
- memset(&w, 0, sizeof(w));
- w.pParse = pParse;
- w.xExprCallback = exprNodeCanReturnSubtype;
- sqlite3WalkExpr(&w, pExpr);
- return w.eCode;
-}
-
-/*
** The index pIdx is used by a query and contains one or more expressions.
** In other words pIdx is an index on an expression. iIdxCur is the cursor
** number for the index and iDataCur is the cursor number for the corresponding
@@ -168197,12 +170957,6 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
continue;
}
if( sqlite3ExprIsConstant(0,pExpr) ) continue;
- if( pExpr->op==TK_FUNCTION && sqlite3ExprCanReturnSubtype(pParse,pExpr) ){
- /* Functions that might set a subtype should not be replaced by the
- ** value taken from an expression index since the index omits the
- ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */
- continue;
- }
p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
if( p==0 ) break;
p->pIENext = pParse->pIdxEpr;
@@ -168245,8 +170999,8 @@ static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){
SrcItem *pItem = &pWInfo->pTabList->a[ii];
if( !pItem->fg.isCte
|| pItem->u2.pCteUse->eM10d!=M10d_Yes
- || NEVER(pItem->pSelect==0)
- || pItem->pSelect->pOrderBy==0
+ || NEVER(pItem->fg.isSubquery==0)
+ || pItem->u4.pSubq->pSelect->pOrderBy==0
){
pWInfo->revMask |= MASKBIT(ii);
}
@@ -168410,10 +171164,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** field (type Bitmask) it must be aligned on an 8-byte boundary on
** some architectures. Hence the ROUND8() below.
*/
- nByteWInfo = ROUND8P(sizeof(WhereInfo));
- if( nTabList>1 ){
- nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel));
- }
+ nByteWInfo = SZ_WHEREINFO(nTabList);
pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
if( db->mallocFailed ){
sqlite3DbFree(db, pWInfo);
@@ -168625,12 +171376,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( db->mallocFailed ) goto whereBeginError;
if( pWInfo->pOrderBy ){
whereInterstageHeuristic(pWInfo);
- wherePathSolver(pWInfo, pWInfo->nRowOut+1);
+ wherePathSolver(pWInfo, pWInfo->nRowOut<0 ? 1 : pWInfo->nRowOut+1);
if( db->mallocFailed ) goto whereBeginError;
}
/* TUNING: Assume that a DISTINCT clause on a subquery reduces
- ** the output size by a factor of 8 (LogEst -30).
+ ** the output size by a factor of 8 (LogEst -30). Search for
+ ** tag-20250414a to see other cases.
*/
if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){
WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n",
@@ -168649,7 +171401,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
assert( db->mallocFailed==0 );
#ifdef WHERETRACE_ENABLED
if( sqlite3WhereTrace ){
- sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
+ sqlite3DebugPrintf("---- Solution cost=%d, nRow=%d",
+ pWInfo->rTotalCost, pWInfo->nRowOut);
if( pWInfo->nOBSat>0 ){
sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask);
}
@@ -168736,15 +171489,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
- assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) );
+ assert( !(wsFlags&WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pSTab) );
if( bOnerow || (
0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
- && !IsVirtual(pTabList->a[0].pTab)
+ && !IsVirtual(pTabList->a[0].pSTab)
&& (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
&& OptimizationEnabled(db, SQLITE_OnePass)
)){
pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
- if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
+ if( HasRowid(pTabList->a[0].pSTab) && (wsFlags & WHERE_IDX_ONLY) ){
if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
bFordelete = OPFLAG_FORDELETE;
}
@@ -168762,7 +171515,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
SrcItem *pTabItem;
pTabItem = &pTabList->a[pLevel->iFrom];
- pTab = pTabItem->pTab;
+ pTab = pTabItem->pSTab;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
pLoop = pLevel->pWLoop;
if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){
@@ -168833,7 +171586,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
iIndexCur = pLevel->iTabCur;
op = 0;
}else if( pWInfo->eOnePass!=ONEPASS_OFF ){
- Index *pJ = pTabItem->pTab->pIndex;
+ Index *pJ = pTabItem->pSTab->pIndex;
iIndexCur = iAuxArg;
assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
while( ALWAYS(pJ) && pJ!=pIx ){
@@ -168900,7 +171653,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
pRJ->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
- assert( pTab==pTabItem->pTab );
+ assert( pTab==pTabItem->pSTab );
if( HasRowid(pTab) ){
KeyInfo *pInfo;
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
@@ -168939,13 +171692,18 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
wsFlags = pLevel->pWLoop->wsFlags;
pSrc = &pTabList->a[pLevel->iFrom];
if( pSrc->fg.isMaterialized ){
- if( pSrc->fg.isCorrelated ){
- sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
+ Subquery *pSubq;
+ int iOnce = 0;
+ assert( pSrc->fg.isSubquery );
+ pSubq = pSrc->u4.pSubq;
+ if( pSrc->fg.isCorrelated==0 ){
+ iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}else{
- int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
- sqlite3VdbeJumpHere(v, iOnce);
+ iOnce = 0;
}
+ sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub);
+ VdbeComment((v, "materialize %!S", pSrc));
+ if( iOnce ) sqlite3VdbeJumpHere(v, iOnce);
}
assert( pTabList == pWInfo->pTabList );
if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
@@ -169005,6 +171763,7 @@ whereBeginError:
){
if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return;
sqlite3VdbePrintOp(0, pc, pOp);
+ sqlite3ShowWhereTerm(0); /* So compiler won't complain about unused func */
}
#endif
@@ -169158,9 +171917,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
assert( pLevel->iTabCur==pSrc->iCursor );
if( pSrc->fg.viaCoroutine ){
int m, n;
- n = pSrc->regResult;
- assert( pSrc->pTab!=0 );
- m = pSrc->pTab->nCol;
+ assert( pSrc->fg.isSubquery );
+ n = pSrc->u4.pSubq->regResult;
+ assert( pSrc->pSTab!=0 );
+ m = pSrc->pSTab->nCol;
sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1);
}
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
@@ -169184,7 +171944,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeJumpHere(v, addr);
}
VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
- pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
+ pWInfo->pTabList->a[pLevel->iFrom].pSTab->zName));
}
assert( pWInfo->nLevel<=pTabList->nSrc );
@@ -169193,7 +171953,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
VdbeOp *pOp, *pLastOp;
Index *pIdx = 0;
SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
- Table *pTab = pTabItem->pTab;
+ Table *pTab = pTabItem->pSTab;
assert( pTab!=0 );
pLoop = pLevel->pWLoop;
@@ -169212,9 +171972,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
*/
if( pTabItem->fg.viaCoroutine ){
testcase( pParse->db->mallocFailed );
- assert( pTabItem->regResult>=0 );
+ assert( pTabItem->fg.isSubquery );
+ assert( pTabItem->u4.pSubq->regResult>=0 );
translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
- pTabItem->regResult, 0);
+ pTabItem->u4.pSubq->regResult, 0);
continue;
}
@@ -169302,14 +172063,28 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
pOp->p2 = x;
pOp->p1 = pLevel->iIdxCur;
OpcodeRewriteTrace(db, k, pOp);
- }else{
- /* Unable to translate the table reference into an index
- ** reference. Verify that this is harmless - that the
- ** table being referenced really is open.
- */
+ }else if( pLoop->wsFlags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){
if( pLoop->wsFlags & WHERE_IDX_ONLY ){
+ /* An error. pLoop is supposed to be a covering index loop,
+ ** and yet the VM code refers to a column of the table that
+ ** is not part of the index. */
sqlite3ErrorMsg(pParse, "internal query planner error");
pParse->rc = SQLITE_INTERNAL;
+ }else{
+ /* The WHERE_EXPRIDX flag is set by the planner when it is likely
+ ** that pLoop is a covering index loop, but it is not possible
+ ** to be 100% sure. In this case, any OP_Explain opcode
+ ** corresponding to this loop describes the index as a "COVERING
+ ** INDEX". But, pOp proves that pLoop is not actually a covering
+ ** index loop. So clear the WHERE_EXPRIDX flag and rewrite the
+ ** text that accompanies the OP_Explain opcode, if any. */
+ pLoop->wsFlags &= ~WHERE_EXPRIDX;
+ sqlite3WhereAddExplainText(pParse,
+ pLevel->addrBody-1,
+ pTabList,
+ pLevel,
+ pWInfo->wctrlFlags
+ );
}
}
}else if( pOp->opcode==OP_Rowid ){
@@ -170256,7 +173031,7 @@ static ExprList *exprListAppendList(
int iDummy;
Expr *pSub;
pSub = sqlite3ExprSkipCollateAndLikely(pDup);
- if( sqlite3ExprIsInteger(pSub, &iDummy) ){
+ if( sqlite3ExprIsInteger(pSub, &iDummy, 0) ){
pSub->op = TK_NULL;
pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
pSub->u.zToken = 0;
@@ -170342,7 +173117,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
p->pWhere = 0;
p->pGroupBy = 0;
p->pHaving = 0;
- p->selFlags &= ~SF_Aggregate;
+ p->selFlags &= ~(u32)SF_Aggregate;
p->selFlags |= SF_WinRewrite;
/* Create the ORDER BY clause for the sub-select. This is the concatenation
@@ -170424,9 +173199,10 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
** of sqlite3DbMallocRawNN() called from
** sqlite3SrcListAppend() */
- if( p->pSrc ){
+ if( p->pSrc==0 ){
+ sqlite3SelectDelete(db, pSub);
+ }else if( sqlite3SrcItemAttachSubquery(pParse, &p->pSrc->a[0], pSub, 0) ){
Table *pTab2;
- p->pSrc->a[0].pSelect = pSub;
p->pSrc->a[0].fg.isCorrelated = 1;
sqlite3SrcListAssignCursors(pParse, p->pSrc);
pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
@@ -170440,7 +173216,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
}else{
memcpy(pTab, pTab2, sizeof(Table));
pTab->tabFlags |= TF_Ephemeral;
- p->pSrc->a[0].pTab = pTab;
+ p->pSrc->a[0].pSTab = pTab;
pTab = pTab2;
memset(&w, 0, sizeof(w));
w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
@@ -170448,8 +173224,6 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
sqlite3WalkSelect(&w, pSub);
}
- }else{
- sqlite3SelectDelete(db, pSub);
}
if( db->mallocFailed ) rc = SQLITE_NOMEM;
@@ -170736,10 +173510,15 @@ SQLITE_PRIVATE int sqlite3WindowCompare(
** 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);
+ int nEphExpr;
+ Window *pMWin;
+ Vdbe *v;
+
+ assert( pSelect->pSrc->a[0].fg.isSubquery );
+ nEphExpr = pSelect->pSrc->a[0].u4.pSubq->pSelect->pEList->nExpr;
+ pMWin = pSelect->pWin;
+ v = sqlite3GetVdbe(pParse);
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
@@ -171013,6 +173792,7 @@ static void windowAggStep(
int regArg;
int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
int i;
+ int addrIf = 0;
assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );
@@ -171029,6 +173809,18 @@ static void windowAggStep(
}
regArg = reg;
+ if( pWin->pFilter ){
+ int regTmp;
+ assert( ExprUseXList(pWin->pOwner) );
+ 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( pMWin->regStartRowid==0
&& (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
&& (pWin->eStart!=TK_UNBOUNDED)
@@ -171048,25 +173840,13 @@ static void windowAggStep(
}
sqlite3VdbeJumpHere(v, addrIsNull);
}else if( pWin->regApp ){
+ assert( pWin->pFilter==0 );
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( ExprUseXList(pWin->pOwner) );
- 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 iOp = sqlite3VdbeCurrentAddr(v);
int iEnd;
@@ -171093,12 +173873,13 @@ static void windowAggStep(
sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep,
bInverse, regArg, pWin->regAccum);
sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, (u8)nArg);
+ sqlite3VdbeChangeP5(v, (u16)nArg);
if( pWin->bExprArgs ){
sqlite3ReleaseTempRange(pParse, regArg, nArg);
}
- if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
}
+
+ if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
}
}
@@ -172136,7 +174917,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
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 nInput = p->pSrc->a[0].pSTab->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: */
@@ -172477,6 +175258,11 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
/* #include "sqliteInt.h" */
/*
+** Verify that the pParse->isCreate field is set
+*/
+#define ASSERT_IS_CREATE assert(pParse->isCreate)
+
+/*
** Disable all error recovery processing in the parser push-down
** automaton.
*/
@@ -172526,12 +175312,23 @@ struct TrigEvent { int a; IdList * b; };
struct FrameBound { int eType; Expr *pExpr; };
/*
+** Generate a syntax error
+*/
+static void parserSyntaxError(Parse *pParse, Token *p){
+ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", p);
+}
+
+/*
** Disable lookaside memory allocation for objects that might be
** shared across database connections.
*/
static void disableLookaside(Parse *pParse){
sqlite3 *db = pParse->db;
pParse->disableLookaside++;
+#ifdef SQLITE_DEBUG
+ pParse->isCreate = 1;
+#endif
+ memset(&pParse->u1.cr, 0, sizeof(pParse->u1.cr));
DisableLookaside;
}
@@ -172733,132 +175530,132 @@ static void updateDeleteLimitError(
#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_MATERIALIZED 97
-#define TK_REINDEX 98
-#define TK_RENAME 99
-#define TK_CTIME_KW 100
-#define TK_ANY 101
-#define TK_BITAND 102
-#define TK_BITOR 103
-#define TK_LSHIFT 104
-#define TK_RSHIFT 105
-#define TK_PLUS 106
-#define TK_MINUS 107
-#define TK_STAR 108
-#define TK_SLASH 109
-#define TK_REM 110
-#define TK_CONCAT 111
-#define TK_PTR 112
-#define TK_COLLATE 113
-#define TK_BITNOT 114
-#define TK_ON 115
-#define TK_INDEXED 116
-#define TK_STRING 117
-#define TK_JOIN_KW 118
-#define TK_CONSTRAINT 119
-#define TK_DEFAULT 120
-#define TK_NULL 121
-#define TK_PRIMARY 122
-#define TK_UNIQUE 123
-#define TK_CHECK 124
-#define TK_REFERENCES 125
-#define TK_AUTOINCR 126
-#define TK_INSERT 127
-#define TK_DELETE 128
-#define TK_UPDATE 129
-#define TK_SET 130
-#define TK_DEFERRABLE 131
-#define TK_FOREIGN 132
-#define TK_DROP 133
-#define TK_UNION 134
-#define TK_ALL 135
-#define TK_EXCEPT 136
-#define TK_INTERSECT 137
-#define TK_SELECT 138
-#define TK_VALUES 139
-#define TK_DISTINCT 140
-#define TK_DOT 141
-#define TK_FROM 142
-#define TK_JOIN 143
-#define TK_USING 144
-#define TK_ORDER 145
-#define TK_GROUP 146
-#define TK_HAVING 147
-#define TK_LIMIT 148
-#define TK_WHERE 149
-#define TK_RETURNING 150
-#define TK_INTO 151
-#define TK_NOTHING 152
-#define TK_FLOAT 153
-#define TK_BLOB 154
-#define TK_INTEGER 155
-#define TK_VARIABLE 156
-#define TK_CASE 157
-#define TK_WHEN 158
-#define TK_THEN 159
-#define TK_ELSE 160
-#define TK_INDEX 161
-#define TK_ALTER 162
-#define TK_ADD 163
-#define TK_WINDOW 164
-#define TK_OVER 165
-#define TK_FILTER 166
-#define TK_COLUMN 167
-#define TK_AGG_FUNCTION 168
-#define TK_AGG_COLUMN 169
-#define TK_TRUEFALSE 170
-#define TK_ISNOT 171
+#define TK_ISNOT 46
+#define TK_MATCH 47
+#define TK_LIKE_KW 48
+#define TK_BETWEEN 49
+#define TK_IN 50
+#define TK_ISNULL 51
+#define TK_NOTNULL 52
+#define TK_NE 53
+#define TK_EQ 54
+#define TK_GT 55
+#define TK_LE 56
+#define TK_LT 57
+#define TK_GE 58
+#define TK_ESCAPE 59
+#define TK_ID 60
+#define TK_COLUMNKW 61
+#define TK_DO 62
+#define TK_FOR 63
+#define TK_IGNORE 64
+#define TK_INITIALLY 65
+#define TK_INSTEAD 66
+#define TK_NO 67
+#define TK_KEY 68
+#define TK_OF 69
+#define TK_OFFSET 70
+#define TK_PRAGMA 71
+#define TK_RAISE 72
+#define TK_RECURSIVE 73
+#define TK_REPLACE 74
+#define TK_RESTRICT 75
+#define TK_ROW 76
+#define TK_ROWS 77
+#define TK_TRIGGER 78
+#define TK_VACUUM 79
+#define TK_VIEW 80
+#define TK_VIRTUAL 81
+#define TK_WITH 82
+#define TK_NULLS 83
+#define TK_FIRST 84
+#define TK_LAST 85
+#define TK_CURRENT 86
+#define TK_FOLLOWING 87
+#define TK_PARTITION 88
+#define TK_PRECEDING 89
+#define TK_RANGE 90
+#define TK_UNBOUNDED 91
+#define TK_EXCLUDE 92
+#define TK_GROUPS 93
+#define TK_OTHERS 94
+#define TK_TIES 95
+#define TK_GENERATED 96
+#define TK_ALWAYS 97
+#define TK_MATERIALIZED 98
+#define TK_REINDEX 99
+#define TK_RENAME 100
+#define TK_CTIME_KW 101
+#define TK_ANY 102
+#define TK_BITAND 103
+#define TK_BITOR 104
+#define TK_LSHIFT 105
+#define TK_RSHIFT 106
+#define TK_PLUS 107
+#define TK_MINUS 108
+#define TK_STAR 109
+#define TK_SLASH 110
+#define TK_REM 111
+#define TK_CONCAT 112
+#define TK_PTR 113
+#define TK_COLLATE 114
+#define TK_BITNOT 115
+#define TK_ON 116
+#define TK_INDEXED 117
+#define TK_STRING 118
+#define TK_JOIN_KW 119
+#define TK_CONSTRAINT 120
+#define TK_DEFAULT 121
+#define TK_NULL 122
+#define TK_PRIMARY 123
+#define TK_UNIQUE 124
+#define TK_CHECK 125
+#define TK_REFERENCES 126
+#define TK_AUTOINCR 127
+#define TK_INSERT 128
+#define TK_DELETE 129
+#define TK_UPDATE 130
+#define TK_SET 131
+#define TK_DEFERRABLE 132
+#define TK_FOREIGN 133
+#define TK_DROP 134
+#define TK_UNION 135
+#define TK_ALL 136
+#define TK_EXCEPT 137
+#define TK_INTERSECT 138
+#define TK_SELECT 139
+#define TK_VALUES 140
+#define TK_DISTINCT 141
+#define TK_DOT 142
+#define TK_FROM 143
+#define TK_JOIN 144
+#define TK_USING 145
+#define TK_ORDER 146
+#define TK_GROUP 147
+#define TK_HAVING 148
+#define TK_LIMIT 149
+#define TK_WHERE 150
+#define TK_RETURNING 151
+#define TK_INTO 152
+#define TK_NOTHING 153
+#define TK_FLOAT 154
+#define TK_BLOB 155
+#define TK_INTEGER 156
+#define TK_VARIABLE 157
+#define TK_CASE 158
+#define TK_WHEN 159
+#define TK_THEN 160
+#define TK_ELSE 161
+#define TK_INDEX 162
+#define TK_ALTER 163
+#define TK_ADD 164
+#define TK_WINDOW 165
+#define TK_OVER 166
+#define TK_FILTER 167
+#define TK_COLUMN 168
+#define TK_AGG_FUNCTION 169
+#define TK_AGG_COLUMN 170
+#define TK_TRUEFALSE 171
#define TK_FUNCTION 172
#define TK_UPLUS 173
#define TK_UMINUS 174
@@ -172872,7 +175669,8 @@ static void updateDeleteLimitError(
#define TK_ERROR 182
#define TK_QNUMBER 183
#define TK_SPACE 184
-#define TK_ILLEGAL 185
+#define TK_COMMENT 185
+#define TK_ILLEGAL 186
#endif
/**************** End token definitions ***************************************/
@@ -172937,31 +175735,31 @@ static void updateDeleteLimitError(
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned short int
-#define YYNOCODE 322
+#define YYNOCODE 323
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 101
+#define YYWILDCARD 102
#define sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
sqlite3ParserTOKENTYPE yy0;
- ExprList* yy14;
- With* yy59;
- Cte* yy67;
- Upsert* yy122;
- IdList* yy132;
- int yy144;
- const char* yy168;
- SrcList* yy203;
- Window* yy211;
- OnOrUsing yy269;
- struct TrigEvent yy286;
- struct {int value; int mask;} yy383;
- u32 yy391;
- TriggerStep* yy427;
- Expr* yy454;
- u8 yy462;
- struct FrameBound yy509;
- Select* yy555;
+ u32 yy9;
+ struct TrigEvent yy28;
+ With* yy125;
+ IdList* yy204;
+ struct FrameBound yy205;
+ TriggerStep* yy319;
+ const char* yy342;
+ Cte* yy361;
+ ExprList* yy402;
+ Upsert* yy403;
+ OnOrUsing yy421;
+ u8 yy444;
+ struct {int value; int mask;} yy481;
+ Window* yy483;
+ int yy502;
+ SrcList* yy563;
+ Expr* yy590;
+ Select* yy637;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
@@ -172983,7 +175781,7 @@ typedef union {
#define YYNSTATE 583
#define YYNRULE 409
#define YYNRULE_WITH_ACTION 344
-#define YYNTOKEN 186
+#define YYNTOKEN 187
#define YY_MAX_SHIFT 582
#define YY_MIN_SHIFTREDUCE 845
#define YY_MAX_SHIFTREDUCE 1253
@@ -172992,8 +175790,8 @@ typedef union {
#define YY_NO_ACTION 1256
#define YY_MIN_REDUCE 1257
#define YY_MAX_REDUCE 1665
-#define YY_MIN_DSTRCTR 205
-#define YY_MAX_DSTRCTR 319
+#define YY_MIN_DSTRCTR 206
+#define YY_MAX_DSTRCTR 320
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
@@ -173076,569 +175874,582 @@ typedef union {
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (2142)
+#define YY_ACTTAB_COUNT (2207)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 576, 128, 125, 232, 1622, 549, 576, 1290, 1281, 576,
- /* 10 */ 328, 576, 1300, 212, 576, 128, 125, 232, 578, 412,
- /* 20 */ 578, 391, 1542, 51, 51, 523, 405, 1293, 529, 51,
- /* 30 */ 51, 983, 51, 51, 81, 81, 1107, 61, 61, 984,
- /* 40 */ 1107, 1292, 380, 135, 136, 90, 1228, 1228, 1063, 1066,
- /* 50 */ 1053, 1053, 133, 133, 134, 134, 134, 134, 1577, 412,
- /* 60 */ 287, 287, 7, 287, 287, 422, 1050, 1050, 1064, 1067,
- /* 70 */ 289, 556, 492, 573, 524, 561, 573, 497, 561, 482,
- /* 80 */ 530, 262, 229, 135, 136, 90, 1228, 1228, 1063, 1066,
- /* 90 */ 1053, 1053, 133, 133, 134, 134, 134, 134, 128, 125,
- /* 100 */ 232, 1506, 132, 132, 132, 132, 131, 131, 130, 130,
- /* 110 */ 130, 129, 126, 450, 1204, 1255, 1, 1, 582, 2,
- /* 120 */ 1259, 1571, 420, 1582, 379, 320, 1174, 153, 1174, 1584,
- /* 130 */ 412, 378, 1582, 543, 1341, 330, 111, 570, 570, 570,
- /* 140 */ 293, 1054, 132, 132, 132, 132, 131, 131, 130, 130,
- /* 150 */ 130, 129, 126, 450, 135, 136, 90, 1228, 1228, 1063,
- /* 160 */ 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, 287,
- /* 170 */ 287, 1204, 1205, 1204, 255, 287, 287, 510, 507, 506,
- /* 180 */ 137, 455, 573, 212, 561, 447, 446, 505, 573, 1616,
- /* 190 */ 561, 134, 134, 134, 134, 127, 400, 243, 132, 132,
- /* 200 */ 132, 132, 131, 131, 130, 130, 130, 129, 126, 450,
- /* 210 */ 282, 471, 345, 132, 132, 132, 132, 131, 131, 130,
- /* 220 */ 130, 130, 129, 126, 450, 574, 155, 936, 936, 454,
- /* 230 */ 227, 521, 1236, 412, 1236, 134, 134, 134, 134, 132,
- /* 240 */ 132, 132, 132, 131, 131, 130, 130, 130, 129, 126,
- /* 250 */ 450, 130, 130, 130, 129, 126, 450, 135, 136, 90,
- /* 260 */ 1228, 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134,
- /* 270 */ 134, 134, 128, 125, 232, 450, 576, 412, 397, 1249,
- /* 280 */ 180, 92, 93, 132, 132, 132, 132, 131, 131, 130,
- /* 290 */ 130, 130, 129, 126, 450, 381, 387, 1204, 383, 81,
- /* 300 */ 81, 135, 136, 90, 1228, 1228, 1063, 1066, 1053, 1053,
- /* 310 */ 133, 133, 134, 134, 134, 134, 132, 132, 132, 132,
- /* 320 */ 131, 131, 130, 130, 130, 129, 126, 450, 131, 131,
- /* 330 */ 130, 130, 130, 129, 126, 450, 556, 1204, 302, 319,
- /* 340 */ 567, 121, 568, 480, 4, 555, 1149, 1657, 1628, 1657,
- /* 350 */ 45, 128, 125, 232, 1204, 1205, 1204, 1250, 571, 1169,
- /* 360 */ 132, 132, 132, 132, 131, 131, 130, 130, 130, 129,
- /* 370 */ 126, 450, 1169, 287, 287, 1169, 1019, 576, 422, 1019,
- /* 380 */ 412, 451, 1602, 582, 2, 1259, 573, 44, 561, 95,
- /* 390 */ 320, 110, 153, 565, 1204, 1205, 1204, 522, 522, 1341,
- /* 400 */ 81, 81, 7, 44, 135, 136, 90, 1228, 1228, 1063,
- /* 410 */ 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, 295,
- /* 420 */ 1149, 1658, 1040, 1658, 1204, 1147, 319, 567, 119, 119,
- /* 430 */ 343, 466, 331, 343, 287, 287, 120, 556, 451, 577,
- /* 440 */ 451, 1169, 1169, 1028, 319, 567, 438, 573, 210, 561,
- /* 450 */ 1339, 1451, 546, 531, 1169, 1169, 1598, 1169, 1169, 416,
- /* 460 */ 319, 567, 243, 132, 132, 132, 132, 131, 131, 130,
- /* 470 */ 130, 130, 129, 126, 450, 1028, 1028, 1030, 1031, 35,
- /* 480 */ 44, 1204, 1205, 1204, 472, 287, 287, 1328, 412, 1307,
- /* 490 */ 372, 1595, 359, 225, 454, 1204, 195, 1328, 573, 1147,
- /* 500 */ 561, 1333, 1333, 274, 576, 1188, 576, 340, 46, 196,
- /* 510 */ 537, 217, 135, 136, 90, 1228, 1228, 1063, 1066, 1053,
- /* 520 */ 1053, 133, 133, 134, 134, 134, 134, 19, 19, 19,
- /* 530 */ 19, 412, 581, 1204, 1259, 511, 1204, 319, 567, 320,
- /* 540 */ 944, 153, 425, 491, 430, 943, 1204, 488, 1341, 1450,
- /* 550 */ 532, 1277, 1204, 1205, 1204, 135, 136, 90, 1228, 1228,
- /* 560 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134,
- /* 570 */ 575, 132, 132, 132, 132, 131, 131, 130, 130, 130,
- /* 580 */ 129, 126, 450, 287, 287, 528, 287, 287, 372, 1595,
- /* 590 */ 1204, 1205, 1204, 1204, 1205, 1204, 573, 486, 561, 573,
- /* 600 */ 889, 561, 412, 1204, 1205, 1204, 886, 40, 22, 22,
- /* 610 */ 220, 243, 525, 1449, 132, 132, 132, 132, 131, 131,
- /* 620 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228,
- /* 630 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134,
- /* 640 */ 134, 412, 180, 454, 1204, 879, 255, 287, 287, 510,
- /* 650 */ 507, 506, 372, 1595, 1568, 1331, 1331, 576, 889, 505,
- /* 660 */ 573, 44, 561, 559, 1207, 135, 136, 90, 1228, 1228,
- /* 670 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134,
- /* 680 */ 81, 81, 422, 576, 377, 132, 132, 132, 132, 131,
- /* 690 */ 131, 130, 130, 130, 129, 126, 450, 297, 287, 287,
- /* 700 */ 460, 1204, 1205, 1204, 1204, 534, 19, 19, 448, 448,
- /* 710 */ 448, 573, 412, 561, 230, 436, 1187, 535, 319, 567,
- /* 720 */ 363, 432, 1207, 1435, 132, 132, 132, 132, 131, 131,
- /* 730 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228,
- /* 740 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134,
- /* 750 */ 134, 412, 211, 949, 1169, 1041, 1110, 1110, 494, 547,
- /* 760 */ 547, 1204, 1205, 1204, 7, 539, 1570, 1169, 376, 576,
- /* 770 */ 1169, 5, 1204, 486, 3, 135, 136, 90, 1228, 1228,
- /* 780 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134,
- /* 790 */ 576, 513, 19, 19, 427, 132, 132, 132, 132, 131,
- /* 800 */ 131, 130, 130, 130, 129, 126, 450, 305, 1204, 433,
- /* 810 */ 225, 1204, 385, 19, 19, 273, 290, 371, 516, 366,
- /* 820 */ 515, 260, 412, 538, 1568, 549, 1024, 362, 437, 1204,
- /* 830 */ 1205, 1204, 902, 1552, 132, 132, 132, 132, 131, 131,
- /* 840 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228,
- /* 850 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134,
- /* 860 */ 134, 412, 1435, 514, 1281, 1204, 1205, 1204, 1204, 1205,
- /* 870 */ 1204, 903, 48, 342, 1568, 1568, 1279, 1627, 1568, 911,
- /* 880 */ 576, 129, 126, 450, 110, 135, 136, 90, 1228, 1228,
- /* 890 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134,
- /* 900 */ 265, 576, 459, 19, 19, 132, 132, 132, 132, 131,
- /* 910 */ 131, 130, 130, 130, 129, 126, 450, 1345, 204, 576,
- /* 920 */ 459, 458, 50, 47, 19, 19, 49, 434, 1105, 573,
- /* 930 */ 497, 561, 412, 428, 108, 1224, 1569, 1554, 376, 205,
- /* 940 */ 550, 550, 81, 81, 132, 132, 132, 132, 131, 131,
- /* 950 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228,
- /* 960 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134,
- /* 970 */ 134, 480, 576, 1204, 576, 1541, 412, 1435, 969, 315,
- /* 980 */ 1659, 398, 284, 497, 969, 893, 1569, 1569, 376, 376,
- /* 990 */ 1569, 461, 376, 1224, 459, 80, 80, 81, 81, 497,
- /* 1000 */ 374, 114, 90, 1228, 1228, 1063, 1066, 1053, 1053, 133,
- /* 1010 */ 133, 134, 134, 134, 134, 132, 132, 132, 132, 131,
- /* 1020 */ 131, 130, 130, 130, 129, 126, 450, 1204, 1505, 576,
- /* 1030 */ 1204, 1205, 1204, 1366, 316, 486, 281, 281, 497, 431,
- /* 1040 */ 557, 288, 288, 402, 1340, 471, 345, 298, 429, 573,
- /* 1050 */ 576, 561, 81, 81, 573, 374, 561, 971, 386, 132,
- /* 1060 */ 132, 132, 132, 131, 131, 130, 130, 130, 129, 126,
- /* 1070 */ 450, 231, 117, 81, 81, 287, 287, 231, 287, 287,
- /* 1080 */ 576, 1511, 576, 1336, 1204, 1205, 1204, 139, 573, 556,
- /* 1090 */ 561, 573, 412, 561, 441, 456, 969, 213, 558, 1511,
- /* 1100 */ 1513, 1550, 969, 143, 143, 145, 145, 1368, 314, 478,
- /* 1110 */ 444, 970, 412, 850, 851, 852, 135, 136, 90, 1228,
- /* 1120 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134,
- /* 1130 */ 134, 357, 412, 397, 1148, 304, 135, 136, 90, 1228,
- /* 1140 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134,
- /* 1150 */ 134, 1575, 323, 6, 862, 7, 135, 124, 90, 1228,
- /* 1160 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134,
- /* 1170 */ 134, 409, 408, 1511, 212, 132, 132, 132, 132, 131,
- /* 1180 */ 131, 130, 130, 130, 129, 126, 450, 411, 118, 1204,
- /* 1190 */ 116, 10, 352, 265, 355, 132, 132, 132, 132, 131,
- /* 1200 */ 131, 130, 130, 130, 129, 126, 450, 576, 324, 306,
- /* 1210 */ 576, 306, 1250, 469, 158, 132, 132, 132, 132, 131,
- /* 1220 */ 131, 130, 130, 130, 129, 126, 450, 207, 1224, 1126,
- /* 1230 */ 65, 65, 470, 66, 66, 412, 447, 446, 882, 531,
- /* 1240 */ 335, 258, 257, 256, 1127, 1233, 1204, 1205, 1204, 327,
- /* 1250 */ 1235, 874, 159, 576, 16, 480, 1085, 1040, 1234, 1128,
- /* 1260 */ 136, 90, 1228, 1228, 1063, 1066, 1053, 1053, 133, 133,
- /* 1270 */ 134, 134, 134, 134, 1029, 576, 81, 81, 1028, 1040,
- /* 1280 */ 922, 576, 463, 1236, 576, 1236, 1224, 502, 107, 1435,
- /* 1290 */ 923, 6, 576, 410, 1498, 882, 1029, 480, 21, 21,
- /* 1300 */ 1028, 332, 1380, 334, 53, 53, 497, 81, 81, 874,
- /* 1310 */ 1028, 1028, 1030, 445, 259, 19, 19, 533, 132, 132,
- /* 1320 */ 132, 132, 131, 131, 130, 130, 130, 129, 126, 450,
- /* 1330 */ 551, 301, 1028, 1028, 1030, 107, 532, 545, 121, 568,
- /* 1340 */ 1188, 4, 1126, 1576, 449, 576, 462, 7, 1282, 418,
- /* 1350 */ 462, 350, 1435, 576, 518, 571, 544, 1127, 121, 568,
- /* 1360 */ 442, 4, 1188, 464, 533, 1180, 1223, 9, 67, 67,
- /* 1370 */ 487, 576, 1128, 303, 410, 571, 54, 54, 451, 576,
- /* 1380 */ 123, 944, 576, 417, 576, 333, 943, 1379, 576, 236,
- /* 1390 */ 565, 576, 1574, 564, 68, 68, 7, 576, 451, 362,
- /* 1400 */ 419, 182, 69, 69, 541, 70, 70, 71, 71, 540,
- /* 1410 */ 565, 72, 72, 484, 55, 55, 473, 1180, 296, 1040,
- /* 1420 */ 56, 56, 296, 493, 541, 119, 119, 410, 1573, 542,
- /* 1430 */ 569, 418, 7, 120, 1244, 451, 577, 451, 465, 1040,
- /* 1440 */ 1028, 576, 1557, 552, 476, 119, 119, 527, 259, 121,
- /* 1450 */ 568, 240, 4, 120, 576, 451, 577, 451, 576, 477,
- /* 1460 */ 1028, 576, 156, 576, 57, 57, 571, 576, 286, 229,
- /* 1470 */ 410, 336, 1028, 1028, 1030, 1031, 35, 59, 59, 219,
- /* 1480 */ 983, 60, 60, 220, 73, 73, 74, 74, 984, 451,
- /* 1490 */ 75, 75, 1028, 1028, 1030, 1031, 35, 96, 216, 291,
- /* 1500 */ 552, 565, 1188, 318, 395, 395, 394, 276, 392, 576,
- /* 1510 */ 485, 859, 474, 1311, 410, 541, 576, 417, 1530, 1144,
- /* 1520 */ 540, 399, 1188, 292, 237, 1153, 326, 38, 23, 576,
- /* 1530 */ 1040, 576, 20, 20, 325, 299, 119, 119, 164, 76,
- /* 1540 */ 76, 1529, 121, 568, 120, 4, 451, 577, 451, 203,
- /* 1550 */ 576, 1028, 141, 141, 142, 142, 576, 322, 39, 571,
- /* 1560 */ 341, 1021, 110, 264, 239, 901, 900, 423, 242, 908,
- /* 1570 */ 909, 370, 173, 77, 77, 43, 479, 1310, 264, 62,
- /* 1580 */ 62, 369, 451, 1028, 1028, 1030, 1031, 35, 1601, 1192,
- /* 1590 */ 453, 1092, 238, 291, 565, 163, 1309, 110, 395, 395,
- /* 1600 */ 394, 276, 392, 986, 987, 859, 481, 346, 264, 110,
- /* 1610 */ 1032, 489, 576, 1188, 503, 1088, 261, 261, 237, 576,
- /* 1620 */ 326, 121, 568, 1040, 4, 347, 1376, 413, 325, 119,
- /* 1630 */ 119, 948, 319, 567, 351, 78, 78, 120, 571, 451,
- /* 1640 */ 577, 451, 79, 79, 1028, 354, 356, 576, 360, 1092,
- /* 1650 */ 110, 576, 974, 942, 264, 123, 457, 358, 239, 576,
- /* 1660 */ 519, 451, 939, 1104, 123, 1104, 173, 576, 1032, 43,
- /* 1670 */ 63, 63, 1324, 565, 168, 168, 1028, 1028, 1030, 1031,
- /* 1680 */ 35, 576, 169, 169, 1308, 872, 238, 157, 1589, 576,
- /* 1690 */ 86, 86, 365, 89, 568, 375, 4, 1103, 941, 1103,
- /* 1700 */ 123, 576, 1040, 1389, 64, 64, 1188, 1434, 119, 119,
- /* 1710 */ 571, 576, 82, 82, 563, 576, 120, 165, 451, 577,
- /* 1720 */ 451, 413, 1362, 1028, 144, 144, 319, 567, 576, 1374,
- /* 1730 */ 562, 498, 279, 451, 83, 83, 1439, 576, 166, 166,
- /* 1740 */ 576, 1289, 554, 576, 1280, 565, 576, 12, 576, 1268,
- /* 1750 */ 457, 146, 146, 1267, 576, 1028, 1028, 1030, 1031, 35,
- /* 1760 */ 140, 140, 1269, 167, 167, 1609, 160, 160, 1359, 150,
- /* 1770 */ 150, 149, 149, 311, 1040, 576, 312, 147, 147, 313,
- /* 1780 */ 119, 119, 222, 235, 576, 1188, 396, 576, 120, 576,
- /* 1790 */ 451, 577, 451, 1192, 453, 1028, 508, 291, 148, 148,
- /* 1800 */ 1421, 1612, 395, 395, 394, 276, 392, 85, 85, 859,
- /* 1810 */ 87, 87, 84, 84, 553, 576, 294, 576, 1426, 338,
- /* 1820 */ 339, 1425, 237, 300, 326, 1416, 1409, 1028, 1028, 1030,
- /* 1830 */ 1031, 35, 325, 344, 403, 483, 226, 1307, 52, 52,
- /* 1840 */ 58, 58, 368, 1371, 1502, 566, 1501, 121, 568, 221,
- /* 1850 */ 4, 208, 268, 209, 390, 1244, 1549, 1188, 1372, 1370,
- /* 1860 */ 1369, 1547, 239, 184, 571, 233, 421, 1241, 95, 218,
- /* 1870 */ 173, 1507, 193, 43, 91, 94, 178, 186, 467, 188,
- /* 1880 */ 468, 1422, 13, 189, 190, 191, 501, 451, 245, 108,
- /* 1890 */ 238, 401, 1428, 1427, 1430, 475, 404, 1496, 197, 565,
- /* 1900 */ 14, 490, 249, 101, 1518, 496, 349, 280, 251, 201,
- /* 1910 */ 353, 499, 252, 406, 1270, 253, 517, 1327, 1326, 435,
- /* 1920 */ 1325, 1318, 103, 893, 1296, 413, 227, 407, 1040, 1626,
- /* 1930 */ 319, 567, 1625, 1297, 119, 119, 439, 367, 1317, 1295,
- /* 1940 */ 1624, 526, 120, 440, 451, 577, 451, 1594, 309, 1028,
- /* 1950 */ 310, 373, 266, 267, 457, 1580, 1579, 443, 138, 1394,
- /* 1960 */ 552, 1393, 11, 1483, 384, 115, 317, 1350, 109, 536,
- /* 1970 */ 42, 579, 382, 214, 1349, 388, 1198, 389, 275, 277,
- /* 1980 */ 278, 1028, 1028, 1030, 1031, 35, 580, 1265, 414, 1260,
- /* 1990 */ 170, 415, 183, 1534, 1535, 1533, 171, 154, 307, 1532,
- /* 2000 */ 846, 223, 224, 88, 452, 215, 172, 321, 234, 1102,
- /* 2010 */ 152, 1188, 1100, 329, 185, 174, 1223, 925, 187, 241,
- /* 2020 */ 337, 244, 1116, 192, 175, 176, 424, 426, 97, 194,
- /* 2030 */ 98, 99, 100, 177, 1119, 1115, 246, 247, 161, 24,
- /* 2040 */ 248, 348, 1238, 264, 1108, 250, 495, 199, 198, 15,
- /* 2050 */ 861, 500, 369, 254, 504, 509, 512, 200, 102, 25,
- /* 2060 */ 179, 361, 26, 364, 104, 891, 308, 162, 105, 904,
- /* 2070 */ 520, 106, 1185, 1069, 1155, 17, 228, 27, 1154, 283,
- /* 2080 */ 285, 263, 978, 202, 972, 123, 28, 1175, 29, 30,
- /* 2090 */ 1179, 1171, 31, 1173, 1160, 41, 32, 206, 548, 33,
- /* 2100 */ 110, 1178, 1083, 8, 112, 1070, 113, 1068, 1072, 34,
- /* 2110 */ 1073, 560, 1125, 269, 1124, 270, 36, 18, 1194, 1033,
- /* 2120 */ 873, 151, 122, 37, 393, 271, 272, 572, 181, 1193,
- /* 2130 */ 1256, 1256, 1256, 935, 1256, 1256, 1256, 1256, 1256, 1256,
- /* 2140 */ 1256, 1617,
+ /* 0 */ 130, 127, 234, 282, 282, 1328, 576, 1307, 460, 289,
+ /* 10 */ 289, 576, 1622, 381, 576, 1328, 573, 576, 562, 413,
+ /* 20 */ 1300, 1542, 573, 481, 562, 524, 460, 459, 558, 82,
+ /* 30 */ 82, 983, 294, 375, 51, 51, 498, 61, 61, 984,
+ /* 40 */ 82, 82, 1577, 137, 138, 91, 7, 1228, 1228, 1063,
+ /* 50 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 413,
+ /* 60 */ 288, 288, 182, 288, 288, 481, 536, 288, 288, 130,
+ /* 70 */ 127, 234, 432, 573, 525, 562, 573, 557, 562, 1290,
+ /* 80 */ 573, 421, 562, 137, 138, 91, 559, 1228, 1228, 1063,
+ /* 90 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 296,
+ /* 100 */ 460, 398, 1249, 134, 134, 134, 134, 133, 133, 132,
+ /* 110 */ 132, 132, 131, 128, 451, 451, 1050, 1050, 1064, 1067,
+ /* 120 */ 1255, 1, 1, 582, 2, 1259, 581, 1174, 1259, 1174,
+ /* 130 */ 321, 413, 155, 321, 1584, 155, 379, 112, 481, 1341,
+ /* 140 */ 456, 299, 1341, 134, 134, 134, 134, 133, 133, 132,
+ /* 150 */ 132, 132, 131, 128, 451, 137, 138, 91, 498, 1228,
+ /* 160 */ 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136,
+ /* 170 */ 136, 1204, 862, 1281, 288, 288, 283, 288, 288, 523,
+ /* 180 */ 523, 1250, 139, 578, 7, 578, 1345, 573, 1169, 562,
+ /* 190 */ 573, 1054, 562, 136, 136, 136, 136, 129, 573, 547,
+ /* 200 */ 562, 1169, 245, 1541, 1169, 245, 133, 133, 132, 132,
+ /* 210 */ 132, 131, 128, 451, 302, 134, 134, 134, 134, 133,
+ /* 220 */ 133, 132, 132, 132, 131, 128, 451, 1575, 1204, 1205,
+ /* 230 */ 1204, 7, 470, 550, 455, 413, 550, 455, 130, 127,
+ /* 240 */ 234, 134, 134, 134, 134, 133, 133, 132, 132, 132,
+ /* 250 */ 131, 128, 451, 136, 136, 136, 136, 538, 483, 137,
+ /* 260 */ 138, 91, 1019, 1228, 1228, 1063, 1066, 1053, 1053, 135,
+ /* 270 */ 135, 136, 136, 136, 136, 1085, 576, 1204, 132, 132,
+ /* 280 */ 132, 131, 128, 451, 93, 214, 134, 134, 134, 134,
+ /* 290 */ 133, 133, 132, 132, 132, 131, 128, 451, 401, 19,
+ /* 300 */ 19, 134, 134, 134, 134, 133, 133, 132, 132, 132,
+ /* 310 */ 131, 128, 451, 1498, 426, 267, 344, 467, 332, 134,
+ /* 320 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128,
+ /* 330 */ 451, 1281, 576, 6, 1204, 1205, 1204, 257, 576, 413,
+ /* 340 */ 511, 508, 507, 1279, 94, 1019, 464, 1204, 551, 551,
+ /* 350 */ 506, 1224, 1571, 44, 38, 51, 51, 411, 576, 413,
+ /* 360 */ 45, 51, 51, 137, 138, 91, 530, 1228, 1228, 1063,
+ /* 370 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 398,
+ /* 380 */ 1148, 82, 82, 137, 138, 91, 39, 1228, 1228, 1063,
+ /* 390 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 344,
+ /* 400 */ 44, 288, 288, 375, 1204, 1205, 1204, 209, 1204, 1224,
+ /* 410 */ 320, 567, 471, 576, 573, 576, 562, 576, 316, 264,
+ /* 420 */ 231, 46, 160, 134, 134, 134, 134, 133, 133, 132,
+ /* 430 */ 132, 132, 131, 128, 451, 303, 82, 82, 82, 82,
+ /* 440 */ 82, 82, 442, 134, 134, 134, 134, 133, 133, 132,
+ /* 450 */ 132, 132, 131, 128, 451, 1582, 544, 320, 567, 1250,
+ /* 460 */ 874, 1582, 380, 382, 413, 1204, 1205, 1204, 360, 182,
+ /* 470 */ 288, 288, 1576, 557, 1339, 557, 7, 557, 1277, 472,
+ /* 480 */ 346, 526, 531, 573, 556, 562, 439, 1511, 137, 138,
+ /* 490 */ 91, 219, 1228, 1228, 1063, 1066, 1053, 1053, 135, 135,
+ /* 500 */ 136, 136, 136, 136, 465, 1511, 1513, 532, 413, 288,
+ /* 510 */ 288, 423, 512, 288, 288, 411, 288, 288, 874, 130,
+ /* 520 */ 127, 234, 573, 1107, 562, 1204, 573, 1107, 562, 573,
+ /* 530 */ 560, 562, 137, 138, 91, 1293, 1228, 1228, 1063, 1066,
+ /* 540 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 134, 134,
+ /* 550 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 451,
+ /* 560 */ 493, 503, 1292, 1204, 257, 288, 288, 511, 508, 507,
+ /* 570 */ 1204, 1628, 1169, 123, 568, 275, 4, 506, 573, 1511,
+ /* 580 */ 562, 331, 1204, 1205, 1204, 1169, 548, 548, 1169, 261,
+ /* 590 */ 571, 7, 134, 134, 134, 134, 133, 133, 132, 132,
+ /* 600 */ 132, 131, 128, 451, 108, 533, 130, 127, 234, 1204,
+ /* 610 */ 448, 447, 413, 1451, 452, 983, 886, 96, 1598, 1233,
+ /* 620 */ 1204, 1205, 1204, 984, 1235, 1450, 565, 1204, 1205, 1204,
+ /* 630 */ 229, 522, 1234, 534, 1333, 1333, 137, 138, 91, 1449,
+ /* 640 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136,
+ /* 650 */ 136, 136, 373, 1595, 971, 1040, 413, 1236, 418, 1236,
+ /* 660 */ 879, 121, 121, 948, 373, 1595, 1204, 1205, 1204, 122,
+ /* 670 */ 1204, 452, 577, 452, 363, 417, 1028, 882, 373, 1595,
+ /* 680 */ 137, 138, 91, 462, 1228, 1228, 1063, 1066, 1053, 1053,
+ /* 690 */ 135, 135, 136, 136, 136, 136, 134, 134, 134, 134,
+ /* 700 */ 133, 133, 132, 132, 132, 131, 128, 451, 1028, 1028,
+ /* 710 */ 1030, 1031, 35, 570, 570, 570, 197, 423, 1040, 198,
+ /* 720 */ 1204, 123, 568, 1204, 4, 320, 567, 1204, 1205, 1204,
+ /* 730 */ 40, 388, 576, 384, 882, 1029, 423, 1188, 571, 1028,
+ /* 740 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131,
+ /* 750 */ 128, 451, 529, 1568, 1204, 19, 19, 1204, 575, 492,
+ /* 760 */ 413, 157, 452, 489, 1187, 1331, 1331, 5, 1204, 949,
+ /* 770 */ 431, 1028, 1028, 1030, 565, 22, 22, 1204, 1205, 1204,
+ /* 780 */ 1204, 1205, 1204, 477, 137, 138, 91, 212, 1228, 1228,
+ /* 790 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136,
+ /* 800 */ 1188, 48, 111, 1040, 413, 1204, 213, 970, 1041, 121,
+ /* 810 */ 121, 1204, 1205, 1204, 1204, 1205, 1204, 122, 221, 452,
+ /* 820 */ 577, 452, 44, 487, 1028, 1204, 1205, 1204, 137, 138,
+ /* 830 */ 91, 378, 1228, 1228, 1063, 1066, 1053, 1053, 135, 135,
+ /* 840 */ 136, 136, 136, 136, 134, 134, 134, 134, 133, 133,
+ /* 850 */ 132, 132, 132, 131, 128, 451, 1028, 1028, 1030, 1031,
+ /* 860 */ 35, 461, 1204, 1205, 1204, 1569, 1040, 377, 214, 1149,
+ /* 870 */ 1657, 535, 1657, 437, 902, 320, 567, 1568, 364, 320,
+ /* 880 */ 567, 412, 329, 1029, 519, 1188, 3, 1028, 134, 134,
+ /* 890 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 451,
+ /* 900 */ 1659, 399, 1169, 307, 893, 307, 515, 576, 413, 214,
+ /* 910 */ 498, 944, 1024, 540, 903, 1169, 943, 392, 1169, 1028,
+ /* 920 */ 1028, 1030, 406, 298, 1204, 50, 1149, 1658, 413, 1658,
+ /* 930 */ 145, 145, 137, 138, 91, 293, 1228, 1228, 1063, 1066,
+ /* 940 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 1188, 1147,
+ /* 950 */ 514, 1568, 137, 138, 91, 1505, 1228, 1228, 1063, 1066,
+ /* 960 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 434, 323,
+ /* 970 */ 435, 539, 111, 1506, 274, 291, 372, 517, 367, 516,
+ /* 980 */ 262, 1204, 1205, 1204, 1574, 481, 363, 576, 7, 1569,
+ /* 990 */ 1568, 377, 134, 134, 134, 134, 133, 133, 132, 132,
+ /* 1000 */ 132, 131, 128, 451, 1568, 576, 1147, 576, 232, 576,
+ /* 1010 */ 19, 19, 134, 134, 134, 134, 133, 133, 132, 132,
+ /* 1020 */ 132, 131, 128, 451, 1169, 433, 576, 1207, 19, 19,
+ /* 1030 */ 19, 19, 19, 19, 1627, 576, 911, 1169, 47, 120,
+ /* 1040 */ 1169, 117, 413, 306, 498, 438, 1125, 206, 336, 19,
+ /* 1050 */ 19, 1435, 49, 449, 449, 449, 1368, 315, 81, 81,
+ /* 1060 */ 576, 304, 413, 1570, 207, 377, 137, 138, 91, 115,
+ /* 1070 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136,
+ /* 1080 */ 136, 136, 576, 82, 82, 1207, 137, 138, 91, 1340,
+ /* 1090 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136,
+ /* 1100 */ 136, 136, 1569, 386, 377, 82, 82, 463, 1126, 1552,
+ /* 1110 */ 333, 463, 335, 131, 128, 451, 1569, 161, 377, 16,
+ /* 1120 */ 317, 387, 428, 1127, 448, 447, 134, 134, 134, 134,
+ /* 1130 */ 133, 133, 132, 132, 132, 131, 128, 451, 1128, 576,
+ /* 1140 */ 1105, 10, 445, 267, 576, 1554, 134, 134, 134, 134,
+ /* 1150 */ 133, 133, 132, 132, 132, 131, 128, 451, 532, 576,
+ /* 1160 */ 922, 576, 19, 19, 576, 1573, 576, 147, 147, 7,
+ /* 1170 */ 923, 1236, 498, 1236, 576, 487, 413, 552, 285, 1224,
+ /* 1180 */ 969, 215, 82, 82, 66, 66, 1435, 67, 67, 21,
+ /* 1190 */ 21, 1110, 1110, 495, 334, 297, 413, 53, 53, 297,
+ /* 1200 */ 137, 138, 91, 119, 1228, 1228, 1063, 1066, 1053, 1053,
+ /* 1210 */ 135, 135, 136, 136, 136, 136, 413, 1336, 1311, 446,
+ /* 1220 */ 137, 138, 91, 227, 1228, 1228, 1063, 1066, 1053, 1053,
+ /* 1230 */ 135, 135, 136, 136, 136, 136, 574, 1224, 936, 936,
+ /* 1240 */ 137, 126, 91, 141, 1228, 1228, 1063, 1066, 1053, 1053,
+ /* 1250 */ 135, 135, 136, 136, 136, 136, 533, 429, 472, 346,
+ /* 1260 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131,
+ /* 1270 */ 128, 451, 576, 457, 233, 343, 1435, 403, 498, 1550,
+ /* 1280 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131,
+ /* 1290 */ 128, 451, 576, 324, 576, 82, 82, 487, 576, 969,
+ /* 1300 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131,
+ /* 1310 */ 128, 451, 288, 288, 546, 68, 68, 54, 54, 553,
+ /* 1320 */ 413, 69, 69, 351, 6, 573, 944, 562, 410, 409,
+ /* 1330 */ 1435, 943, 450, 545, 260, 259, 258, 576, 158, 576,
+ /* 1340 */ 413, 222, 1180, 479, 969, 138, 91, 430, 1228, 1228,
+ /* 1350 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136,
+ /* 1360 */ 70, 70, 71, 71, 576, 1126, 91, 576, 1228, 1228,
+ /* 1370 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136,
+ /* 1380 */ 1127, 166, 850, 851, 852, 1282, 419, 72, 72, 108,
+ /* 1390 */ 73, 73, 1310, 358, 1180, 1128, 576, 305, 576, 123,
+ /* 1400 */ 568, 494, 4, 488, 134, 134, 134, 134, 133, 133,
+ /* 1410 */ 132, 132, 132, 131, 128, 451, 571, 564, 534, 55,
+ /* 1420 */ 55, 56, 56, 576, 134, 134, 134, 134, 133, 133,
+ /* 1430 */ 132, 132, 132, 131, 128, 451, 576, 1104, 233, 1104,
+ /* 1440 */ 452, 1602, 582, 2, 1259, 576, 57, 57, 576, 321,
+ /* 1450 */ 576, 155, 565, 1435, 485, 353, 576, 356, 1341, 59,
+ /* 1460 */ 59, 576, 44, 969, 569, 419, 576, 238, 60, 60,
+ /* 1470 */ 261, 74, 74, 75, 75, 287, 231, 576, 1366, 76,
+ /* 1480 */ 76, 1040, 420, 184, 20, 20, 576, 121, 121, 77,
+ /* 1490 */ 77, 97, 218, 288, 288, 122, 125, 452, 577, 452,
+ /* 1500 */ 143, 143, 1028, 576, 520, 576, 573, 576, 562, 144,
+ /* 1510 */ 144, 474, 227, 1244, 478, 123, 568, 576, 4, 320,
+ /* 1520 */ 567, 245, 411, 576, 443, 411, 78, 78, 62, 62,
+ /* 1530 */ 79, 79, 571, 319, 1028, 1028, 1030, 1031, 35, 418,
+ /* 1540 */ 63, 63, 576, 290, 411, 9, 80, 80, 1144, 576,
+ /* 1550 */ 400, 576, 486, 455, 576, 1223, 452, 576, 325, 342,
+ /* 1560 */ 576, 111, 576, 1188, 242, 64, 64, 473, 565, 576,
+ /* 1570 */ 23, 576, 170, 170, 171, 171, 576, 87, 87, 328,
+ /* 1580 */ 65, 65, 542, 83, 83, 146, 146, 541, 123, 568,
+ /* 1590 */ 341, 4, 84, 84, 168, 168, 576, 1040, 576, 148,
+ /* 1600 */ 148, 576, 1380, 121, 121, 571, 1021, 576, 266, 576,
+ /* 1610 */ 424, 122, 576, 452, 577, 452, 576, 553, 1028, 142,
+ /* 1620 */ 142, 169, 169, 576, 162, 162, 528, 889, 371, 452,
+ /* 1630 */ 152, 152, 151, 151, 1379, 149, 149, 109, 370, 150,
+ /* 1640 */ 150, 565, 576, 480, 576, 266, 86, 86, 576, 1092,
+ /* 1650 */ 1028, 1028, 1030, 1031, 35, 542, 482, 576, 266, 466,
+ /* 1660 */ 543, 123, 568, 1616, 4, 88, 88, 85, 85, 475,
+ /* 1670 */ 1040, 52, 52, 222, 901, 900, 121, 121, 571, 1188,
+ /* 1680 */ 58, 58, 244, 1032, 122, 889, 452, 577, 452, 908,
+ /* 1690 */ 909, 1028, 300, 347, 504, 111, 263, 361, 165, 111,
+ /* 1700 */ 111, 1088, 452, 263, 974, 1153, 266, 1092, 986, 987,
+ /* 1710 */ 942, 939, 125, 125, 565, 1103, 872, 1103, 159, 941,
+ /* 1720 */ 1309, 125, 1557, 1028, 1028, 1030, 1031, 35, 542, 337,
+ /* 1730 */ 1530, 205, 1529, 541, 499, 1589, 490, 348, 1376, 352,
+ /* 1740 */ 355, 1032, 357, 1040, 359, 1324, 1308, 366, 563, 121,
+ /* 1750 */ 121, 376, 1188, 1389, 1434, 1362, 280, 122, 1374, 452,
+ /* 1760 */ 577, 452, 167, 1439, 1028, 1289, 1280, 1268, 1267, 1269,
+ /* 1770 */ 1609, 1359, 312, 313, 314, 397, 12, 237, 224, 1421,
+ /* 1780 */ 295, 1416, 1409, 1426, 339, 484, 340, 509, 1371, 1612,
+ /* 1790 */ 1372, 1425, 1244, 404, 301, 228, 1028, 1028, 1030, 1031,
+ /* 1800 */ 35, 1601, 1192, 454, 345, 1307, 292, 369, 1502, 1501,
+ /* 1810 */ 270, 396, 396, 395, 277, 393, 1370, 1369, 859, 1549,
+ /* 1820 */ 186, 123, 568, 235, 4, 1188, 391, 210, 211, 223,
+ /* 1830 */ 1547, 239, 1241, 327, 422, 96, 220, 195, 571, 180,
+ /* 1840 */ 188, 326, 468, 469, 190, 191, 502, 192, 193, 566,
+ /* 1850 */ 247, 109, 1430, 491, 199, 251, 102, 281, 402, 476,
+ /* 1860 */ 405, 1496, 452, 497, 253, 1422, 13, 1428, 14, 1427,
+ /* 1870 */ 203, 1507, 241, 500, 565, 354, 407, 92, 95, 1270,
+ /* 1880 */ 175, 254, 518, 43, 1327, 255, 1326, 1325, 436, 1518,
+ /* 1890 */ 350, 1318, 104, 229, 893, 1626, 440, 441, 1625, 408,
+ /* 1900 */ 240, 1296, 268, 1040, 310, 269, 1297, 527, 444, 121,
+ /* 1910 */ 121, 368, 1295, 1594, 1624, 311, 1394, 122, 1317, 452,
+ /* 1920 */ 577, 452, 374, 1580, 1028, 1393, 140, 553, 11, 90,
+ /* 1930 */ 568, 385, 4, 116, 318, 414, 1579, 110, 1483, 537,
+ /* 1940 */ 320, 567, 1350, 555, 42, 579, 571, 1349, 1198, 383,
+ /* 1950 */ 276, 390, 216, 389, 278, 279, 1028, 1028, 1030, 1031,
+ /* 1960 */ 35, 172, 580, 1265, 458, 1260, 415, 416, 185, 156,
+ /* 1970 */ 452, 1534, 1535, 173, 1533, 1532, 89, 308, 225, 226,
+ /* 1980 */ 846, 174, 565, 453, 217, 1188, 322, 236, 1102, 154,
+ /* 1990 */ 1100, 330, 187, 176, 1223, 243, 189, 925, 338, 246,
+ /* 2000 */ 1116, 194, 177, 425, 178, 427, 98, 196, 99, 100,
+ /* 2010 */ 101, 1040, 179, 1119, 1115, 248, 249, 121, 121, 163,
+ /* 2020 */ 24, 250, 349, 1238, 496, 122, 1108, 452, 577, 452,
+ /* 2030 */ 1192, 454, 1028, 266, 292, 200, 252, 201, 861, 396,
+ /* 2040 */ 396, 395, 277, 393, 15, 501, 859, 370, 292, 256,
+ /* 2050 */ 202, 554, 505, 396, 396, 395, 277, 393, 103, 239,
+ /* 2060 */ 859, 327, 25, 26, 1028, 1028, 1030, 1031, 35, 326,
+ /* 2070 */ 362, 510, 891, 239, 365, 327, 513, 904, 105, 309,
+ /* 2080 */ 164, 181, 27, 326, 106, 521, 107, 1185, 1069, 1155,
+ /* 2090 */ 17, 1154, 230, 1188, 284, 286, 265, 204, 125, 1171,
+ /* 2100 */ 241, 28, 978, 972, 29, 41, 1175, 1179, 175, 1173,
+ /* 2110 */ 30, 43, 31, 8, 241, 1178, 32, 1160, 208, 549,
+ /* 2120 */ 33, 111, 175, 1083, 1070, 43, 1068, 1072, 240, 113,
+ /* 2130 */ 114, 34, 561, 118, 1124, 271, 1073, 36, 18, 572,
+ /* 2140 */ 1033, 873, 240, 124, 37, 935, 272, 273, 1617, 183,
+ /* 2150 */ 153, 394, 1194, 1193, 1256, 1256, 1256, 1256, 1256, 1256,
+ /* 2160 */ 1256, 1256, 1256, 414, 1256, 1256, 1256, 1256, 320, 567,
+ /* 2170 */ 1256, 1256, 1256, 1256, 1256, 1256, 1256, 414, 1256, 1256,
+ /* 2180 */ 1256, 1256, 320, 567, 1256, 1256, 1256, 1256, 1256, 1256,
+ /* 2190 */ 1256, 1256, 458, 1256, 1256, 1256, 1256, 1256, 1256, 1256,
+ /* 2200 */ 1256, 1256, 1256, 1256, 1256, 1256, 458,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 194, 276, 277, 278, 216, 194, 194, 217, 194, 194,
- /* 10 */ 194, 194, 224, 194, 194, 276, 277, 278, 204, 19,
- /* 20 */ 206, 202, 297, 217, 218, 205, 207, 217, 205, 217,
- /* 30 */ 218, 31, 217, 218, 217, 218, 29, 217, 218, 39,
- /* 40 */ 33, 217, 220, 43, 44, 45, 46, 47, 48, 49,
- /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 312, 19,
- /* 60 */ 240, 241, 316, 240, 241, 194, 46, 47, 48, 49,
- /* 70 */ 22, 254, 65, 253, 254, 255, 253, 194, 255, 194,
- /* 80 */ 263, 258, 259, 43, 44, 45, 46, 47, 48, 49,
- /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 276, 277,
- /* 100 */ 278, 285, 102, 103, 104, 105, 106, 107, 108, 109,
- /* 110 */ 110, 111, 112, 113, 59, 186, 187, 188, 189, 190,
- /* 120 */ 191, 310, 239, 317, 318, 196, 86, 198, 88, 317,
- /* 130 */ 19, 319, 317, 318, 205, 264, 25, 211, 212, 213,
- /* 140 */ 205, 121, 102, 103, 104, 105, 106, 107, 108, 109,
- /* 150 */ 110, 111, 112, 113, 43, 44, 45, 46, 47, 48,
- /* 160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 240,
- /* 170 */ 241, 116, 117, 118, 119, 240, 241, 122, 123, 124,
- /* 180 */ 69, 298, 253, 194, 255, 106, 107, 132, 253, 141,
- /* 190 */ 255, 54, 55, 56, 57, 58, 207, 268, 102, 103,
- /* 200 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- /* 210 */ 214, 128, 129, 102, 103, 104, 105, 106, 107, 108,
- /* 220 */ 109, 110, 111, 112, 113, 134, 25, 136, 137, 300,
- /* 230 */ 165, 166, 153, 19, 155, 54, 55, 56, 57, 102,
- /* 240 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
- /* 250 */ 113, 108, 109, 110, 111, 112, 113, 43, 44, 45,
- /* 260 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
- /* 270 */ 56, 57, 276, 277, 278, 113, 194, 19, 22, 23,
- /* 280 */ 194, 67, 24, 102, 103, 104, 105, 106, 107, 108,
- /* 290 */ 109, 110, 111, 112, 113, 220, 250, 59, 252, 217,
- /* 300 */ 218, 43, 44, 45, 46, 47, 48, 49, 50, 51,
- /* 310 */ 52, 53, 54, 55, 56, 57, 102, 103, 104, 105,
- /* 320 */ 106, 107, 108, 109, 110, 111, 112, 113, 106, 107,
- /* 330 */ 108, 109, 110, 111, 112, 113, 254, 59, 205, 138,
- /* 340 */ 139, 19, 20, 194, 22, 263, 22, 23, 231, 25,
- /* 350 */ 72, 276, 277, 278, 116, 117, 118, 101, 36, 76,
- /* 360 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
- /* 370 */ 112, 113, 89, 240, 241, 92, 73, 194, 194, 73,
- /* 380 */ 19, 59, 188, 189, 190, 191, 253, 81, 255, 151,
- /* 390 */ 196, 25, 198, 71, 116, 117, 118, 311, 312, 205,
- /* 400 */ 217, 218, 316, 81, 43, 44, 45, 46, 47, 48,
- /* 410 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 270,
- /* 420 */ 22, 23, 100, 25, 59, 101, 138, 139, 106, 107,
- /* 430 */ 127, 128, 129, 127, 240, 241, 114, 254, 116, 117,
- /* 440 */ 118, 76, 76, 121, 138, 139, 263, 253, 264, 255,
- /* 450 */ 205, 275, 87, 19, 89, 89, 194, 92, 92, 199,
- /* 460 */ 138, 139, 268, 102, 103, 104, 105, 106, 107, 108,
- /* 470 */ 109, 110, 111, 112, 113, 153, 154, 155, 156, 157,
- /* 480 */ 81, 116, 117, 118, 129, 240, 241, 224, 19, 226,
- /* 490 */ 314, 315, 23, 25, 300, 59, 22, 234, 253, 101,
- /* 500 */ 255, 236, 237, 26, 194, 183, 194, 152, 72, 22,
- /* 510 */ 145, 150, 43, 44, 45, 46, 47, 48, 49, 50,
- /* 520 */ 51, 52, 53, 54, 55, 56, 57, 217, 218, 217,
- /* 530 */ 218, 19, 189, 59, 191, 23, 59, 138, 139, 196,
- /* 540 */ 135, 198, 232, 283, 232, 140, 59, 287, 205, 275,
- /* 550 */ 116, 205, 116, 117, 118, 43, 44, 45, 46, 47,
- /* 560 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 570 */ 194, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- /* 580 */ 111, 112, 113, 240, 241, 194, 240, 241, 314, 315,
- /* 590 */ 116, 117, 118, 116, 117, 118, 253, 194, 255, 253,
- /* 600 */ 59, 255, 19, 116, 117, 118, 23, 22, 217, 218,
- /* 610 */ 142, 268, 205, 275, 102, 103, 104, 105, 106, 107,
- /* 620 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
- /* 630 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 640 */ 57, 19, 194, 300, 59, 23, 119, 240, 241, 122,
- /* 650 */ 123, 124, 314, 315, 194, 236, 237, 194, 117, 132,
- /* 660 */ 253, 81, 255, 205, 59, 43, 44, 45, 46, 47,
- /* 670 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 680 */ 217, 218, 194, 194, 194, 102, 103, 104, 105, 106,
- /* 690 */ 107, 108, 109, 110, 111, 112, 113, 294, 240, 241,
- /* 700 */ 120, 116, 117, 118, 59, 194, 217, 218, 211, 212,
- /* 710 */ 213, 253, 19, 255, 194, 19, 23, 254, 138, 139,
- /* 720 */ 24, 232, 117, 194, 102, 103, 104, 105, 106, 107,
- /* 730 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
- /* 740 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 750 */ 57, 19, 264, 108, 76, 23, 127, 128, 129, 311,
- /* 760 */ 312, 116, 117, 118, 316, 87, 306, 89, 308, 194,
- /* 770 */ 92, 22, 59, 194, 22, 43, 44, 45, 46, 47,
- /* 780 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 790 */ 194, 95, 217, 218, 265, 102, 103, 104, 105, 106,
- /* 800 */ 107, 108, 109, 110, 111, 112, 113, 232, 59, 113,
- /* 810 */ 25, 59, 194, 217, 218, 119, 120, 121, 122, 123,
- /* 820 */ 124, 125, 19, 145, 194, 194, 23, 131, 232, 116,
- /* 830 */ 117, 118, 35, 194, 102, 103, 104, 105, 106, 107,
- /* 840 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
- /* 850 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 860 */ 57, 19, 194, 66, 194, 116, 117, 118, 116, 117,
- /* 870 */ 118, 74, 242, 294, 194, 194, 206, 23, 194, 25,
- /* 880 */ 194, 111, 112, 113, 25, 43, 44, 45, 46, 47,
- /* 890 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- /* 900 */ 24, 194, 194, 217, 218, 102, 103, 104, 105, 106,
- /* 910 */ 107, 108, 109, 110, 111, 112, 113, 241, 232, 194,
- /* 920 */ 212, 213, 242, 242, 217, 218, 242, 130, 11, 253,
- /* 930 */ 194, 255, 19, 265, 149, 59, 306, 194, 308, 232,
- /* 940 */ 309, 310, 217, 218, 102, 103, 104, 105, 106, 107,
- /* 950 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
- /* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 970 */ 57, 194, 194, 59, 194, 239, 19, 194, 25, 254,
- /* 980 */ 303, 304, 23, 194, 25, 126, 306, 306, 308, 308,
- /* 990 */ 306, 271, 308, 117, 286, 217, 218, 217, 218, 194,
- /* 1000 */ 194, 159, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 1010 */ 53, 54, 55, 56, 57, 102, 103, 104, 105, 106,
- /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 59, 239, 194,
- /* 1030 */ 116, 117, 118, 260, 254, 194, 240, 241, 194, 233,
- /* 1040 */ 205, 240, 241, 205, 239, 128, 129, 270, 265, 253,
- /* 1050 */ 194, 255, 217, 218, 253, 194, 255, 143, 280, 102,
- /* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
- /* 1070 */ 113, 118, 159, 217, 218, 240, 241, 118, 240, 241,
- /* 1080 */ 194, 194, 194, 239, 116, 117, 118, 22, 253, 254,
- /* 1090 */ 255, 253, 19, 255, 233, 194, 143, 24, 263, 212,
- /* 1100 */ 213, 194, 143, 217, 218, 217, 218, 261, 262, 271,
- /* 1110 */ 254, 143, 19, 7, 8, 9, 43, 44, 45, 46,
- /* 1120 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1130 */ 57, 16, 19, 22, 23, 294, 43, 44, 45, 46,
- /* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1150 */ 57, 312, 194, 214, 21, 316, 43, 44, 45, 46,
- /* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1170 */ 57, 106, 107, 286, 194, 102, 103, 104, 105, 106,
- /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 207, 158, 59,
- /* 1190 */ 160, 22, 77, 24, 79, 102, 103, 104, 105, 106,
- /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 194, 194, 229,
- /* 1210 */ 194, 231, 101, 80, 22, 102, 103, 104, 105, 106,
- /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 288, 59, 12,
- /* 1230 */ 217, 218, 293, 217, 218, 19, 106, 107, 59, 19,
- /* 1240 */ 16, 127, 128, 129, 27, 115, 116, 117, 118, 194,
- /* 1250 */ 120, 59, 22, 194, 24, 194, 123, 100, 128, 42,
- /* 1260 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 1270 */ 54, 55, 56, 57, 117, 194, 217, 218, 121, 100,
- /* 1280 */ 63, 194, 245, 153, 194, 155, 117, 19, 115, 194,
- /* 1290 */ 73, 214, 194, 256, 161, 116, 117, 194, 217, 218,
- /* 1300 */ 121, 77, 194, 79, 217, 218, 194, 217, 218, 117,
- /* 1310 */ 153, 154, 155, 254, 46, 217, 218, 144, 102, 103,
- /* 1320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- /* 1330 */ 232, 270, 153, 154, 155, 115, 116, 66, 19, 20,
- /* 1340 */ 183, 22, 12, 312, 254, 194, 262, 316, 209, 210,
- /* 1350 */ 266, 239, 194, 194, 108, 36, 85, 27, 19, 20,
- /* 1360 */ 265, 22, 183, 245, 144, 94, 25, 48, 217, 218,
- /* 1370 */ 293, 194, 42, 270, 256, 36, 217, 218, 59, 194,
- /* 1380 */ 25, 135, 194, 115, 194, 161, 140, 194, 194, 15,
- /* 1390 */ 71, 194, 312, 63, 217, 218, 316, 194, 59, 131,
- /* 1400 */ 301, 302, 217, 218, 85, 217, 218, 217, 218, 90,
- /* 1410 */ 71, 217, 218, 19, 217, 218, 245, 146, 262, 100,
- /* 1420 */ 217, 218, 266, 265, 85, 106, 107, 256, 312, 90,
- /* 1430 */ 209, 210, 316, 114, 60, 116, 117, 118, 194, 100,
- /* 1440 */ 121, 194, 194, 145, 115, 106, 107, 19, 46, 19,
- /* 1450 */ 20, 24, 22, 114, 194, 116, 117, 118, 194, 245,
- /* 1460 */ 121, 194, 164, 194, 217, 218, 36, 194, 258, 259,
- /* 1470 */ 256, 194, 153, 154, 155, 156, 157, 217, 218, 150,
- /* 1480 */ 31, 217, 218, 142, 217, 218, 217, 218, 39, 59,
- /* 1490 */ 217, 218, 153, 154, 155, 156, 157, 149, 150, 5,
- /* 1500 */ 145, 71, 183, 245, 10, 11, 12, 13, 14, 194,
- /* 1510 */ 116, 17, 129, 227, 256, 85, 194, 115, 194, 23,
- /* 1520 */ 90, 25, 183, 99, 30, 97, 32, 22, 22, 194,
- /* 1530 */ 100, 194, 217, 218, 40, 152, 106, 107, 23, 217,
- /* 1540 */ 218, 194, 19, 20, 114, 22, 116, 117, 118, 257,
- /* 1550 */ 194, 121, 217, 218, 217, 218, 194, 133, 53, 36,
- /* 1560 */ 23, 23, 25, 25, 70, 120, 121, 61, 141, 7,
- /* 1570 */ 8, 121, 78, 217, 218, 81, 23, 227, 25, 217,
- /* 1580 */ 218, 131, 59, 153, 154, 155, 156, 157, 0, 1,
- /* 1590 */ 2, 59, 98, 5, 71, 23, 227, 25, 10, 11,
- /* 1600 */ 12, 13, 14, 83, 84, 17, 23, 23, 25, 25,
- /* 1610 */ 59, 194, 194, 183, 23, 23, 25, 25, 30, 194,
- /* 1620 */ 32, 19, 20, 100, 22, 194, 194, 133, 40, 106,
- /* 1630 */ 107, 108, 138, 139, 194, 217, 218, 114, 36, 116,
- /* 1640 */ 117, 118, 217, 218, 121, 194, 194, 194, 23, 117,
- /* 1650 */ 25, 194, 23, 23, 25, 25, 162, 194, 70, 194,
- /* 1660 */ 145, 59, 23, 153, 25, 155, 78, 194, 117, 81,
- /* 1670 */ 217, 218, 194, 71, 217, 218, 153, 154, 155, 156,
- /* 1680 */ 157, 194, 217, 218, 194, 23, 98, 25, 321, 194,
- /* 1690 */ 217, 218, 194, 19, 20, 194, 22, 153, 23, 155,
- /* 1700 */ 25, 194, 100, 194, 217, 218, 183, 194, 106, 107,
- /* 1710 */ 36, 194, 217, 218, 237, 194, 114, 243, 116, 117,
- /* 1720 */ 118, 133, 194, 121, 217, 218, 138, 139, 194, 194,
- /* 1730 */ 194, 290, 289, 59, 217, 218, 194, 194, 217, 218,
- /* 1740 */ 194, 194, 140, 194, 194, 71, 194, 244, 194, 194,
- /* 1750 */ 162, 217, 218, 194, 194, 153, 154, 155, 156, 157,
- /* 1760 */ 217, 218, 194, 217, 218, 194, 217, 218, 257, 217,
- /* 1770 */ 218, 217, 218, 257, 100, 194, 257, 217, 218, 257,
- /* 1780 */ 106, 107, 215, 299, 194, 183, 192, 194, 114, 194,
- /* 1790 */ 116, 117, 118, 1, 2, 121, 221, 5, 217, 218,
- /* 1800 */ 273, 197, 10, 11, 12, 13, 14, 217, 218, 17,
- /* 1810 */ 217, 218, 217, 218, 140, 194, 246, 194, 273, 295,
- /* 1820 */ 247, 273, 30, 247, 32, 269, 269, 153, 154, 155,
- /* 1830 */ 156, 157, 40, 246, 273, 295, 230, 226, 217, 218,
- /* 1840 */ 217, 218, 220, 261, 220, 282, 220, 19, 20, 244,
- /* 1850 */ 22, 250, 141, 250, 246, 60, 201, 183, 261, 261,
- /* 1860 */ 261, 201, 70, 299, 36, 299, 201, 38, 151, 150,
- /* 1870 */ 78, 285, 22, 81, 296, 296, 43, 235, 18, 238,
- /* 1880 */ 201, 274, 272, 238, 238, 238, 18, 59, 200, 149,
- /* 1890 */ 98, 247, 274, 274, 235, 247, 247, 247, 235, 71,
- /* 1900 */ 272, 201, 200, 158, 292, 62, 291, 201, 200, 22,
- /* 1910 */ 201, 222, 200, 222, 201, 200, 115, 219, 219, 64,
- /* 1920 */ 219, 228, 22, 126, 221, 133, 165, 222, 100, 225,
- /* 1930 */ 138, 139, 225, 219, 106, 107, 24, 219, 228, 219,
- /* 1940 */ 219, 307, 114, 113, 116, 117, 118, 315, 284, 121,
- /* 1950 */ 284, 222, 201, 91, 162, 320, 320, 82, 148, 267,
- /* 1960 */ 145, 267, 22, 279, 201, 158, 281, 251, 147, 146,
- /* 1970 */ 25, 203, 250, 249, 251, 248, 13, 247, 195, 195,
- /* 1980 */ 6, 153, 154, 155, 156, 157, 193, 193, 305, 193,
- /* 1990 */ 208, 305, 302, 214, 214, 214, 208, 223, 223, 214,
- /* 2000 */ 4, 215, 215, 214, 3, 22, 208, 163, 15, 23,
- /* 2010 */ 16, 183, 23, 139, 151, 130, 25, 20, 142, 24,
- /* 2020 */ 16, 144, 1, 142, 130, 130, 61, 37, 53, 151,
- /* 2030 */ 53, 53, 53, 130, 116, 1, 34, 141, 5, 22,
- /* 2040 */ 115, 161, 75, 25, 68, 141, 41, 115, 68, 24,
- /* 2050 */ 20, 19, 131, 125, 67, 67, 96, 22, 22, 22,
- /* 2060 */ 37, 23, 22, 24, 22, 59, 67, 23, 149, 28,
- /* 2070 */ 22, 25, 23, 23, 23, 22, 141, 34, 97, 23,
- /* 2080 */ 23, 34, 116, 22, 143, 25, 34, 75, 34, 34,
- /* 2090 */ 75, 88, 34, 86, 23, 22, 34, 25, 24, 34,
- /* 2100 */ 25, 93, 23, 44, 142, 23, 142, 23, 23, 22,
- /* 2110 */ 11, 25, 23, 25, 23, 22, 22, 22, 1, 23,
- /* 2120 */ 23, 23, 22, 22, 15, 141, 141, 25, 25, 1,
- /* 2130 */ 322, 322, 322, 135, 322, 322, 322, 322, 322, 322,
- /* 2140 */ 322, 141, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2150 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2160 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2170 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2180 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2190 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2200 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2210 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2220 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2230 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2240 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2250 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2260 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2270 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2280 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2290 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2300 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2310 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322,
- /* 2320 */ 322, 322, 322, 322, 322, 322, 322, 322,
+ /* 0 */ 277, 278, 279, 241, 242, 225, 195, 227, 195, 241,
+ /* 10 */ 242, 195, 217, 221, 195, 235, 254, 195, 256, 19,
+ /* 20 */ 225, 298, 254, 195, 256, 206, 213, 214, 206, 218,
+ /* 30 */ 219, 31, 206, 195, 218, 219, 195, 218, 219, 39,
+ /* 40 */ 218, 219, 313, 43, 44, 45, 317, 47, 48, 49,
+ /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 19,
+ /* 60 */ 241, 242, 195, 241, 242, 195, 255, 241, 242, 277,
+ /* 70 */ 278, 279, 234, 254, 255, 256, 254, 255, 256, 218,
+ /* 80 */ 254, 240, 256, 43, 44, 45, 264, 47, 48, 49,
+ /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 271,
+ /* 100 */ 287, 22, 23, 103, 104, 105, 106, 107, 108, 109,
+ /* 110 */ 110, 111, 112, 113, 114, 114, 47, 48, 49, 50,
+ /* 120 */ 187, 188, 189, 190, 191, 192, 190, 87, 192, 89,
+ /* 130 */ 197, 19, 199, 197, 318, 199, 320, 25, 195, 206,
+ /* 140 */ 299, 271, 206, 103, 104, 105, 106, 107, 108, 109,
+ /* 150 */ 110, 111, 112, 113, 114, 43, 44, 45, 195, 47,
+ /* 160 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ /* 170 */ 58, 60, 21, 195, 241, 242, 215, 241, 242, 312,
+ /* 180 */ 313, 102, 70, 205, 317, 207, 242, 254, 77, 256,
+ /* 190 */ 254, 122, 256, 55, 56, 57, 58, 59, 254, 88,
+ /* 200 */ 256, 90, 269, 240, 93, 269, 107, 108, 109, 110,
+ /* 210 */ 111, 112, 113, 114, 271, 103, 104, 105, 106, 107,
+ /* 220 */ 108, 109, 110, 111, 112, 113, 114, 313, 117, 118,
+ /* 230 */ 119, 317, 81, 195, 301, 19, 195, 301, 277, 278,
+ /* 240 */ 279, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ /* 250 */ 112, 113, 114, 55, 56, 57, 58, 146, 195, 43,
+ /* 260 */ 44, 45, 74, 47, 48, 49, 50, 51, 52, 53,
+ /* 270 */ 54, 55, 56, 57, 58, 124, 195, 60, 109, 110,
+ /* 280 */ 111, 112, 113, 114, 68, 195, 103, 104, 105, 106,
+ /* 290 */ 107, 108, 109, 110, 111, 112, 113, 114, 208, 218,
+ /* 300 */ 219, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ /* 310 */ 112, 113, 114, 162, 233, 24, 128, 129, 130, 103,
+ /* 320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+ /* 330 */ 114, 195, 195, 215, 117, 118, 119, 120, 195, 19,
+ /* 340 */ 123, 124, 125, 207, 24, 74, 246, 60, 310, 311,
+ /* 350 */ 133, 60, 311, 82, 22, 218, 219, 257, 195, 19,
+ /* 360 */ 73, 218, 219, 43, 44, 45, 206, 47, 48, 49,
+ /* 370 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 22,
+ /* 380 */ 23, 218, 219, 43, 44, 45, 54, 47, 48, 49,
+ /* 390 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 128,
+ /* 400 */ 82, 241, 242, 195, 117, 118, 119, 289, 60, 118,
+ /* 410 */ 139, 140, 294, 195, 254, 195, 256, 195, 255, 259,
+ /* 420 */ 260, 73, 22, 103, 104, 105, 106, 107, 108, 109,
+ /* 430 */ 110, 111, 112, 113, 114, 206, 218, 219, 218, 219,
+ /* 440 */ 218, 219, 234, 103, 104, 105, 106, 107, 108, 109,
+ /* 450 */ 110, 111, 112, 113, 114, 318, 319, 139, 140, 102,
+ /* 460 */ 60, 318, 319, 221, 19, 117, 118, 119, 23, 195,
+ /* 470 */ 241, 242, 313, 255, 206, 255, 317, 255, 206, 129,
+ /* 480 */ 130, 206, 264, 254, 264, 256, 264, 195, 43, 44,
+ /* 490 */ 45, 151, 47, 48, 49, 50, 51, 52, 53, 54,
+ /* 500 */ 55, 56, 57, 58, 246, 213, 214, 19, 19, 241,
+ /* 510 */ 242, 195, 23, 241, 242, 257, 241, 242, 118, 277,
+ /* 520 */ 278, 279, 254, 29, 256, 60, 254, 33, 256, 254,
+ /* 530 */ 206, 256, 43, 44, 45, 218, 47, 48, 49, 50,
+ /* 540 */ 51, 52, 53, 54, 55, 56, 57, 58, 103, 104,
+ /* 550 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ /* 560 */ 66, 19, 218, 60, 120, 241, 242, 123, 124, 125,
+ /* 570 */ 60, 232, 77, 19, 20, 26, 22, 133, 254, 287,
+ /* 580 */ 256, 265, 117, 118, 119, 90, 312, 313, 93, 47,
+ /* 590 */ 36, 317, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 600 */ 111, 112, 113, 114, 116, 117, 277, 278, 279, 60,
+ /* 610 */ 107, 108, 19, 276, 60, 31, 23, 152, 195, 116,
+ /* 620 */ 117, 118, 119, 39, 121, 276, 72, 117, 118, 119,
+ /* 630 */ 166, 167, 129, 145, 237, 238, 43, 44, 45, 276,
+ /* 640 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 650 */ 57, 58, 315, 316, 144, 101, 19, 154, 116, 156,
+ /* 660 */ 23, 107, 108, 109, 315, 316, 117, 118, 119, 115,
+ /* 670 */ 60, 117, 118, 119, 132, 200, 122, 60, 315, 316,
+ /* 680 */ 43, 44, 45, 272, 47, 48, 49, 50, 51, 52,
+ /* 690 */ 53, 54, 55, 56, 57, 58, 103, 104, 105, 106,
+ /* 700 */ 107, 108, 109, 110, 111, 112, 113, 114, 154, 155,
+ /* 710 */ 156, 157, 158, 212, 213, 214, 22, 195, 101, 22,
+ /* 720 */ 60, 19, 20, 60, 22, 139, 140, 117, 118, 119,
+ /* 730 */ 22, 251, 195, 253, 117, 118, 195, 183, 36, 122,
+ /* 740 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ /* 750 */ 113, 114, 195, 195, 60, 218, 219, 60, 195, 284,
+ /* 760 */ 19, 25, 60, 288, 23, 237, 238, 22, 60, 109,
+ /* 770 */ 233, 154, 155, 156, 72, 218, 219, 117, 118, 119,
+ /* 780 */ 117, 118, 119, 116, 43, 44, 45, 265, 47, 48,
+ /* 790 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ /* 800 */ 183, 243, 25, 101, 19, 60, 265, 144, 23, 107,
+ /* 810 */ 108, 117, 118, 119, 117, 118, 119, 115, 151, 117,
+ /* 820 */ 118, 119, 82, 195, 122, 117, 118, 119, 43, 44,
+ /* 830 */ 45, 195, 47, 48, 49, 50, 51, 52, 53, 54,
+ /* 840 */ 55, 56, 57, 58, 103, 104, 105, 106, 107, 108,
+ /* 850 */ 109, 110, 111, 112, 113, 114, 154, 155, 156, 157,
+ /* 860 */ 158, 121, 117, 118, 119, 307, 101, 309, 195, 22,
+ /* 870 */ 23, 195, 25, 19, 35, 139, 140, 195, 24, 139,
+ /* 880 */ 140, 208, 195, 118, 109, 183, 22, 122, 103, 104,
+ /* 890 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ /* 900 */ 304, 305, 77, 230, 127, 232, 67, 195, 19, 195,
+ /* 910 */ 195, 136, 23, 88, 75, 90, 141, 203, 93, 154,
+ /* 920 */ 155, 156, 208, 295, 60, 243, 22, 23, 19, 25,
+ /* 930 */ 218, 219, 43, 44, 45, 100, 47, 48, 49, 50,
+ /* 940 */ 51, 52, 53, 54, 55, 56, 57, 58, 183, 102,
+ /* 950 */ 96, 195, 43, 44, 45, 240, 47, 48, 49, 50,
+ /* 960 */ 51, 52, 53, 54, 55, 56, 57, 58, 114, 134,
+ /* 970 */ 131, 146, 25, 286, 120, 121, 122, 123, 124, 125,
+ /* 980 */ 126, 117, 118, 119, 313, 195, 132, 195, 317, 307,
+ /* 990 */ 195, 309, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 1000 */ 111, 112, 113, 114, 195, 195, 102, 195, 195, 195,
+ /* 1010 */ 218, 219, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 1020 */ 111, 112, 113, 114, 77, 233, 195, 60, 218, 219,
+ /* 1030 */ 218, 219, 218, 219, 23, 195, 25, 90, 243, 159,
+ /* 1040 */ 93, 161, 19, 233, 195, 233, 23, 233, 16, 218,
+ /* 1050 */ 219, 195, 243, 212, 213, 214, 262, 263, 218, 219,
+ /* 1060 */ 195, 271, 19, 307, 233, 309, 43, 44, 45, 160,
+ /* 1070 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 1080 */ 57, 58, 195, 218, 219, 118, 43, 44, 45, 240,
+ /* 1090 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 1100 */ 57, 58, 307, 195, 309, 218, 219, 263, 12, 195,
+ /* 1110 */ 78, 267, 80, 112, 113, 114, 307, 22, 309, 24,
+ /* 1120 */ 255, 281, 266, 27, 107, 108, 103, 104, 105, 106,
+ /* 1130 */ 107, 108, 109, 110, 111, 112, 113, 114, 42, 195,
+ /* 1140 */ 11, 22, 255, 24, 195, 195, 103, 104, 105, 106,
+ /* 1150 */ 107, 108, 109, 110, 111, 112, 113, 114, 19, 195,
+ /* 1160 */ 64, 195, 218, 219, 195, 313, 195, 218, 219, 317,
+ /* 1170 */ 74, 154, 195, 156, 195, 195, 19, 233, 23, 60,
+ /* 1180 */ 25, 24, 218, 219, 218, 219, 195, 218, 219, 218,
+ /* 1190 */ 219, 128, 129, 130, 162, 263, 19, 218, 219, 267,
+ /* 1200 */ 43, 44, 45, 160, 47, 48, 49, 50, 51, 52,
+ /* 1210 */ 53, 54, 55, 56, 57, 58, 19, 240, 228, 255,
+ /* 1220 */ 43, 44, 45, 25, 47, 48, 49, 50, 51, 52,
+ /* 1230 */ 53, 54, 55, 56, 57, 58, 135, 118, 137, 138,
+ /* 1240 */ 43, 44, 45, 22, 47, 48, 49, 50, 51, 52,
+ /* 1250 */ 53, 54, 55, 56, 57, 58, 117, 266, 129, 130,
+ /* 1260 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ /* 1270 */ 113, 114, 195, 195, 119, 295, 195, 206, 195, 195,
+ /* 1280 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ /* 1290 */ 113, 114, 195, 195, 195, 218, 219, 195, 195, 144,
+ /* 1300 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
+ /* 1310 */ 113, 114, 241, 242, 67, 218, 219, 218, 219, 146,
+ /* 1320 */ 19, 218, 219, 240, 215, 254, 136, 256, 107, 108,
+ /* 1330 */ 195, 141, 255, 86, 128, 129, 130, 195, 165, 195,
+ /* 1340 */ 19, 143, 95, 272, 25, 44, 45, 266, 47, 48,
+ /* 1350 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ /* 1360 */ 218, 219, 218, 219, 195, 12, 45, 195, 47, 48,
+ /* 1370 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ /* 1380 */ 27, 23, 7, 8, 9, 210, 211, 218, 219, 116,
+ /* 1390 */ 218, 219, 228, 16, 147, 42, 195, 295, 195, 19,
+ /* 1400 */ 20, 266, 22, 294, 103, 104, 105, 106, 107, 108,
+ /* 1410 */ 109, 110, 111, 112, 113, 114, 36, 64, 145, 218,
+ /* 1420 */ 219, 218, 219, 195, 103, 104, 105, 106, 107, 108,
+ /* 1430 */ 109, 110, 111, 112, 113, 114, 195, 154, 119, 156,
+ /* 1440 */ 60, 189, 190, 191, 192, 195, 218, 219, 195, 197,
+ /* 1450 */ 195, 199, 72, 195, 19, 78, 195, 80, 206, 218,
+ /* 1460 */ 219, 195, 82, 144, 210, 211, 195, 15, 218, 219,
+ /* 1470 */ 47, 218, 219, 218, 219, 259, 260, 195, 261, 218,
+ /* 1480 */ 219, 101, 302, 303, 218, 219, 195, 107, 108, 218,
+ /* 1490 */ 219, 150, 151, 241, 242, 115, 25, 117, 118, 119,
+ /* 1500 */ 218, 219, 122, 195, 146, 195, 254, 195, 256, 218,
+ /* 1510 */ 219, 246, 25, 61, 246, 19, 20, 195, 22, 139,
+ /* 1520 */ 140, 269, 257, 195, 266, 257, 218, 219, 218, 219,
+ /* 1530 */ 218, 219, 36, 246, 154, 155, 156, 157, 158, 116,
+ /* 1540 */ 218, 219, 195, 22, 257, 49, 218, 219, 23, 195,
+ /* 1550 */ 25, 195, 117, 301, 195, 25, 60, 195, 195, 23,
+ /* 1560 */ 195, 25, 195, 183, 24, 218, 219, 130, 72, 195,
+ /* 1570 */ 22, 195, 218, 219, 218, 219, 195, 218, 219, 195,
+ /* 1580 */ 218, 219, 86, 218, 219, 218, 219, 91, 19, 20,
+ /* 1590 */ 153, 22, 218, 219, 218, 219, 195, 101, 195, 218,
+ /* 1600 */ 219, 195, 195, 107, 108, 36, 23, 195, 25, 195,
+ /* 1610 */ 62, 115, 195, 117, 118, 119, 195, 146, 122, 218,
+ /* 1620 */ 219, 218, 219, 195, 218, 219, 19, 60, 122, 60,
+ /* 1630 */ 218, 219, 218, 219, 195, 218, 219, 150, 132, 218,
+ /* 1640 */ 219, 72, 195, 23, 195, 25, 218, 219, 195, 60,
+ /* 1650 */ 154, 155, 156, 157, 158, 86, 23, 195, 25, 195,
+ /* 1660 */ 91, 19, 20, 142, 22, 218, 219, 218, 219, 130,
+ /* 1670 */ 101, 218, 219, 143, 121, 122, 107, 108, 36, 183,
+ /* 1680 */ 218, 219, 142, 60, 115, 118, 117, 118, 119, 7,
+ /* 1690 */ 8, 122, 153, 23, 23, 25, 25, 23, 23, 25,
+ /* 1700 */ 25, 23, 60, 25, 23, 98, 25, 118, 84, 85,
+ /* 1710 */ 23, 23, 25, 25, 72, 154, 23, 156, 25, 23,
+ /* 1720 */ 228, 25, 195, 154, 155, 156, 157, 158, 86, 195,
+ /* 1730 */ 195, 258, 195, 91, 291, 322, 195, 195, 195, 195,
+ /* 1740 */ 195, 118, 195, 101, 195, 195, 195, 195, 238, 107,
+ /* 1750 */ 108, 195, 183, 195, 195, 195, 290, 115, 195, 117,
+ /* 1760 */ 118, 119, 244, 195, 122, 195, 195, 195, 195, 195,
+ /* 1770 */ 195, 258, 258, 258, 258, 193, 245, 300, 216, 274,
+ /* 1780 */ 247, 270, 270, 274, 296, 296, 248, 222, 262, 198,
+ /* 1790 */ 262, 274, 61, 274, 248, 231, 154, 155, 156, 157,
+ /* 1800 */ 158, 0, 1, 2, 247, 227, 5, 221, 221, 221,
+ /* 1810 */ 142, 10, 11, 12, 13, 14, 262, 262, 17, 202,
+ /* 1820 */ 300, 19, 20, 300, 22, 183, 247, 251, 251, 245,
+ /* 1830 */ 202, 30, 38, 32, 202, 152, 151, 22, 36, 43,
+ /* 1840 */ 236, 40, 18, 202, 239, 239, 18, 239, 239, 283,
+ /* 1850 */ 201, 150, 236, 202, 236, 201, 159, 202, 248, 248,
+ /* 1860 */ 248, 248, 60, 63, 201, 275, 273, 275, 273, 275,
+ /* 1870 */ 22, 286, 71, 223, 72, 202, 223, 297, 297, 202,
+ /* 1880 */ 79, 201, 116, 82, 220, 201, 220, 220, 65, 293,
+ /* 1890 */ 292, 229, 22, 166, 127, 226, 24, 114, 226, 223,
+ /* 1900 */ 99, 222, 202, 101, 285, 92, 220, 308, 83, 107,
+ /* 1910 */ 108, 220, 220, 316, 220, 285, 268, 115, 229, 117,
+ /* 1920 */ 118, 119, 223, 321, 122, 268, 149, 146, 22, 19,
+ /* 1930 */ 20, 202, 22, 159, 282, 134, 321, 148, 280, 147,
+ /* 1940 */ 139, 140, 252, 141, 25, 204, 36, 252, 13, 251,
+ /* 1950 */ 196, 248, 250, 249, 196, 6, 154, 155, 156, 157,
+ /* 1960 */ 158, 209, 194, 194, 163, 194, 306, 306, 303, 224,
+ /* 1970 */ 60, 215, 215, 209, 215, 215, 215, 224, 216, 216,
+ /* 1980 */ 4, 209, 72, 3, 22, 183, 164, 15, 23, 16,
+ /* 1990 */ 23, 140, 152, 131, 25, 24, 143, 20, 16, 145,
+ /* 2000 */ 1, 143, 131, 62, 131, 37, 54, 152, 54, 54,
+ /* 2010 */ 54, 101, 131, 117, 1, 34, 142, 107, 108, 5,
+ /* 2020 */ 22, 116, 162, 76, 41, 115, 69, 117, 118, 119,
+ /* 2030 */ 1, 2, 122, 25, 5, 69, 142, 116, 20, 10,
+ /* 2040 */ 11, 12, 13, 14, 24, 19, 17, 132, 5, 126,
+ /* 2050 */ 22, 141, 68, 10, 11, 12, 13, 14, 22, 30,
+ /* 2060 */ 17, 32, 22, 22, 154, 155, 156, 157, 158, 40,
+ /* 2070 */ 23, 68, 60, 30, 24, 32, 97, 28, 22, 68,
+ /* 2080 */ 23, 37, 34, 40, 150, 22, 25, 23, 23, 23,
+ /* 2090 */ 22, 98, 142, 183, 23, 23, 34, 22, 25, 89,
+ /* 2100 */ 71, 34, 117, 144, 34, 22, 76, 76, 79, 87,
+ /* 2110 */ 34, 82, 34, 44, 71, 94, 34, 23, 25, 24,
+ /* 2120 */ 34, 25, 79, 23, 23, 82, 23, 23, 99, 143,
+ /* 2130 */ 143, 22, 25, 25, 23, 22, 11, 22, 22, 25,
+ /* 2140 */ 23, 23, 99, 22, 22, 136, 142, 142, 142, 25,
+ /* 2150 */ 23, 15, 1, 1, 323, 323, 323, 323, 323, 323,
+ /* 2160 */ 323, 323, 323, 134, 323, 323, 323, 323, 139, 140,
+ /* 2170 */ 323, 323, 323, 323, 323, 323, 323, 134, 323, 323,
+ /* 2180 */ 323, 323, 139, 140, 323, 323, 323, 323, 323, 323,
+ /* 2190 */ 323, 323, 163, 323, 323, 323, 323, 323, 323, 323,
+ /* 2200 */ 323, 323, 323, 323, 323, 323, 163, 323, 323, 323,
+ /* 2210 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2220 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2230 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2240 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2250 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2260 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2270 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2280 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2290 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2300 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2310 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2320 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2330 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323,
+ /* 2340 */ 323, 187, 187, 187, 187, 187, 187, 187, 187, 187,
+ /* 2350 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
+ /* 2360 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
+ /* 2370 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
+ /* 2380 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
+ /* 2390 */ 187, 187, 187, 187,
};
#define YY_SHIFT_COUNT (582)
#define YY_SHIFT_MIN (0)
-#define YY_SHIFT_MAX (2128)
+#define YY_SHIFT_MAX (2152)
static const unsigned short int yy_shift_ofst[] = {
- /* 0 */ 1792, 1588, 1494, 322, 322, 399, 306, 1319, 1339, 1430,
- /* 10 */ 1828, 1828, 1828, 580, 399, 399, 399, 399, 399, 0,
- /* 20 */ 0, 214, 1093, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
- /* 30 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1130, 1130,
- /* 40 */ 365, 365, 55, 278, 436, 713, 713, 201, 201, 201,
- /* 50 */ 201, 40, 111, 258, 361, 469, 512, 583, 622, 693,
- /* 60 */ 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, 1093,
- /* 70 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
- /* 80 */ 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1523, 1602,
- /* 90 */ 1674, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
- /* 100 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
- /* 110 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
- /* 120 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
- /* 130 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828,
- /* 140 */ 137, 181, 181, 181, 181, 181, 181, 181, 96, 222,
- /* 150 */ 143, 477, 713, 1133, 1268, 713, 713, 79, 79, 713,
- /* 160 */ 770, 83, 65, 65, 65, 288, 162, 162, 2142, 2142,
- /* 170 */ 696, 696, 696, 238, 474, 474, 474, 474, 1217, 1217,
- /* 180 */ 678, 477, 324, 398, 713, 713, 713, 713, 713, 713,
- /* 190 */ 713, 713, 713, 713, 713, 713, 713, 713, 713, 713,
- /* 200 */ 713, 713, 713, 1220, 366, 366, 713, 917, 283, 283,
- /* 210 */ 434, 434, 605, 605, 1298, 2142, 2142, 2142, 2142, 2142,
- /* 220 */ 2142, 2142, 1179, 1157, 1157, 487, 527, 585, 645, 749,
- /* 230 */ 914, 968, 752, 713, 713, 713, 713, 713, 713, 713,
- /* 240 */ 713, 713, 713, 303, 713, 713, 713, 713, 713, 713,
- /* 250 */ 713, 713, 713, 713, 713, 713, 797, 797, 797, 713,
- /* 260 */ 713, 713, 959, 713, 713, 713, 1169, 1271, 713, 713,
- /* 270 */ 1330, 713, 713, 713, 713, 713, 713, 713, 713, 629,
- /* 280 */ 7, 91, 876, 876, 876, 876, 953, 91, 91, 1246,
- /* 290 */ 1065, 1106, 1374, 1329, 1348, 468, 1348, 1394, 785, 1329,
- /* 300 */ 1329, 785, 1329, 468, 1394, 859, 854, 1402, 1449, 1449,
- /* 310 */ 1449, 1173, 1173, 1173, 1173, 1355, 1355, 1030, 1341, 405,
- /* 320 */ 1230, 1795, 1795, 1711, 1711, 1829, 1829, 1711, 1717, 1719,
- /* 330 */ 1850, 1833, 1860, 1860, 1860, 1860, 1711, 1868, 1740, 1719,
- /* 340 */ 1719, 1740, 1850, 1833, 1740, 1833, 1740, 1711, 1868, 1745,
- /* 350 */ 1843, 1711, 1868, 1887, 1711, 1868, 1711, 1868, 1887, 1801,
- /* 360 */ 1801, 1801, 1855, 1900, 1900, 1887, 1801, 1797, 1801, 1855,
- /* 370 */ 1801, 1801, 1761, 1912, 1830, 1830, 1887, 1711, 1862, 1862,
- /* 380 */ 1875, 1875, 1810, 1815, 1940, 1711, 1807, 1810, 1821, 1823,
- /* 390 */ 1740, 1945, 1963, 1963, 1974, 1974, 1974, 2142, 2142, 2142,
- /* 400 */ 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142,
- /* 410 */ 2142, 2142, 20, 1224, 256, 1111, 1115, 1114, 1192, 1496,
- /* 420 */ 1424, 1505, 1427, 355, 1383, 1537, 1506, 1538, 1553, 1583,
- /* 430 */ 1584, 1591, 1625, 541, 1445, 1562, 1450, 1572, 1515, 1428,
- /* 440 */ 1532, 1592, 1629, 1520, 1630, 1639, 1510, 1544, 1662, 1675,
- /* 450 */ 1551, 48, 1996, 2001, 1983, 1844, 1993, 1994, 1986, 1989,
- /* 460 */ 1874, 1863, 1885, 1991, 1991, 1995, 1876, 1997, 1877, 2004,
- /* 470 */ 2021, 1881, 1894, 1991, 1895, 1965, 1990, 1991, 1878, 1975,
- /* 480 */ 1977, 1978, 1979, 1903, 1918, 2002, 1896, 2034, 2033, 2017,
- /* 490 */ 1925, 1880, 1976, 2018, 1980, 1967, 2005, 1904, 1932, 2025,
- /* 500 */ 2030, 2032, 1921, 1928, 2035, 1987, 2036, 2037, 2038, 2040,
- /* 510 */ 1988, 2006, 2039, 1960, 2041, 2042, 1999, 2023, 2044, 2043,
- /* 520 */ 1919, 2048, 2049, 2050, 2046, 2051, 2053, 1981, 1935, 2056,
- /* 530 */ 2057, 1966, 2047, 2061, 1941, 2060, 2052, 2054, 2055, 2058,
- /* 540 */ 2003, 2012, 2007, 2059, 2015, 2008, 2062, 2071, 2073, 2074,
- /* 550 */ 2072, 2075, 2065, 1962, 1964, 2079, 2060, 2082, 2084, 2085,
- /* 560 */ 2087, 2086, 2089, 2088, 2091, 2093, 2099, 2094, 2095, 2096,
- /* 570 */ 2097, 2100, 2101, 2102, 1998, 1984, 1985, 2000, 2103, 2098,
- /* 580 */ 2109, 2117, 2128,
+ /* 0 */ 2029, 1801, 2043, 1380, 1380, 318, 271, 1496, 1569, 1642,
+ /* 10 */ 702, 702, 702, 740, 318, 318, 318, 318, 318, 0,
+ /* 20 */ 0, 216, 1177, 702, 702, 702, 702, 702, 702, 702,
+ /* 30 */ 702, 702, 702, 702, 702, 702, 702, 702, 503, 503,
+ /* 40 */ 111, 111, 217, 287, 348, 610, 610, 736, 736, 736,
+ /* 50 */ 736, 40, 112, 320, 340, 445, 489, 593, 637, 741,
+ /* 60 */ 785, 889, 909, 1023, 1043, 1157, 1177, 1177, 1177, 1177,
+ /* 70 */ 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177,
+ /* 80 */ 1177, 1177, 1177, 1177, 1197, 1177, 1301, 1321, 1321, 554,
+ /* 90 */ 1802, 1910, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 100 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 110 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 120 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 130 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702,
+ /* 140 */ 702, 702, 138, 198, 198, 198, 198, 198, 198, 198,
+ /* 150 */ 183, 99, 169, 549, 610, 151, 542, 610, 610, 1017,
+ /* 160 */ 1017, 610, 1001, 350, 464, 464, 464, 586, 1, 1,
+ /* 170 */ 2207, 2207, 854, 854, 854, 465, 694, 694, 694, 694,
+ /* 180 */ 1096, 1096, 825, 549, 847, 904, 610, 610, 610, 610,
+ /* 190 */ 610, 610, 610, 610, 610, 610, 610, 610, 610, 610,
+ /* 200 */ 610, 610, 610, 610, 610, 488, 947, 947, 610, 1129,
+ /* 210 */ 495, 495, 1139, 1139, 967, 967, 1173, 2207, 2207, 2207,
+ /* 220 */ 2207, 2207, 2207, 2207, 617, 765, 765, 697, 444, 708,
+ /* 230 */ 660, 745, 510, 663, 864, 610, 610, 610, 610, 610,
+ /* 240 */ 610, 610, 610, 610, 610, 188, 610, 610, 610, 610,
+ /* 250 */ 610, 610, 610, 610, 610, 610, 610, 610, 839, 839,
+ /* 260 */ 839, 610, 610, 610, 1155, 610, 610, 610, 1119, 1247,
+ /* 270 */ 610, 1353, 610, 610, 610, 610, 610, 610, 610, 610,
+ /* 280 */ 1063, 494, 1101, 291, 291, 291, 291, 1319, 1101, 1101,
+ /* 290 */ 775, 1221, 1375, 1452, 667, 1341, 1198, 1341, 1435, 1487,
+ /* 300 */ 667, 667, 1487, 667, 1198, 1435, 777, 1011, 1423, 584,
+ /* 310 */ 584, 584, 1273, 1273, 1273, 1273, 1471, 1471, 880, 1530,
+ /* 320 */ 1190, 1095, 1731, 1731, 1668, 1668, 1794, 1794, 1668, 1683,
+ /* 330 */ 1685, 1815, 1796, 1824, 1824, 1824, 1824, 1668, 1828, 1701,
+ /* 340 */ 1685, 1685, 1701, 1815, 1796, 1701, 1796, 1701, 1668, 1828,
+ /* 350 */ 1697, 1800, 1668, 1828, 1848, 1668, 1828, 1668, 1828, 1848,
+ /* 360 */ 1766, 1766, 1766, 1823, 1870, 1870, 1848, 1766, 1767, 1766,
+ /* 370 */ 1823, 1766, 1766, 1727, 1872, 1783, 1783, 1848, 1668, 1813,
+ /* 380 */ 1813, 1825, 1825, 1777, 1781, 1906, 1668, 1774, 1777, 1789,
+ /* 390 */ 1792, 1701, 1919, 1935, 1935, 1949, 1949, 1949, 2207, 2207,
+ /* 400 */ 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207,
+ /* 410 */ 2207, 2207, 2207, 69, 1032, 79, 357, 1377, 1206, 400,
+ /* 420 */ 1525, 835, 332, 1540, 1437, 1539, 1536, 1548, 1583, 1620,
+ /* 430 */ 1633, 1670, 1671, 1674, 1567, 1553, 1682, 1506, 1675, 1358,
+ /* 440 */ 1607, 1589, 1678, 1681, 1624, 1687, 1688, 1283, 1561, 1693,
+ /* 450 */ 1696, 1623, 1521, 1976, 1980, 1962, 1822, 1972, 1973, 1965,
+ /* 460 */ 1967, 1851, 1840, 1862, 1969, 1969, 1971, 1853, 1977, 1854,
+ /* 470 */ 1982, 1999, 1858, 1871, 1969, 1873, 1941, 1968, 1969, 1855,
+ /* 480 */ 1952, 1954, 1955, 1956, 1881, 1896, 1981, 1874, 2013, 2014,
+ /* 490 */ 1998, 1905, 1860, 1957, 2008, 1966, 1947, 1983, 1894, 1921,
+ /* 500 */ 2020, 2018, 2026, 1915, 1923, 2028, 1984, 2036, 2040, 2047,
+ /* 510 */ 2041, 2003, 2012, 2050, 1979, 2049, 2056, 2011, 2044, 2057,
+ /* 520 */ 2048, 1934, 2063, 2064, 2065, 2061, 2066, 2068, 1993, 1950,
+ /* 530 */ 2071, 2072, 1985, 2062, 2075, 1959, 2073, 2067, 2070, 2076,
+ /* 540 */ 2078, 2010, 2030, 2022, 2069, 2031, 2021, 2082, 2094, 2083,
+ /* 550 */ 2095, 2093, 2096, 2086, 1986, 1987, 2100, 2073, 2101, 2103,
+ /* 560 */ 2104, 2109, 2107, 2108, 2111, 2113, 2125, 2115, 2116, 2117,
+ /* 570 */ 2118, 2121, 2122, 2114, 2009, 2004, 2005, 2006, 2124, 2127,
+ /* 580 */ 2136, 2151, 2152,
};
-#define YY_REDUCE_COUNT (411)
-#define YY_REDUCE_MIN (-275)
-#define YY_REDUCE_MAX (1798)
+#define YY_REDUCE_COUNT (412)
+#define YY_REDUCE_MIN (-277)
+#define YY_REDUCE_MAX (1772)
static const short yy_reduce_ofst[] = {
- /* 0 */ -71, 194, 343, 835, -180, -177, 838, -194, -188, -185,
- /* 10 */ -183, 82, 183, -65, 133, 245, 346, 407, 458, -178,
- /* 20 */ 75, -275, -4, 310, 312, 489, 575, 596, 463, 686,
- /* 30 */ 707, 725, 780, 1098, 856, 778, 1059, 1090, 708, 887,
- /* 40 */ 86, 448, 980, 630, 680, 681, 684, 796, 801, 796,
- /* 50 */ 801, -261, -261, -261, -261, -261, -261, -261, -261, -261,
- /* 60 */ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261,
- /* 70 */ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261,
- /* 80 */ -261, -261, -261, -261, -261, -261, -261, -261, 391, 886,
- /* 90 */ 888, 1013, 1016, 1081, 1087, 1151, 1159, 1177, 1185, 1188,
- /* 100 */ 1190, 1194, 1197, 1203, 1247, 1260, 1264, 1267, 1269, 1273,
- /* 110 */ 1315, 1322, 1335, 1337, 1356, 1362, 1418, 1425, 1453, 1457,
- /* 120 */ 1465, 1473, 1487, 1495, 1507, 1517, 1521, 1534, 1543, 1546,
- /* 130 */ 1549, 1552, 1554, 1560, 1581, 1590, 1593, 1595, 1621, 1623,
- /* 140 */ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261,
- /* 150 */ -261, -186, -117, 260, 263, 460, 631, -74, 497, -181,
- /* 160 */ -261, 939, 176, 274, 338, 676, -261, -261, -261, -261,
- /* 170 */ -212, -212, -212, -184, 149, 777, 1061, 1103, 265, 419,
- /* 180 */ -254, 670, 677, 677, -11, -129, 184, 488, 736, 789,
- /* 190 */ 805, 844, 403, 529, 579, 668, 783, 841, 1158, 1112,
- /* 200 */ 806, 861, 1095, 846, 839, 1031, -189, 1077, 1080, 1116,
- /* 210 */ 1084, 1156, 1139, 1221, 46, 1099, 1037, 1118, 1171, 1214,
- /* 220 */ 1210, 1258, -210, -190, -176, -115, 117, 262, 376, 490,
- /* 230 */ 511, 520, 618, 639, 743, 901, 907, 958, 1014, 1055,
- /* 240 */ 1108, 1193, 1244, 720, 1248, 1277, 1324, 1347, 1417, 1431,
- /* 250 */ 1432, 1440, 1451, 1452, 1463, 1478, 1286, 1350, 1369, 1490,
- /* 260 */ 1498, 1501, 773, 1509, 1513, 1528, 1292, 1367, 1535, 1536,
- /* 270 */ 1477, 1542, 376, 1547, 1550, 1555, 1559, 1568, 1571, 1441,
- /* 280 */ 1443, 1474, 1511, 1516, 1519, 1522, 773, 1474, 1474, 1503,
- /* 290 */ 1567, 1594, 1484, 1527, 1556, 1570, 1557, 1524, 1573, 1545,
- /* 300 */ 1548, 1576, 1561, 1587, 1540, 1575, 1606, 1611, 1622, 1624,
- /* 310 */ 1626, 1582, 1597, 1598, 1599, 1601, 1603, 1563, 1608, 1605,
- /* 320 */ 1604, 1564, 1566, 1655, 1660, 1578, 1579, 1665, 1586, 1607,
- /* 330 */ 1610, 1642, 1641, 1645, 1646, 1647, 1679, 1688, 1644, 1618,
- /* 340 */ 1619, 1648, 1628, 1659, 1649, 1663, 1650, 1700, 1702, 1612,
- /* 350 */ 1615, 1706, 1708, 1689, 1709, 1712, 1713, 1715, 1691, 1698,
- /* 360 */ 1699, 1701, 1693, 1704, 1707, 1705, 1714, 1703, 1718, 1710,
- /* 370 */ 1720, 1721, 1632, 1634, 1664, 1666, 1729, 1751, 1635, 1636,
- /* 380 */ 1692, 1694, 1716, 1722, 1684, 1763, 1685, 1723, 1724, 1727,
- /* 390 */ 1730, 1768, 1783, 1784, 1793, 1794, 1796, 1683, 1686, 1690,
- /* 400 */ 1782, 1779, 1780, 1781, 1785, 1788, 1774, 1775, 1786, 1787,
- /* 410 */ 1789, 1798,
+ /* 0 */ -67, 1252, -64, -178, -181, 160, 1071, 143, -184, 137,
+ /* 10 */ 218, 220, 222, -174, 229, 268, 272, 275, 324, -208,
+ /* 20 */ 242, -277, -39, 81, 537, 792, 810, 812, -189, 814,
+ /* 30 */ 831, 163, 865, 944, 887, 840, 964, 1077, -187, 292,
+ /* 40 */ -133, 274, 673, 558, 682, 795, 809, -238, -232, -238,
+ /* 50 */ -232, 329, 329, 329, 329, 329, 329, 329, 329, 329,
+ /* 60 */ 329, 329, 329, 329, 329, 329, 329, 329, 329, 329,
+ /* 70 */ 329, 329, 329, 329, 329, 329, 329, 329, 329, 329,
+ /* 80 */ 329, 329, 329, 329, 329, 329, 329, 329, 329, 557,
+ /* 90 */ 712, 949, 966, 969, 971, 979, 1097, 1099, 1103, 1142,
+ /* 100 */ 1144, 1169, 1172, 1201, 1203, 1228, 1241, 1250, 1253, 1255,
+ /* 110 */ 1261, 1266, 1271, 1282, 1291, 1308, 1310, 1312, 1322, 1328,
+ /* 120 */ 1347, 1354, 1356, 1359, 1362, 1365, 1367, 1374, 1376, 1381,
+ /* 130 */ 1401, 1403, 1406, 1412, 1414, 1417, 1421, 1428, 1447, 1449,
+ /* 140 */ 1453, 1462, 329, 329, 329, 329, 329, 329, 329, 329,
+ /* 150 */ 329, 329, 329, -22, -159, 475, -220, 756, 38, 501,
+ /* 160 */ 841, 714, 329, 118, 337, 349, 363, -56, 329, 329,
+ /* 170 */ 329, 329, -205, -205, -205, 687, -172, -130, -57, 790,
+ /* 180 */ 397, 528, -271, 136, 596, 596, 90, 316, 522, 541,
+ /* 190 */ -37, 715, 849, 977, 628, 856, 980, 991, 1081, 1102,
+ /* 200 */ 1135, 1083, -162, 208, 1258, 794, -86, 159, 41, 1109,
+ /* 210 */ 671, 852, 844, 932, 1175, 1254, 480, 1180, 100, 258,
+ /* 220 */ 1265, 1268, 1216, 1287, -139, 317, 344, 63, 339, 423,
+ /* 230 */ 563, 636, 676, 813, 908, 914, 950, 1078, 1084, 1098,
+ /* 240 */ 1363, 1384, 1407, 1439, 1464, 411, 1527, 1534, 1535, 1537,
+ /* 250 */ 1541, 1542, 1543, 1544, 1545, 1547, 1549, 1550, 990, 1164,
+ /* 260 */ 1492, 1551, 1552, 1556, 1217, 1558, 1559, 1560, 1473, 1413,
+ /* 270 */ 1563, 1510, 1568, 563, 1570, 1571, 1572, 1573, 1574, 1575,
+ /* 280 */ 1443, 1466, 1518, 1513, 1514, 1515, 1516, 1217, 1518, 1518,
+ /* 290 */ 1531, 1562, 1582, 1477, 1505, 1511, 1533, 1512, 1488, 1538,
+ /* 300 */ 1509, 1517, 1546, 1519, 1557, 1489, 1565, 1564, 1578, 1586,
+ /* 310 */ 1587, 1588, 1526, 1528, 1554, 1555, 1576, 1577, 1566, 1579,
+ /* 320 */ 1584, 1591, 1520, 1523, 1617, 1628, 1580, 1581, 1632, 1585,
+ /* 330 */ 1590, 1593, 1604, 1605, 1606, 1608, 1609, 1641, 1649, 1610,
+ /* 340 */ 1592, 1594, 1611, 1595, 1616, 1612, 1618, 1613, 1651, 1654,
+ /* 350 */ 1596, 1598, 1655, 1663, 1650, 1673, 1680, 1677, 1684, 1653,
+ /* 360 */ 1664, 1666, 1667, 1662, 1669, 1672, 1676, 1686, 1679, 1691,
+ /* 370 */ 1689, 1692, 1694, 1597, 1599, 1619, 1630, 1699, 1700, 1602,
+ /* 380 */ 1615, 1648, 1657, 1690, 1698, 1658, 1729, 1652, 1695, 1702,
+ /* 390 */ 1704, 1703, 1741, 1754, 1758, 1768, 1769, 1771, 1660, 1661,
+ /* 400 */ 1665, 1752, 1756, 1757, 1759, 1760, 1764, 1745, 1753, 1762,
+ /* 410 */ 1763, 1761, 1772,
};
static const YYACTIONTYPE yy_default[] = {
/* 0 */ 1663, 1663, 1663, 1491, 1254, 1367, 1254, 1254, 1254, 1254,
@@ -173647,57 +176458,57 @@ static const YYACTIONTYPE yy_default[] = {
/* 30 */ 1254, 1254, 1254, 1254, 1254, 1490, 1254, 1254, 1254, 1254,
/* 40 */ 1578, 1578, 1254, 1254, 1254, 1254, 1254, 1563, 1562, 1254,
/* 50 */ 1254, 1254, 1406, 1254, 1413, 1254, 1254, 1254, 1254, 1254,
- /* 60 */ 1492, 1493, 1254, 1254, 1254, 1543, 1545, 1508, 1420, 1419,
- /* 70 */ 1418, 1417, 1526, 1385, 1411, 1404, 1408, 1487, 1488, 1486,
- /* 80 */ 1641, 1493, 1492, 1254, 1407, 1455, 1471, 1454, 1254, 1254,
+ /* 60 */ 1492, 1493, 1254, 1254, 1254, 1254, 1543, 1545, 1508, 1420,
+ /* 70 */ 1419, 1418, 1417, 1526, 1385, 1411, 1404, 1408, 1487, 1488,
+ /* 80 */ 1486, 1641, 1493, 1492, 1254, 1407, 1455, 1471, 1454, 1254,
/* 90 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
/* 100 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
/* 110 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
/* 120 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
/* 130 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 140 */ 1463, 1470, 1469, 1468, 1477, 1467, 1464, 1457, 1456, 1458,
- /* 150 */ 1459, 1278, 1254, 1275, 1329, 1254, 1254, 1254, 1254, 1254,
- /* 160 */ 1460, 1287, 1448, 1447, 1446, 1254, 1474, 1461, 1473, 1472,
- /* 170 */ 1551, 1615, 1614, 1509, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 180 */ 1578, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 140 */ 1254, 1254, 1463, 1470, 1469, 1468, 1477, 1467, 1464, 1457,
+ /* 150 */ 1456, 1458, 1459, 1278, 1254, 1275, 1329, 1254, 1254, 1254,
+ /* 160 */ 1254, 1254, 1460, 1287, 1448, 1447, 1446, 1254, 1474, 1461,
+ /* 170 */ 1473, 1472, 1551, 1615, 1614, 1509, 1254, 1254, 1254, 1254,
+ /* 180 */ 1254, 1254, 1578, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
/* 190 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 200 */ 1254, 1254, 1254, 1387, 1578, 1578, 1254, 1287, 1578, 1578,
- /* 210 */ 1388, 1388, 1283, 1283, 1391, 1558, 1358, 1358, 1358, 1358,
- /* 220 */ 1367, 1358, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 230 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1548, 1546, 1254,
- /* 240 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 200 */ 1254, 1254, 1254, 1254, 1254, 1387, 1578, 1578, 1254, 1287,
+ /* 210 */ 1578, 1578, 1388, 1388, 1283, 1283, 1391, 1558, 1358, 1358,
+ /* 220 */ 1358, 1358, 1367, 1358, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 230 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1548,
+ /* 240 */ 1546, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
/* 250 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 260 */ 1254, 1254, 1254, 1254, 1254, 1254, 1363, 1254, 1254, 1254,
- /* 270 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1608, 1254,
- /* 280 */ 1521, 1343, 1363, 1363, 1363, 1363, 1365, 1344, 1342, 1357,
- /* 290 */ 1288, 1261, 1655, 1423, 1412, 1364, 1412, 1652, 1410, 1423,
- /* 300 */ 1423, 1410, 1423, 1364, 1652, 1304, 1630, 1299, 1397, 1397,
- /* 310 */ 1397, 1387, 1387, 1387, 1387, 1391, 1391, 1489, 1364, 1357,
- /* 320 */ 1254, 1655, 1655, 1373, 1373, 1654, 1654, 1373, 1509, 1638,
- /* 330 */ 1432, 1332, 1338, 1338, 1338, 1338, 1373, 1272, 1410, 1638,
- /* 340 */ 1638, 1410, 1432, 1332, 1410, 1332, 1410, 1373, 1272, 1525,
- /* 350 */ 1649, 1373, 1272, 1499, 1373, 1272, 1373, 1272, 1499, 1330,
- /* 360 */ 1330, 1330, 1319, 1254, 1254, 1499, 1330, 1304, 1330, 1319,
- /* 370 */ 1330, 1330, 1596, 1254, 1503, 1503, 1499, 1373, 1588, 1588,
- /* 380 */ 1400, 1400, 1405, 1391, 1494, 1373, 1254, 1405, 1403, 1401,
- /* 390 */ 1410, 1322, 1611, 1611, 1607, 1607, 1607, 1660, 1660, 1558,
- /* 400 */ 1623, 1287, 1287, 1287, 1287, 1623, 1306, 1306, 1288, 1288,
- /* 410 */ 1287, 1623, 1254, 1254, 1254, 1254, 1254, 1254, 1618, 1254,
- /* 420 */ 1553, 1510, 1377, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 430 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1564,
- /* 440 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 450 */ 1254, 1437, 1254, 1257, 1555, 1254, 1254, 1254, 1254, 1254,
- /* 460 */ 1254, 1254, 1254, 1414, 1415, 1378, 1254, 1254, 1254, 1254,
- /* 470 */ 1254, 1254, 1254, 1429, 1254, 1254, 1254, 1424, 1254, 1254,
- /* 480 */ 1254, 1254, 1254, 1254, 1254, 1254, 1651, 1254, 1254, 1254,
- /* 490 */ 1254, 1254, 1254, 1524, 1523, 1254, 1254, 1375, 1254, 1254,
+ /* 260 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1363, 1254,
+ /* 270 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1608,
+ /* 280 */ 1254, 1521, 1343, 1363, 1363, 1363, 1363, 1365, 1344, 1342,
+ /* 290 */ 1357, 1288, 1261, 1655, 1423, 1412, 1364, 1412, 1652, 1410,
+ /* 300 */ 1423, 1423, 1410, 1423, 1364, 1652, 1304, 1630, 1299, 1397,
+ /* 310 */ 1397, 1397, 1387, 1387, 1387, 1387, 1391, 1391, 1489, 1364,
+ /* 320 */ 1357, 1254, 1655, 1655, 1373, 1373, 1654, 1654, 1373, 1509,
+ /* 330 */ 1638, 1432, 1332, 1338, 1338, 1338, 1338, 1373, 1272, 1410,
+ /* 340 */ 1638, 1638, 1410, 1432, 1332, 1410, 1332, 1410, 1373, 1272,
+ /* 350 */ 1525, 1649, 1373, 1272, 1499, 1373, 1272, 1373, 1272, 1499,
+ /* 360 */ 1330, 1330, 1330, 1319, 1254, 1254, 1499, 1330, 1304, 1330,
+ /* 370 */ 1319, 1330, 1330, 1596, 1254, 1503, 1503, 1499, 1373, 1588,
+ /* 380 */ 1588, 1400, 1400, 1405, 1391, 1494, 1373, 1254, 1405, 1403,
+ /* 390 */ 1401, 1410, 1322, 1611, 1611, 1607, 1607, 1607, 1660, 1660,
+ /* 400 */ 1558, 1623, 1287, 1287, 1287, 1287, 1623, 1306, 1306, 1288,
+ /* 410 */ 1288, 1287, 1623, 1254, 1254, 1254, 1254, 1254, 1254, 1618,
+ /* 420 */ 1254, 1553, 1510, 1377, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 430 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 440 */ 1564, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 450 */ 1254, 1254, 1437, 1254, 1257, 1555, 1254, 1254, 1254, 1254,
+ /* 460 */ 1254, 1254, 1254, 1254, 1414, 1415, 1378, 1254, 1254, 1254,
+ /* 470 */ 1254, 1254, 1254, 1254, 1429, 1254, 1254, 1254, 1424, 1254,
+ /* 480 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1651, 1254, 1254,
+ /* 490 */ 1254, 1254, 1254, 1254, 1524, 1523, 1254, 1254, 1375, 1254,
/* 500 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 510 */ 1254, 1302, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 510 */ 1254, 1254, 1302, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
/* 520 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 530 */ 1254, 1254, 1254, 1254, 1254, 1402, 1254, 1254, 1254, 1254,
+ /* 530 */ 1254, 1254, 1254, 1254, 1254, 1254, 1402, 1254, 1254, 1254,
/* 540 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
- /* 550 */ 1593, 1392, 1254, 1254, 1254, 1254, 1642, 1254, 1254, 1254,
- /* 560 */ 1254, 1352, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
+ /* 550 */ 1254, 1593, 1392, 1254, 1254, 1254, 1254, 1642, 1254, 1254,
+ /* 560 */ 1254, 1254, 1352, 1254, 1254, 1254, 1254, 1254, 1254, 1254,
/* 570 */ 1254, 1254, 1254, 1634, 1346, 1438, 1254, 1441, 1276, 1254,
/* 580 */ 1266, 1254, 1254,
};
@@ -173721,52 +176532,53 @@ static const YYACTIONTYPE yy_default[] = {
static const YYCODETYPE yyFallback[] = {
0, /* $ => nothing */
0, /* SEMI => nothing */
- 59, /* EXPLAIN => ID */
- 59, /* QUERY => ID */
- 59, /* PLAN => ID */
- 59, /* BEGIN => ID */
+ 60, /* EXPLAIN => ID */
+ 60, /* QUERY => ID */
+ 60, /* PLAN => ID */
+ 60, /* BEGIN => ID */
0, /* TRANSACTION => nothing */
- 59, /* DEFERRED => ID */
- 59, /* IMMEDIATE => ID */
- 59, /* EXCLUSIVE => ID */
+ 60, /* DEFERRED => ID */
+ 60, /* IMMEDIATE => ID */
+ 60, /* EXCLUSIVE => ID */
0, /* COMMIT => nothing */
- 59, /* END => ID */
- 59, /* ROLLBACK => ID */
- 59, /* SAVEPOINT => ID */
- 59, /* RELEASE => ID */
+ 60, /* END => ID */
+ 60, /* ROLLBACK => ID */
+ 60, /* SAVEPOINT => ID */
+ 60, /* RELEASE => ID */
0, /* TO => nothing */
0, /* TABLE => nothing */
0, /* CREATE => nothing */
- 59, /* IF => ID */
+ 60, /* IF => ID */
0, /* NOT => nothing */
0, /* EXISTS => nothing */
- 59, /* TEMP => ID */
+ 60, /* TEMP => ID */
0, /* LP => nothing */
0, /* RP => nothing */
0, /* AS => nothing */
0, /* COMMA => nothing */
- 59, /* WITHOUT => ID */
- 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 */
+ 60, /* WITHOUT => ID */
+ 60, /* ABORT => ID */
+ 60, /* ACTION => ID */
+ 60, /* AFTER => ID */
+ 60, /* ANALYZE => ID */
+ 60, /* ASC => ID */
+ 60, /* ATTACH => ID */
+ 60, /* BEFORE => ID */
+ 60, /* BY => ID */
+ 60, /* CASCADE => ID */
+ 60, /* CAST => ID */
+ 60, /* CONFLICT => ID */
+ 60, /* DATABASE => ID */
+ 60, /* DESC => ID */
+ 60, /* DETACH => ID */
+ 60, /* EACH => ID */
+ 60, /* FAIL => ID */
0, /* OR => nothing */
0, /* AND => nothing */
0, /* IS => nothing */
- 59, /* MATCH => ID */
- 59, /* LIKE_KW => ID */
+ 0, /* ISNOT => nothing */
+ 60, /* MATCH => ID */
+ 60, /* LIKE_KW => ID */
0, /* BETWEEN => nothing */
0, /* IN => nothing */
0, /* ISNULL => nothing */
@@ -173779,47 +176591,47 @@ static const YYCODETYPE yyFallback[] = {
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, /* MATERIALIZED => ID */
- 59, /* REINDEX => ID */
- 59, /* RENAME => ID */
- 59, /* CTIME_KW => ID */
+ 60, /* COLUMNKW => ID */
+ 60, /* DO => ID */
+ 60, /* FOR => ID */
+ 60, /* IGNORE => ID */
+ 60, /* INITIALLY => ID */
+ 60, /* INSTEAD => ID */
+ 60, /* NO => ID */
+ 60, /* KEY => ID */
+ 60, /* OF => ID */
+ 60, /* OFFSET => ID */
+ 60, /* PRAGMA => ID */
+ 60, /* RAISE => ID */
+ 60, /* RECURSIVE => ID */
+ 60, /* REPLACE => ID */
+ 60, /* RESTRICT => ID */
+ 60, /* ROW => ID */
+ 60, /* ROWS => ID */
+ 60, /* TRIGGER => ID */
+ 60, /* VACUUM => ID */
+ 60, /* VIEW => ID */
+ 60, /* VIRTUAL => ID */
+ 60, /* WITH => ID */
+ 60, /* NULLS => ID */
+ 60, /* FIRST => ID */
+ 60, /* LAST => ID */
+ 60, /* CURRENT => ID */
+ 60, /* FOLLOWING => ID */
+ 60, /* PARTITION => ID */
+ 60, /* PRECEDING => ID */
+ 60, /* RANGE => ID */
+ 60, /* UNBOUNDED => ID */
+ 60, /* EXCLUDE => ID */
+ 60, /* GROUPS => ID */
+ 60, /* OTHERS => ID */
+ 60, /* TIES => ID */
+ 60, /* GENERATED => ID */
+ 60, /* ALWAYS => ID */
+ 60, /* MATERIALIZED => ID */
+ 60, /* REINDEX => ID */
+ 60, /* RENAME => ID */
+ 60, /* CTIME_KW => ID */
0, /* ANY => nothing */
0, /* BITAND => nothing */
0, /* BITOR => nothing */
@@ -173890,7 +176702,6 @@ static const YYCODETYPE yyFallback[] = {
0, /* AGG_FUNCTION => nothing */
0, /* AGG_COLUMN => nothing */
0, /* TRUEFALSE => nothing */
- 0, /* ISNOT => nothing */
0, /* FUNCTION => nothing */
0, /* UPLUS => nothing */
0, /* UMINUS => nothing */
@@ -173904,6 +176715,7 @@ static const YYCODETYPE yyFallback[] = {
0, /* ERROR => nothing */
0, /* QNUMBER => nothing */
0, /* SPACE => nothing */
+ 0, /* COMMENT => nothing */
0, /* ILLEGAL => nothing */
};
#endif /* YYFALLBACK */
@@ -174034,132 +176846,132 @@ static const char *const yyTokenName[] = {
/* 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 */ "MATERIALIZED",
- /* 98 */ "REINDEX",
- /* 99 */ "RENAME",
- /* 100 */ "CTIME_KW",
- /* 101 */ "ANY",
- /* 102 */ "BITAND",
- /* 103 */ "BITOR",
- /* 104 */ "LSHIFT",
- /* 105 */ "RSHIFT",
- /* 106 */ "PLUS",
- /* 107 */ "MINUS",
- /* 108 */ "STAR",
- /* 109 */ "SLASH",
- /* 110 */ "REM",
- /* 111 */ "CONCAT",
- /* 112 */ "PTR",
- /* 113 */ "COLLATE",
- /* 114 */ "BITNOT",
- /* 115 */ "ON",
- /* 116 */ "INDEXED",
- /* 117 */ "STRING",
- /* 118 */ "JOIN_KW",
- /* 119 */ "CONSTRAINT",
- /* 120 */ "DEFAULT",
- /* 121 */ "NULL",
- /* 122 */ "PRIMARY",
- /* 123 */ "UNIQUE",
- /* 124 */ "CHECK",
- /* 125 */ "REFERENCES",
- /* 126 */ "AUTOINCR",
- /* 127 */ "INSERT",
- /* 128 */ "DELETE",
- /* 129 */ "UPDATE",
- /* 130 */ "SET",
- /* 131 */ "DEFERRABLE",
- /* 132 */ "FOREIGN",
- /* 133 */ "DROP",
- /* 134 */ "UNION",
- /* 135 */ "ALL",
- /* 136 */ "EXCEPT",
- /* 137 */ "INTERSECT",
- /* 138 */ "SELECT",
- /* 139 */ "VALUES",
- /* 140 */ "DISTINCT",
- /* 141 */ "DOT",
- /* 142 */ "FROM",
- /* 143 */ "JOIN",
- /* 144 */ "USING",
- /* 145 */ "ORDER",
- /* 146 */ "GROUP",
- /* 147 */ "HAVING",
- /* 148 */ "LIMIT",
- /* 149 */ "WHERE",
- /* 150 */ "RETURNING",
- /* 151 */ "INTO",
- /* 152 */ "NOTHING",
- /* 153 */ "FLOAT",
- /* 154 */ "BLOB",
- /* 155 */ "INTEGER",
- /* 156 */ "VARIABLE",
- /* 157 */ "CASE",
- /* 158 */ "WHEN",
- /* 159 */ "THEN",
- /* 160 */ "ELSE",
- /* 161 */ "INDEX",
- /* 162 */ "ALTER",
- /* 163 */ "ADD",
- /* 164 */ "WINDOW",
- /* 165 */ "OVER",
- /* 166 */ "FILTER",
- /* 167 */ "COLUMN",
- /* 168 */ "AGG_FUNCTION",
- /* 169 */ "AGG_COLUMN",
- /* 170 */ "TRUEFALSE",
- /* 171 */ "ISNOT",
+ /* 46 */ "ISNOT",
+ /* 47 */ "MATCH",
+ /* 48 */ "LIKE_KW",
+ /* 49 */ "BETWEEN",
+ /* 50 */ "IN",
+ /* 51 */ "ISNULL",
+ /* 52 */ "NOTNULL",
+ /* 53 */ "NE",
+ /* 54 */ "EQ",
+ /* 55 */ "GT",
+ /* 56 */ "LE",
+ /* 57 */ "LT",
+ /* 58 */ "GE",
+ /* 59 */ "ESCAPE",
+ /* 60 */ "ID",
+ /* 61 */ "COLUMNKW",
+ /* 62 */ "DO",
+ /* 63 */ "FOR",
+ /* 64 */ "IGNORE",
+ /* 65 */ "INITIALLY",
+ /* 66 */ "INSTEAD",
+ /* 67 */ "NO",
+ /* 68 */ "KEY",
+ /* 69 */ "OF",
+ /* 70 */ "OFFSET",
+ /* 71 */ "PRAGMA",
+ /* 72 */ "RAISE",
+ /* 73 */ "RECURSIVE",
+ /* 74 */ "REPLACE",
+ /* 75 */ "RESTRICT",
+ /* 76 */ "ROW",
+ /* 77 */ "ROWS",
+ /* 78 */ "TRIGGER",
+ /* 79 */ "VACUUM",
+ /* 80 */ "VIEW",
+ /* 81 */ "VIRTUAL",
+ /* 82 */ "WITH",
+ /* 83 */ "NULLS",
+ /* 84 */ "FIRST",
+ /* 85 */ "LAST",
+ /* 86 */ "CURRENT",
+ /* 87 */ "FOLLOWING",
+ /* 88 */ "PARTITION",
+ /* 89 */ "PRECEDING",
+ /* 90 */ "RANGE",
+ /* 91 */ "UNBOUNDED",
+ /* 92 */ "EXCLUDE",
+ /* 93 */ "GROUPS",
+ /* 94 */ "OTHERS",
+ /* 95 */ "TIES",
+ /* 96 */ "GENERATED",
+ /* 97 */ "ALWAYS",
+ /* 98 */ "MATERIALIZED",
+ /* 99 */ "REINDEX",
+ /* 100 */ "RENAME",
+ /* 101 */ "CTIME_KW",
+ /* 102 */ "ANY",
+ /* 103 */ "BITAND",
+ /* 104 */ "BITOR",
+ /* 105 */ "LSHIFT",
+ /* 106 */ "RSHIFT",
+ /* 107 */ "PLUS",
+ /* 108 */ "MINUS",
+ /* 109 */ "STAR",
+ /* 110 */ "SLASH",
+ /* 111 */ "REM",
+ /* 112 */ "CONCAT",
+ /* 113 */ "PTR",
+ /* 114 */ "COLLATE",
+ /* 115 */ "BITNOT",
+ /* 116 */ "ON",
+ /* 117 */ "INDEXED",
+ /* 118 */ "STRING",
+ /* 119 */ "JOIN_KW",
+ /* 120 */ "CONSTRAINT",
+ /* 121 */ "DEFAULT",
+ /* 122 */ "NULL",
+ /* 123 */ "PRIMARY",
+ /* 124 */ "UNIQUE",
+ /* 125 */ "CHECK",
+ /* 126 */ "REFERENCES",
+ /* 127 */ "AUTOINCR",
+ /* 128 */ "INSERT",
+ /* 129 */ "DELETE",
+ /* 130 */ "UPDATE",
+ /* 131 */ "SET",
+ /* 132 */ "DEFERRABLE",
+ /* 133 */ "FOREIGN",
+ /* 134 */ "DROP",
+ /* 135 */ "UNION",
+ /* 136 */ "ALL",
+ /* 137 */ "EXCEPT",
+ /* 138 */ "INTERSECT",
+ /* 139 */ "SELECT",
+ /* 140 */ "VALUES",
+ /* 141 */ "DISTINCT",
+ /* 142 */ "DOT",
+ /* 143 */ "FROM",
+ /* 144 */ "JOIN",
+ /* 145 */ "USING",
+ /* 146 */ "ORDER",
+ /* 147 */ "GROUP",
+ /* 148 */ "HAVING",
+ /* 149 */ "LIMIT",
+ /* 150 */ "WHERE",
+ /* 151 */ "RETURNING",
+ /* 152 */ "INTO",
+ /* 153 */ "NOTHING",
+ /* 154 */ "FLOAT",
+ /* 155 */ "BLOB",
+ /* 156 */ "INTEGER",
+ /* 157 */ "VARIABLE",
+ /* 158 */ "CASE",
+ /* 159 */ "WHEN",
+ /* 160 */ "THEN",
+ /* 161 */ "ELSE",
+ /* 162 */ "INDEX",
+ /* 163 */ "ALTER",
+ /* 164 */ "ADD",
+ /* 165 */ "WINDOW",
+ /* 166 */ "OVER",
+ /* 167 */ "FILTER",
+ /* 168 */ "COLUMN",
+ /* 169 */ "AGG_FUNCTION",
+ /* 170 */ "AGG_COLUMN",
+ /* 171 */ "TRUEFALSE",
/* 172 */ "FUNCTION",
/* 173 */ "UPLUS",
/* 174 */ "UMINUS",
@@ -174173,143 +176985,144 @@ static const char *const yyTokenName[] = {
/* 182 */ "ERROR",
/* 183 */ "QNUMBER",
/* 184 */ "SPACE",
- /* 185 */ "ILLEGAL",
- /* 186 */ "input",
- /* 187 */ "cmdlist",
- /* 188 */ "ecmd",
- /* 189 */ "cmdx",
- /* 190 */ "explain",
- /* 191 */ "cmd",
- /* 192 */ "transtype",
- /* 193 */ "trans_opt",
- /* 194 */ "nm",
- /* 195 */ "savepoint_opt",
- /* 196 */ "create_table",
- /* 197 */ "create_table_args",
- /* 198 */ "createkw",
- /* 199 */ "temp",
- /* 200 */ "ifnotexists",
- /* 201 */ "dbnm",
- /* 202 */ "columnlist",
- /* 203 */ "conslist_opt",
- /* 204 */ "table_option_set",
- /* 205 */ "select",
- /* 206 */ "table_option",
- /* 207 */ "columnname",
- /* 208 */ "carglist",
- /* 209 */ "typetoken",
- /* 210 */ "typename",
- /* 211 */ "signed",
- /* 212 */ "plus_num",
- /* 213 */ "minus_num",
- /* 214 */ "scanpt",
- /* 215 */ "scantok",
- /* 216 */ "ccons",
- /* 217 */ "term",
- /* 218 */ "expr",
- /* 219 */ "onconf",
- /* 220 */ "sortorder",
- /* 221 */ "autoinc",
- /* 222 */ "eidlist_opt",
- /* 223 */ "refargs",
- /* 224 */ "defer_subclause",
- /* 225 */ "generated",
- /* 226 */ "refarg",
- /* 227 */ "refact",
- /* 228 */ "init_deferred_pred_opt",
- /* 229 */ "conslist",
- /* 230 */ "tconscomma",
- /* 231 */ "tcons",
- /* 232 */ "sortlist",
- /* 233 */ "eidlist",
- /* 234 */ "defer_subclause_opt",
- /* 235 */ "orconf",
- /* 236 */ "resolvetype",
- /* 237 */ "raisetype",
- /* 238 */ "ifexists",
- /* 239 */ "fullname",
- /* 240 */ "selectnowith",
- /* 241 */ "oneselect",
- /* 242 */ "wqlist",
- /* 243 */ "multiselect_op",
- /* 244 */ "distinct",
- /* 245 */ "selcollist",
- /* 246 */ "from",
- /* 247 */ "where_opt",
- /* 248 */ "groupby_opt",
- /* 249 */ "having_opt",
- /* 250 */ "orderby_opt",
- /* 251 */ "limit_opt",
- /* 252 */ "window_clause",
- /* 253 */ "values",
- /* 254 */ "nexprlist",
- /* 255 */ "mvalues",
- /* 256 */ "sclp",
- /* 257 */ "as",
- /* 258 */ "seltablist",
- /* 259 */ "stl_prefix",
- /* 260 */ "joinop",
- /* 261 */ "on_using",
- /* 262 */ "indexed_by",
- /* 263 */ "exprlist",
- /* 264 */ "xfullname",
- /* 265 */ "idlist",
- /* 266 */ "indexed_opt",
- /* 267 */ "nulls",
- /* 268 */ "with",
- /* 269 */ "where_opt_ret",
- /* 270 */ "setlist",
- /* 271 */ "insert_cmd",
- /* 272 */ "idlist_opt",
- /* 273 */ "upsert",
- /* 274 */ "returning",
- /* 275 */ "filter_over",
- /* 276 */ "likeop",
- /* 277 */ "between_op",
- /* 278 */ "in_op",
- /* 279 */ "paren_exprlist",
- /* 280 */ "case_operand",
- /* 281 */ "case_exprlist",
- /* 282 */ "case_else",
- /* 283 */ "uniqueflag",
- /* 284 */ "collate",
- /* 285 */ "vinto",
- /* 286 */ "nmnum",
- /* 287 */ "trigger_decl",
- /* 288 */ "trigger_cmd_list",
- /* 289 */ "trigger_time",
- /* 290 */ "trigger_event",
- /* 291 */ "foreach_clause",
- /* 292 */ "when_clause",
- /* 293 */ "trigger_cmd",
- /* 294 */ "trnm",
- /* 295 */ "tridxby",
- /* 296 */ "database_kw_opt",
- /* 297 */ "key_opt",
- /* 298 */ "add_column_fullname",
- /* 299 */ "kwcolumn_opt",
- /* 300 */ "create_vtab",
- /* 301 */ "vtabarglist",
- /* 302 */ "vtabarg",
- /* 303 */ "vtabargtoken",
- /* 304 */ "lp",
- /* 305 */ "anylist",
- /* 306 */ "wqitem",
- /* 307 */ "wqas",
- /* 308 */ "withnm",
- /* 309 */ "windowdefn_list",
- /* 310 */ "windowdefn",
- /* 311 */ "window",
- /* 312 */ "frame_opt",
- /* 313 */ "part_opt",
- /* 314 */ "filter_clause",
- /* 315 */ "over_clause",
- /* 316 */ "range_or_rows",
- /* 317 */ "frame_bound",
- /* 318 */ "frame_bound_s",
- /* 319 */ "frame_bound_e",
- /* 320 */ "frame_exclude_opt",
- /* 321 */ "frame_exclude",
+ /* 185 */ "COMMENT",
+ /* 186 */ "ILLEGAL",
+ /* 187 */ "input",
+ /* 188 */ "cmdlist",
+ /* 189 */ "ecmd",
+ /* 190 */ "cmdx",
+ /* 191 */ "explain",
+ /* 192 */ "cmd",
+ /* 193 */ "transtype",
+ /* 194 */ "trans_opt",
+ /* 195 */ "nm",
+ /* 196 */ "savepoint_opt",
+ /* 197 */ "create_table",
+ /* 198 */ "create_table_args",
+ /* 199 */ "createkw",
+ /* 200 */ "temp",
+ /* 201 */ "ifnotexists",
+ /* 202 */ "dbnm",
+ /* 203 */ "columnlist",
+ /* 204 */ "conslist_opt",
+ /* 205 */ "table_option_set",
+ /* 206 */ "select",
+ /* 207 */ "table_option",
+ /* 208 */ "columnname",
+ /* 209 */ "carglist",
+ /* 210 */ "typetoken",
+ /* 211 */ "typename",
+ /* 212 */ "signed",
+ /* 213 */ "plus_num",
+ /* 214 */ "minus_num",
+ /* 215 */ "scanpt",
+ /* 216 */ "scantok",
+ /* 217 */ "ccons",
+ /* 218 */ "term",
+ /* 219 */ "expr",
+ /* 220 */ "onconf",
+ /* 221 */ "sortorder",
+ /* 222 */ "autoinc",
+ /* 223 */ "eidlist_opt",
+ /* 224 */ "refargs",
+ /* 225 */ "defer_subclause",
+ /* 226 */ "generated",
+ /* 227 */ "refarg",
+ /* 228 */ "refact",
+ /* 229 */ "init_deferred_pred_opt",
+ /* 230 */ "conslist",
+ /* 231 */ "tconscomma",
+ /* 232 */ "tcons",
+ /* 233 */ "sortlist",
+ /* 234 */ "eidlist",
+ /* 235 */ "defer_subclause_opt",
+ /* 236 */ "orconf",
+ /* 237 */ "resolvetype",
+ /* 238 */ "raisetype",
+ /* 239 */ "ifexists",
+ /* 240 */ "fullname",
+ /* 241 */ "selectnowith",
+ /* 242 */ "oneselect",
+ /* 243 */ "wqlist",
+ /* 244 */ "multiselect_op",
+ /* 245 */ "distinct",
+ /* 246 */ "selcollist",
+ /* 247 */ "from",
+ /* 248 */ "where_opt",
+ /* 249 */ "groupby_opt",
+ /* 250 */ "having_opt",
+ /* 251 */ "orderby_opt",
+ /* 252 */ "limit_opt",
+ /* 253 */ "window_clause",
+ /* 254 */ "values",
+ /* 255 */ "nexprlist",
+ /* 256 */ "mvalues",
+ /* 257 */ "sclp",
+ /* 258 */ "as",
+ /* 259 */ "seltablist",
+ /* 260 */ "stl_prefix",
+ /* 261 */ "joinop",
+ /* 262 */ "on_using",
+ /* 263 */ "indexed_by",
+ /* 264 */ "exprlist",
+ /* 265 */ "xfullname",
+ /* 266 */ "idlist",
+ /* 267 */ "indexed_opt",
+ /* 268 */ "nulls",
+ /* 269 */ "with",
+ /* 270 */ "where_opt_ret",
+ /* 271 */ "setlist",
+ /* 272 */ "insert_cmd",
+ /* 273 */ "idlist_opt",
+ /* 274 */ "upsert",
+ /* 275 */ "returning",
+ /* 276 */ "filter_over",
+ /* 277 */ "likeop",
+ /* 278 */ "between_op",
+ /* 279 */ "in_op",
+ /* 280 */ "paren_exprlist",
+ /* 281 */ "case_operand",
+ /* 282 */ "case_exprlist",
+ /* 283 */ "case_else",
+ /* 284 */ "uniqueflag",
+ /* 285 */ "collate",
+ /* 286 */ "vinto",
+ /* 287 */ "nmnum",
+ /* 288 */ "trigger_decl",
+ /* 289 */ "trigger_cmd_list",
+ /* 290 */ "trigger_time",
+ /* 291 */ "trigger_event",
+ /* 292 */ "foreach_clause",
+ /* 293 */ "when_clause",
+ /* 294 */ "trigger_cmd",
+ /* 295 */ "trnm",
+ /* 296 */ "tridxby",
+ /* 297 */ "database_kw_opt",
+ /* 298 */ "key_opt",
+ /* 299 */ "add_column_fullname",
+ /* 300 */ "kwcolumn_opt",
+ /* 301 */ "create_vtab",
+ /* 302 */ "vtabarglist",
+ /* 303 */ "vtabarg",
+ /* 304 */ "vtabargtoken",
+ /* 305 */ "lp",
+ /* 306 */ "anylist",
+ /* 307 */ "wqitem",
+ /* 308 */ "wqas",
+ /* 309 */ "withnm",
+ /* 310 */ "windowdefn_list",
+ /* 311 */ "windowdefn",
+ /* 312 */ "window",
+ /* 313 */ "frame_opt",
+ /* 314 */ "part_opt",
+ /* 315 */ "filter_clause",
+ /* 316 */ "over_clause",
+ /* 317 */ "range_or_rows",
+ /* 318 */ "frame_bound",
+ /* 319 */ "frame_bound_s",
+ /* 320 */ "frame_bound_e",
+ /* 321 */ "frame_exclude_opt",
+ /* 322 */ "frame_exclude",
};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
@@ -174597,7 +177410,7 @@ static const char *const yyRuleName[] = {
/* 277 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
/* 278 */ "trigger_cmd ::= scanpt select scanpt",
/* 279 */ "expr ::= RAISE LP IGNORE RP",
- /* 280 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 280 */ "expr ::= RAISE LP raisetype COMMA expr RP",
/* 281 */ "raisetype ::= ROLLBACK",
/* 282 */ "raisetype ::= ABORT",
/* 283 */ "raisetype ::= FAIL",
@@ -174849,98 +177662,98 @@ static void yy_destructor(
** inside the C code.
*/
/********* Begin destructor definitions ***************************************/
- case 205: /* select */
- case 240: /* selectnowith */
- case 241: /* oneselect */
- case 253: /* values */
- case 255: /* mvalues */
+ case 206: /* select */
+ case 241: /* selectnowith */
+ case 242: /* oneselect */
+ case 254: /* values */
+ case 256: /* mvalues */
{
-sqlite3SelectDelete(pParse->db, (yypminor->yy555));
-}
- break;
- case 217: /* term */
- case 218: /* expr */
- case 247: /* where_opt */
- case 249: /* having_opt */
- case 269: /* where_opt_ret */
- case 280: /* case_operand */
- case 282: /* case_else */
- case 285: /* vinto */
- case 292: /* when_clause */
- case 297: /* key_opt */
- case 314: /* filter_clause */
+sqlite3SelectDelete(pParse->db, (yypminor->yy637));
+}
+ break;
+ case 218: /* term */
+ case 219: /* expr */
+ case 248: /* where_opt */
+ case 250: /* having_opt */
+ case 270: /* where_opt_ret */
+ case 281: /* case_operand */
+ case 283: /* case_else */
+ case 286: /* vinto */
+ case 293: /* when_clause */
+ case 298: /* key_opt */
+ case 315: /* filter_clause */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy454));
-}
- break;
- case 222: /* eidlist_opt */
- case 232: /* sortlist */
- case 233: /* eidlist */
- case 245: /* selcollist */
- case 248: /* groupby_opt */
- case 250: /* orderby_opt */
- case 254: /* nexprlist */
- case 256: /* sclp */
- case 263: /* exprlist */
- case 270: /* setlist */
- case 279: /* paren_exprlist */
- case 281: /* case_exprlist */
- case 313: /* part_opt */
+sqlite3ExprDelete(pParse->db, (yypminor->yy590));
+}
+ break;
+ case 223: /* eidlist_opt */
+ case 233: /* sortlist */
+ case 234: /* eidlist */
+ case 246: /* selcollist */
+ case 249: /* groupby_opt */
+ case 251: /* orderby_opt */
+ case 255: /* nexprlist */
+ case 257: /* sclp */
+ case 264: /* exprlist */
+ case 271: /* setlist */
+ case 280: /* paren_exprlist */
+ case 282: /* case_exprlist */
+ case 314: /* part_opt */
{
-sqlite3ExprListDelete(pParse->db, (yypminor->yy14));
+sqlite3ExprListDelete(pParse->db, (yypminor->yy402));
}
break;
- case 239: /* fullname */
- case 246: /* from */
- case 258: /* seltablist */
- case 259: /* stl_prefix */
- case 264: /* xfullname */
+ case 240: /* fullname */
+ case 247: /* from */
+ case 259: /* seltablist */
+ case 260: /* stl_prefix */
+ case 265: /* xfullname */
{
-sqlite3SrcListDelete(pParse->db, (yypminor->yy203));
+sqlite3SrcListDelete(pParse->db, (yypminor->yy563));
}
break;
- case 242: /* wqlist */
+ case 243: /* wqlist */
{
-sqlite3WithDelete(pParse->db, (yypminor->yy59));
+sqlite3WithDelete(pParse->db, (yypminor->yy125));
}
break;
- case 252: /* window_clause */
- case 309: /* windowdefn_list */
+ case 253: /* window_clause */
+ case 310: /* windowdefn_list */
{
-sqlite3WindowListDelete(pParse->db, (yypminor->yy211));
+sqlite3WindowListDelete(pParse->db, (yypminor->yy483));
}
break;
- case 265: /* idlist */
- case 272: /* idlist_opt */
+ case 266: /* idlist */
+ case 273: /* idlist_opt */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy132));
+sqlite3IdListDelete(pParse->db, (yypminor->yy204));
}
break;
- case 275: /* filter_over */
- case 310: /* windowdefn */
- case 311: /* window */
- case 312: /* frame_opt */
- case 315: /* over_clause */
+ case 276: /* filter_over */
+ case 311: /* windowdefn */
+ case 312: /* window */
+ case 313: /* frame_opt */
+ case 316: /* over_clause */
{
-sqlite3WindowDelete(pParse->db, (yypminor->yy211));
+sqlite3WindowDelete(pParse->db, (yypminor->yy483));
}
break;
- case 288: /* trigger_cmd_list */
- case 293: /* trigger_cmd */
+ case 289: /* trigger_cmd_list */
+ case 294: /* trigger_cmd */
{
-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427));
+sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy319));
}
break;
- case 290: /* trigger_event */
+ case 291: /* trigger_event */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy286).b);
+sqlite3IdListDelete(pParse->db, (yypminor->yy28).b);
}
break;
- case 317: /* frame_bound */
- case 318: /* frame_bound_s */
- case 319: /* frame_bound_e */
+ case 318: /* frame_bound */
+ case 319: /* frame_bound_s */
+ case 320: /* frame_bound_e */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy509).pExpr);
+sqlite3ExprDelete(pParse->db, (yypminor->yy205).pExpr);
}
break;
/********* End destructor definitions *****************************************/
@@ -175242,415 +178055,415 @@ static void yy_shift(
/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
** of that rule */
static const YYCODETYPE yyRuleInfoLhs[] = {
- 190, /* (0) explain ::= EXPLAIN */
- 190, /* (1) explain ::= EXPLAIN QUERY PLAN */
- 189, /* (2) cmdx ::= cmd */
- 191, /* (3) cmd ::= BEGIN transtype trans_opt */
- 192, /* (4) transtype ::= */
- 192, /* (5) transtype ::= DEFERRED */
- 192, /* (6) transtype ::= IMMEDIATE */
- 192, /* (7) transtype ::= EXCLUSIVE */
- 191, /* (8) cmd ::= COMMIT|END trans_opt */
- 191, /* (9) cmd ::= ROLLBACK trans_opt */
- 191, /* (10) cmd ::= SAVEPOINT nm */
- 191, /* (11) cmd ::= RELEASE savepoint_opt nm */
- 191, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
- 196, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
- 198, /* (14) createkw ::= CREATE */
- 200, /* (15) ifnotexists ::= */
- 200, /* (16) ifnotexists ::= IF NOT EXISTS */
- 199, /* (17) temp ::= TEMP */
- 199, /* (18) temp ::= */
- 197, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
- 197, /* (20) create_table_args ::= AS select */
- 204, /* (21) table_option_set ::= */
- 204, /* (22) table_option_set ::= table_option_set COMMA table_option */
- 206, /* (23) table_option ::= WITHOUT nm */
- 206, /* (24) table_option ::= nm */
- 207, /* (25) columnname ::= nm typetoken */
- 209, /* (26) typetoken ::= */
- 209, /* (27) typetoken ::= typename LP signed RP */
- 209, /* (28) typetoken ::= typename LP signed COMMA signed RP */
- 210, /* (29) typename ::= typename ID|STRING */
- 214, /* (30) scanpt ::= */
- 215, /* (31) scantok ::= */
- 216, /* (32) ccons ::= CONSTRAINT nm */
- 216, /* (33) ccons ::= DEFAULT scantok term */
- 216, /* (34) ccons ::= DEFAULT LP expr RP */
- 216, /* (35) ccons ::= DEFAULT PLUS scantok term */
- 216, /* (36) ccons ::= DEFAULT MINUS scantok term */
- 216, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
- 216, /* (38) ccons ::= NOT NULL onconf */
- 216, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
- 216, /* (40) ccons ::= UNIQUE onconf */
- 216, /* (41) ccons ::= CHECK LP expr RP */
- 216, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
- 216, /* (43) ccons ::= defer_subclause */
- 216, /* (44) ccons ::= COLLATE ID|STRING */
- 225, /* (45) generated ::= LP expr RP */
- 225, /* (46) generated ::= LP expr RP ID */
- 221, /* (47) autoinc ::= */
- 221, /* (48) autoinc ::= AUTOINCR */
- 223, /* (49) refargs ::= */
- 223, /* (50) refargs ::= refargs refarg */
- 226, /* (51) refarg ::= MATCH nm */
- 226, /* (52) refarg ::= ON INSERT refact */
- 226, /* (53) refarg ::= ON DELETE refact */
- 226, /* (54) refarg ::= ON UPDATE refact */
- 227, /* (55) refact ::= SET NULL */
- 227, /* (56) refact ::= SET DEFAULT */
- 227, /* (57) refact ::= CASCADE */
- 227, /* (58) refact ::= RESTRICT */
- 227, /* (59) refact ::= NO ACTION */
- 224, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
- 224, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
- 228, /* (62) init_deferred_pred_opt ::= */
- 228, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
- 228, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
- 203, /* (65) conslist_opt ::= */
- 230, /* (66) tconscomma ::= COMMA */
- 231, /* (67) tcons ::= CONSTRAINT nm */
- 231, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
- 231, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
- 231, /* (70) tcons ::= CHECK LP expr RP onconf */
- 231, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
- 234, /* (72) defer_subclause_opt ::= */
- 219, /* (73) onconf ::= */
- 219, /* (74) onconf ::= ON CONFLICT resolvetype */
- 235, /* (75) orconf ::= */
- 235, /* (76) orconf ::= OR resolvetype */
- 236, /* (77) resolvetype ::= IGNORE */
- 236, /* (78) resolvetype ::= REPLACE */
- 191, /* (79) cmd ::= DROP TABLE ifexists fullname */
- 238, /* (80) ifexists ::= IF EXISTS */
- 238, /* (81) ifexists ::= */
- 191, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
- 191, /* (83) cmd ::= DROP VIEW ifexists fullname */
- 191, /* (84) cmd ::= select */
- 205, /* (85) select ::= WITH wqlist selectnowith */
- 205, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
- 205, /* (87) select ::= selectnowith */
- 240, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
- 243, /* (89) multiselect_op ::= UNION */
- 243, /* (90) multiselect_op ::= UNION ALL */
- 243, /* (91) multiselect_op ::= EXCEPT|INTERSECT */
- 241, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
- 241, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
- 253, /* (94) values ::= VALUES LP nexprlist RP */
- 241, /* (95) oneselect ::= mvalues */
- 255, /* (96) mvalues ::= values COMMA LP nexprlist RP */
- 255, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */
- 244, /* (98) distinct ::= DISTINCT */
- 244, /* (99) distinct ::= ALL */
- 244, /* (100) distinct ::= */
- 256, /* (101) sclp ::= */
- 245, /* (102) selcollist ::= sclp scanpt expr scanpt as */
- 245, /* (103) selcollist ::= sclp scanpt STAR */
- 245, /* (104) selcollist ::= sclp scanpt nm DOT STAR */
- 257, /* (105) as ::= AS nm */
- 257, /* (106) as ::= */
- 246, /* (107) from ::= */
- 246, /* (108) from ::= FROM seltablist */
- 259, /* (109) stl_prefix ::= seltablist joinop */
- 259, /* (110) stl_prefix ::= */
- 258, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */
- 258, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
- 258, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
- 258, /* (114) seltablist ::= stl_prefix LP select RP as on_using */
- 258, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */
- 201, /* (116) dbnm ::= */
- 201, /* (117) dbnm ::= DOT nm */
- 239, /* (118) fullname ::= nm */
- 239, /* (119) fullname ::= nm DOT nm */
- 264, /* (120) xfullname ::= nm */
- 264, /* (121) xfullname ::= nm DOT nm */
- 264, /* (122) xfullname ::= nm DOT nm AS nm */
- 264, /* (123) xfullname ::= nm AS nm */
- 260, /* (124) joinop ::= COMMA|JOIN */
- 260, /* (125) joinop ::= JOIN_KW JOIN */
- 260, /* (126) joinop ::= JOIN_KW nm JOIN */
- 260, /* (127) joinop ::= JOIN_KW nm nm JOIN */
- 261, /* (128) on_using ::= ON expr */
- 261, /* (129) on_using ::= USING LP idlist RP */
- 261, /* (130) on_using ::= */
- 266, /* (131) indexed_opt ::= */
- 262, /* (132) indexed_by ::= INDEXED BY nm */
- 262, /* (133) indexed_by ::= NOT INDEXED */
- 250, /* (134) orderby_opt ::= */
- 250, /* (135) orderby_opt ::= ORDER BY sortlist */
- 232, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */
- 232, /* (137) sortlist ::= expr sortorder nulls */
- 220, /* (138) sortorder ::= ASC */
- 220, /* (139) sortorder ::= DESC */
- 220, /* (140) sortorder ::= */
- 267, /* (141) nulls ::= NULLS FIRST */
- 267, /* (142) nulls ::= NULLS LAST */
- 267, /* (143) nulls ::= */
- 248, /* (144) groupby_opt ::= */
- 248, /* (145) groupby_opt ::= GROUP BY nexprlist */
- 249, /* (146) having_opt ::= */
- 249, /* (147) having_opt ::= HAVING expr */
- 251, /* (148) limit_opt ::= */
- 251, /* (149) limit_opt ::= LIMIT expr */
- 251, /* (150) limit_opt ::= LIMIT expr OFFSET expr */
- 251, /* (151) limit_opt ::= LIMIT expr COMMA expr */
- 191, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
- 247, /* (153) where_opt ::= */
- 247, /* (154) where_opt ::= WHERE expr */
- 269, /* (155) where_opt_ret ::= */
- 269, /* (156) where_opt_ret ::= WHERE expr */
- 269, /* (157) where_opt_ret ::= RETURNING selcollist */
- 269, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */
- 191, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
- 270, /* (160) setlist ::= setlist COMMA nm EQ expr */
- 270, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */
- 270, /* (162) setlist ::= nm EQ expr */
- 270, /* (163) setlist ::= LP idlist RP EQ expr */
- 191, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
- 191, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
- 273, /* (166) upsert ::= */
- 273, /* (167) upsert ::= RETURNING selcollist */
- 273, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
- 273, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
- 273, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */
- 273, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
- 274, /* (172) returning ::= RETURNING selcollist */
- 271, /* (173) insert_cmd ::= INSERT orconf */
- 271, /* (174) insert_cmd ::= REPLACE */
- 272, /* (175) idlist_opt ::= */
- 272, /* (176) idlist_opt ::= LP idlist RP */
- 265, /* (177) idlist ::= idlist COMMA nm */
- 265, /* (178) idlist ::= nm */
- 218, /* (179) expr ::= LP expr RP */
- 218, /* (180) expr ::= ID|INDEXED|JOIN_KW */
- 218, /* (181) expr ::= nm DOT nm */
- 218, /* (182) expr ::= nm DOT nm DOT nm */
- 217, /* (183) term ::= NULL|FLOAT|BLOB */
- 217, /* (184) term ::= STRING */
- 217, /* (185) term ::= INTEGER */
- 218, /* (186) expr ::= VARIABLE */
- 218, /* (187) expr ::= expr COLLATE ID|STRING */
- 218, /* (188) expr ::= CAST LP expr AS typetoken RP */
- 218, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
- 218, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
- 218, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
- 218, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
- 218, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
- 218, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
- 217, /* (195) term ::= CTIME_KW */
- 218, /* (196) expr ::= LP nexprlist COMMA expr RP */
- 218, /* (197) expr ::= expr AND expr */
- 218, /* (198) expr ::= expr OR expr */
- 218, /* (199) expr ::= expr LT|GT|GE|LE expr */
- 218, /* (200) expr ::= expr EQ|NE expr */
- 218, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- 218, /* (202) expr ::= expr PLUS|MINUS expr */
- 218, /* (203) expr ::= expr STAR|SLASH|REM expr */
- 218, /* (204) expr ::= expr CONCAT expr */
- 276, /* (205) likeop ::= NOT LIKE_KW|MATCH */
- 218, /* (206) expr ::= expr likeop expr */
- 218, /* (207) expr ::= expr likeop expr ESCAPE expr */
- 218, /* (208) expr ::= expr ISNULL|NOTNULL */
- 218, /* (209) expr ::= expr NOT NULL */
- 218, /* (210) expr ::= expr IS expr */
- 218, /* (211) expr ::= expr IS NOT expr */
- 218, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */
- 218, /* (213) expr ::= expr IS DISTINCT FROM expr */
- 218, /* (214) expr ::= NOT expr */
- 218, /* (215) expr ::= BITNOT expr */
- 218, /* (216) expr ::= PLUS|MINUS expr */
- 218, /* (217) expr ::= expr PTR expr */
- 277, /* (218) between_op ::= BETWEEN */
- 277, /* (219) between_op ::= NOT BETWEEN */
- 218, /* (220) expr ::= expr between_op expr AND expr */
- 278, /* (221) in_op ::= IN */
- 278, /* (222) in_op ::= NOT IN */
- 218, /* (223) expr ::= expr in_op LP exprlist RP */
- 218, /* (224) expr ::= LP select RP */
- 218, /* (225) expr ::= expr in_op LP select RP */
- 218, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */
- 218, /* (227) expr ::= EXISTS LP select RP */
- 218, /* (228) expr ::= CASE case_operand case_exprlist case_else END */
- 281, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- 281, /* (230) case_exprlist ::= WHEN expr THEN expr */
- 282, /* (231) case_else ::= ELSE expr */
- 282, /* (232) case_else ::= */
- 280, /* (233) case_operand ::= */
- 263, /* (234) exprlist ::= */
- 254, /* (235) nexprlist ::= nexprlist COMMA expr */
- 254, /* (236) nexprlist ::= expr */
- 279, /* (237) paren_exprlist ::= */
- 279, /* (238) paren_exprlist ::= LP exprlist RP */
- 191, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
- 283, /* (240) uniqueflag ::= UNIQUE */
- 283, /* (241) uniqueflag ::= */
- 222, /* (242) eidlist_opt ::= */
- 222, /* (243) eidlist_opt ::= LP eidlist RP */
- 233, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */
- 233, /* (245) eidlist ::= nm collate sortorder */
- 284, /* (246) collate ::= */
- 284, /* (247) collate ::= COLLATE ID|STRING */
- 191, /* (248) cmd ::= DROP INDEX ifexists fullname */
- 191, /* (249) cmd ::= VACUUM vinto */
- 191, /* (250) cmd ::= VACUUM nm vinto */
- 285, /* (251) vinto ::= INTO expr */
- 285, /* (252) vinto ::= */
- 191, /* (253) cmd ::= PRAGMA nm dbnm */
- 191, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */
- 191, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */
- 191, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */
- 191, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */
- 212, /* (258) plus_num ::= PLUS INTEGER|FLOAT */
- 213, /* (259) minus_num ::= MINUS INTEGER|FLOAT */
- 191, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
- 287, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
- 289, /* (262) trigger_time ::= BEFORE|AFTER */
- 289, /* (263) trigger_time ::= INSTEAD OF */
- 289, /* (264) trigger_time ::= */
- 290, /* (265) trigger_event ::= DELETE|INSERT */
- 290, /* (266) trigger_event ::= UPDATE */
- 290, /* (267) trigger_event ::= UPDATE OF idlist */
- 292, /* (268) when_clause ::= */
- 292, /* (269) when_clause ::= WHEN expr */
- 288, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
- 288, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */
- 294, /* (272) trnm ::= nm DOT nm */
- 295, /* (273) tridxby ::= INDEXED BY nm */
- 295, /* (274) tridxby ::= NOT INDEXED */
- 293, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
- 293, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
- 293, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
- 293, /* (278) trigger_cmd ::= scanpt select scanpt */
- 218, /* (279) expr ::= RAISE LP IGNORE RP */
- 218, /* (280) expr ::= RAISE LP raisetype COMMA nm RP */
- 237, /* (281) raisetype ::= ROLLBACK */
- 237, /* (282) raisetype ::= ABORT */
- 237, /* (283) raisetype ::= FAIL */
- 191, /* (284) cmd ::= DROP TRIGGER ifexists fullname */
- 191, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
- 191, /* (286) cmd ::= DETACH database_kw_opt expr */
- 297, /* (287) key_opt ::= */
- 297, /* (288) key_opt ::= KEY expr */
- 191, /* (289) cmd ::= REINDEX */
- 191, /* (290) cmd ::= REINDEX nm dbnm */
- 191, /* (291) cmd ::= ANALYZE */
- 191, /* (292) cmd ::= ANALYZE nm dbnm */
- 191, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */
- 191, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
- 191, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
- 298, /* (296) add_column_fullname ::= fullname */
- 191, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
- 191, /* (298) cmd ::= create_vtab */
- 191, /* (299) cmd ::= create_vtab LP vtabarglist RP */
- 300, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
- 302, /* (301) vtabarg ::= */
- 303, /* (302) vtabargtoken ::= ANY */
- 303, /* (303) vtabargtoken ::= lp anylist RP */
- 304, /* (304) lp ::= LP */
- 268, /* (305) with ::= WITH wqlist */
- 268, /* (306) with ::= WITH RECURSIVE wqlist */
- 307, /* (307) wqas ::= AS */
- 307, /* (308) wqas ::= AS MATERIALIZED */
- 307, /* (309) wqas ::= AS NOT MATERIALIZED */
- 306, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */
- 308, /* (311) withnm ::= nm */
- 242, /* (312) wqlist ::= wqitem */
- 242, /* (313) wqlist ::= wqlist COMMA wqitem */
- 309, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- 310, /* (315) windowdefn ::= nm AS LP window RP */
- 311, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- 311, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- 311, /* (318) window ::= ORDER BY sortlist frame_opt */
- 311, /* (319) window ::= nm ORDER BY sortlist frame_opt */
- 311, /* (320) window ::= nm frame_opt */
- 312, /* (321) frame_opt ::= */
- 312, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- 312, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- 316, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */
- 318, /* (325) frame_bound_s ::= frame_bound */
- 318, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */
- 319, /* (327) frame_bound_e ::= frame_bound */
- 319, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */
- 317, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */
- 317, /* (330) frame_bound ::= CURRENT ROW */
- 320, /* (331) frame_exclude_opt ::= */
- 320, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */
- 321, /* (333) frame_exclude ::= NO OTHERS */
- 321, /* (334) frame_exclude ::= CURRENT ROW */
- 321, /* (335) frame_exclude ::= GROUP|TIES */
- 252, /* (336) window_clause ::= WINDOW windowdefn_list */
- 275, /* (337) filter_over ::= filter_clause over_clause */
- 275, /* (338) filter_over ::= over_clause */
- 275, /* (339) filter_over ::= filter_clause */
- 315, /* (340) over_clause ::= OVER LP window RP */
- 315, /* (341) over_clause ::= OVER nm */
- 314, /* (342) filter_clause ::= FILTER LP WHERE expr RP */
- 217, /* (343) term ::= QNUMBER */
- 186, /* (344) input ::= cmdlist */
- 187, /* (345) cmdlist ::= cmdlist ecmd */
- 187, /* (346) cmdlist ::= ecmd */
- 188, /* (347) ecmd ::= SEMI */
- 188, /* (348) ecmd ::= cmdx SEMI */
- 188, /* (349) ecmd ::= explain cmdx SEMI */
- 193, /* (350) trans_opt ::= */
- 193, /* (351) trans_opt ::= TRANSACTION */
- 193, /* (352) trans_opt ::= TRANSACTION nm */
- 195, /* (353) savepoint_opt ::= SAVEPOINT */
- 195, /* (354) savepoint_opt ::= */
- 191, /* (355) cmd ::= create_table create_table_args */
- 204, /* (356) table_option_set ::= table_option */
- 202, /* (357) columnlist ::= columnlist COMMA columnname carglist */
- 202, /* (358) columnlist ::= columnname carglist */
- 194, /* (359) nm ::= ID|INDEXED|JOIN_KW */
- 194, /* (360) nm ::= STRING */
- 209, /* (361) typetoken ::= typename */
- 210, /* (362) typename ::= ID|STRING */
- 211, /* (363) signed ::= plus_num */
- 211, /* (364) signed ::= minus_num */
- 208, /* (365) carglist ::= carglist ccons */
- 208, /* (366) carglist ::= */
- 216, /* (367) ccons ::= NULL onconf */
- 216, /* (368) ccons ::= GENERATED ALWAYS AS generated */
- 216, /* (369) ccons ::= AS generated */
- 203, /* (370) conslist_opt ::= COMMA conslist */
- 229, /* (371) conslist ::= conslist tconscomma tcons */
- 229, /* (372) conslist ::= tcons */
- 230, /* (373) tconscomma ::= */
- 234, /* (374) defer_subclause_opt ::= defer_subclause */
- 236, /* (375) resolvetype ::= raisetype */
- 240, /* (376) selectnowith ::= oneselect */
- 241, /* (377) oneselect ::= values */
- 256, /* (378) sclp ::= selcollist COMMA */
- 257, /* (379) as ::= ID|STRING */
- 266, /* (380) indexed_opt ::= indexed_by */
- 274, /* (381) returning ::= */
- 218, /* (382) expr ::= term */
- 276, /* (383) likeop ::= LIKE_KW|MATCH */
- 280, /* (384) case_operand ::= expr */
- 263, /* (385) exprlist ::= nexprlist */
- 286, /* (386) nmnum ::= plus_num */
- 286, /* (387) nmnum ::= nm */
- 286, /* (388) nmnum ::= ON */
- 286, /* (389) nmnum ::= DELETE */
- 286, /* (390) nmnum ::= DEFAULT */
- 212, /* (391) plus_num ::= INTEGER|FLOAT */
- 291, /* (392) foreach_clause ::= */
- 291, /* (393) foreach_clause ::= FOR EACH ROW */
- 294, /* (394) trnm ::= nm */
- 295, /* (395) tridxby ::= */
- 296, /* (396) database_kw_opt ::= DATABASE */
- 296, /* (397) database_kw_opt ::= */
- 299, /* (398) kwcolumn_opt ::= */
- 299, /* (399) kwcolumn_opt ::= COLUMNKW */
- 301, /* (400) vtabarglist ::= vtabarg */
- 301, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */
- 302, /* (402) vtabarg ::= vtabarg vtabargtoken */
- 305, /* (403) anylist ::= */
- 305, /* (404) anylist ::= anylist LP anylist RP */
- 305, /* (405) anylist ::= anylist ANY */
- 268, /* (406) with ::= */
- 309, /* (407) windowdefn_list ::= windowdefn */
- 311, /* (408) window ::= frame_opt */
+ 191, /* (0) explain ::= EXPLAIN */
+ 191, /* (1) explain ::= EXPLAIN QUERY PLAN */
+ 190, /* (2) cmdx ::= cmd */
+ 192, /* (3) cmd ::= BEGIN transtype trans_opt */
+ 193, /* (4) transtype ::= */
+ 193, /* (5) transtype ::= DEFERRED */
+ 193, /* (6) transtype ::= IMMEDIATE */
+ 193, /* (7) transtype ::= EXCLUSIVE */
+ 192, /* (8) cmd ::= COMMIT|END trans_opt */
+ 192, /* (9) cmd ::= ROLLBACK trans_opt */
+ 192, /* (10) cmd ::= SAVEPOINT nm */
+ 192, /* (11) cmd ::= RELEASE savepoint_opt nm */
+ 192, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ 197, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ 199, /* (14) createkw ::= CREATE */
+ 201, /* (15) ifnotexists ::= */
+ 201, /* (16) ifnotexists ::= IF NOT EXISTS */
+ 200, /* (17) temp ::= TEMP */
+ 200, /* (18) temp ::= */
+ 198, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
+ 198, /* (20) create_table_args ::= AS select */
+ 205, /* (21) table_option_set ::= */
+ 205, /* (22) table_option_set ::= table_option_set COMMA table_option */
+ 207, /* (23) table_option ::= WITHOUT nm */
+ 207, /* (24) table_option ::= nm */
+ 208, /* (25) columnname ::= nm typetoken */
+ 210, /* (26) typetoken ::= */
+ 210, /* (27) typetoken ::= typename LP signed RP */
+ 210, /* (28) typetoken ::= typename LP signed COMMA signed RP */
+ 211, /* (29) typename ::= typename ID|STRING */
+ 215, /* (30) scanpt ::= */
+ 216, /* (31) scantok ::= */
+ 217, /* (32) ccons ::= CONSTRAINT nm */
+ 217, /* (33) ccons ::= DEFAULT scantok term */
+ 217, /* (34) ccons ::= DEFAULT LP expr RP */
+ 217, /* (35) ccons ::= DEFAULT PLUS scantok term */
+ 217, /* (36) ccons ::= DEFAULT MINUS scantok term */
+ 217, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
+ 217, /* (38) ccons ::= NOT NULL onconf */
+ 217, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
+ 217, /* (40) ccons ::= UNIQUE onconf */
+ 217, /* (41) ccons ::= CHECK LP expr RP */
+ 217, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
+ 217, /* (43) ccons ::= defer_subclause */
+ 217, /* (44) ccons ::= COLLATE ID|STRING */
+ 226, /* (45) generated ::= LP expr RP */
+ 226, /* (46) generated ::= LP expr RP ID */
+ 222, /* (47) autoinc ::= */
+ 222, /* (48) autoinc ::= AUTOINCR */
+ 224, /* (49) refargs ::= */
+ 224, /* (50) refargs ::= refargs refarg */
+ 227, /* (51) refarg ::= MATCH nm */
+ 227, /* (52) refarg ::= ON INSERT refact */
+ 227, /* (53) refarg ::= ON DELETE refact */
+ 227, /* (54) refarg ::= ON UPDATE refact */
+ 228, /* (55) refact ::= SET NULL */
+ 228, /* (56) refact ::= SET DEFAULT */
+ 228, /* (57) refact ::= CASCADE */
+ 228, /* (58) refact ::= RESTRICT */
+ 228, /* (59) refact ::= NO ACTION */
+ 225, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+ 225, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ 229, /* (62) init_deferred_pred_opt ::= */
+ 229, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ 229, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+ 204, /* (65) conslist_opt ::= */
+ 231, /* (66) tconscomma ::= COMMA */
+ 232, /* (67) tcons ::= CONSTRAINT nm */
+ 232, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+ 232, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
+ 232, /* (70) tcons ::= CHECK LP expr RP onconf */
+ 232, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ 235, /* (72) defer_subclause_opt ::= */
+ 220, /* (73) onconf ::= */
+ 220, /* (74) onconf ::= ON CONFLICT resolvetype */
+ 236, /* (75) orconf ::= */
+ 236, /* (76) orconf ::= OR resolvetype */
+ 237, /* (77) resolvetype ::= IGNORE */
+ 237, /* (78) resolvetype ::= REPLACE */
+ 192, /* (79) cmd ::= DROP TABLE ifexists fullname */
+ 239, /* (80) ifexists ::= IF EXISTS */
+ 239, /* (81) ifexists ::= */
+ 192, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ 192, /* (83) cmd ::= DROP VIEW ifexists fullname */
+ 192, /* (84) cmd ::= select */
+ 206, /* (85) select ::= WITH wqlist selectnowith */
+ 206, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
+ 206, /* (87) select ::= selectnowith */
+ 241, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
+ 244, /* (89) multiselect_op ::= UNION */
+ 244, /* (90) multiselect_op ::= UNION ALL */
+ 244, /* (91) multiselect_op ::= EXCEPT|INTERSECT */
+ 242, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ 242, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+ 254, /* (94) values ::= VALUES LP nexprlist RP */
+ 242, /* (95) oneselect ::= mvalues */
+ 256, /* (96) mvalues ::= values COMMA LP nexprlist RP */
+ 256, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */
+ 245, /* (98) distinct ::= DISTINCT */
+ 245, /* (99) distinct ::= ALL */
+ 245, /* (100) distinct ::= */
+ 257, /* (101) sclp ::= */
+ 246, /* (102) selcollist ::= sclp scanpt expr scanpt as */
+ 246, /* (103) selcollist ::= sclp scanpt STAR */
+ 246, /* (104) selcollist ::= sclp scanpt nm DOT STAR */
+ 258, /* (105) as ::= AS nm */
+ 258, /* (106) as ::= */
+ 247, /* (107) from ::= */
+ 247, /* (108) from ::= FROM seltablist */
+ 260, /* (109) stl_prefix ::= seltablist joinop */
+ 260, /* (110) stl_prefix ::= */
+ 259, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */
+ 259, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
+ 259, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
+ 259, /* (114) seltablist ::= stl_prefix LP select RP as on_using */
+ 259, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */
+ 202, /* (116) dbnm ::= */
+ 202, /* (117) dbnm ::= DOT nm */
+ 240, /* (118) fullname ::= nm */
+ 240, /* (119) fullname ::= nm DOT nm */
+ 265, /* (120) xfullname ::= nm */
+ 265, /* (121) xfullname ::= nm DOT nm */
+ 265, /* (122) xfullname ::= nm DOT nm AS nm */
+ 265, /* (123) xfullname ::= nm AS nm */
+ 261, /* (124) joinop ::= COMMA|JOIN */
+ 261, /* (125) joinop ::= JOIN_KW JOIN */
+ 261, /* (126) joinop ::= JOIN_KW nm JOIN */
+ 261, /* (127) joinop ::= JOIN_KW nm nm JOIN */
+ 262, /* (128) on_using ::= ON expr */
+ 262, /* (129) on_using ::= USING LP idlist RP */
+ 262, /* (130) on_using ::= */
+ 267, /* (131) indexed_opt ::= */
+ 263, /* (132) indexed_by ::= INDEXED BY nm */
+ 263, /* (133) indexed_by ::= NOT INDEXED */
+ 251, /* (134) orderby_opt ::= */
+ 251, /* (135) orderby_opt ::= ORDER BY sortlist */
+ 233, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */
+ 233, /* (137) sortlist ::= expr sortorder nulls */
+ 221, /* (138) sortorder ::= ASC */
+ 221, /* (139) sortorder ::= DESC */
+ 221, /* (140) sortorder ::= */
+ 268, /* (141) nulls ::= NULLS FIRST */
+ 268, /* (142) nulls ::= NULLS LAST */
+ 268, /* (143) nulls ::= */
+ 249, /* (144) groupby_opt ::= */
+ 249, /* (145) groupby_opt ::= GROUP BY nexprlist */
+ 250, /* (146) having_opt ::= */
+ 250, /* (147) having_opt ::= HAVING expr */
+ 252, /* (148) limit_opt ::= */
+ 252, /* (149) limit_opt ::= LIMIT expr */
+ 252, /* (150) limit_opt ::= LIMIT expr OFFSET expr */
+ 252, /* (151) limit_opt ::= LIMIT expr COMMA expr */
+ 192, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
+ 248, /* (153) where_opt ::= */
+ 248, /* (154) where_opt ::= WHERE expr */
+ 270, /* (155) where_opt_ret ::= */
+ 270, /* (156) where_opt_ret ::= WHERE expr */
+ 270, /* (157) where_opt_ret ::= RETURNING selcollist */
+ 270, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */
+ 192, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
+ 271, /* (160) setlist ::= setlist COMMA nm EQ expr */
+ 271, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */
+ 271, /* (162) setlist ::= nm EQ expr */
+ 271, /* (163) setlist ::= LP idlist RP EQ expr */
+ 192, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ 192, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
+ 274, /* (166) upsert ::= */
+ 274, /* (167) upsert ::= RETURNING selcollist */
+ 274, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
+ 274, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
+ 274, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */
+ 274, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
+ 275, /* (172) returning ::= RETURNING selcollist */
+ 272, /* (173) insert_cmd ::= INSERT orconf */
+ 272, /* (174) insert_cmd ::= REPLACE */
+ 273, /* (175) idlist_opt ::= */
+ 273, /* (176) idlist_opt ::= LP idlist RP */
+ 266, /* (177) idlist ::= idlist COMMA nm */
+ 266, /* (178) idlist ::= nm */
+ 219, /* (179) expr ::= LP expr RP */
+ 219, /* (180) expr ::= ID|INDEXED|JOIN_KW */
+ 219, /* (181) expr ::= nm DOT nm */
+ 219, /* (182) expr ::= nm DOT nm DOT nm */
+ 218, /* (183) term ::= NULL|FLOAT|BLOB */
+ 218, /* (184) term ::= STRING */
+ 218, /* (185) term ::= INTEGER */
+ 219, /* (186) expr ::= VARIABLE */
+ 219, /* (187) expr ::= expr COLLATE ID|STRING */
+ 219, /* (188) expr ::= CAST LP expr AS typetoken RP */
+ 219, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ 219, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+ 219, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ 219, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ 219, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+ 219, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ 218, /* (195) term ::= CTIME_KW */
+ 219, /* (196) expr ::= LP nexprlist COMMA expr RP */
+ 219, /* (197) expr ::= expr AND expr */
+ 219, /* (198) expr ::= expr OR expr */
+ 219, /* (199) expr ::= expr LT|GT|GE|LE expr */
+ 219, /* (200) expr ::= expr EQ|NE expr */
+ 219, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ 219, /* (202) expr ::= expr PLUS|MINUS expr */
+ 219, /* (203) expr ::= expr STAR|SLASH|REM expr */
+ 219, /* (204) expr ::= expr CONCAT expr */
+ 277, /* (205) likeop ::= NOT LIKE_KW|MATCH */
+ 219, /* (206) expr ::= expr likeop expr */
+ 219, /* (207) expr ::= expr likeop expr ESCAPE expr */
+ 219, /* (208) expr ::= expr ISNULL|NOTNULL */
+ 219, /* (209) expr ::= expr NOT NULL */
+ 219, /* (210) expr ::= expr IS expr */
+ 219, /* (211) expr ::= expr IS NOT expr */
+ 219, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */
+ 219, /* (213) expr ::= expr IS DISTINCT FROM expr */
+ 219, /* (214) expr ::= NOT expr */
+ 219, /* (215) expr ::= BITNOT expr */
+ 219, /* (216) expr ::= PLUS|MINUS expr */
+ 219, /* (217) expr ::= expr PTR expr */
+ 278, /* (218) between_op ::= BETWEEN */
+ 278, /* (219) between_op ::= NOT BETWEEN */
+ 219, /* (220) expr ::= expr between_op expr AND expr */
+ 279, /* (221) in_op ::= IN */
+ 279, /* (222) in_op ::= NOT IN */
+ 219, /* (223) expr ::= expr in_op LP exprlist RP */
+ 219, /* (224) expr ::= LP select RP */
+ 219, /* (225) expr ::= expr in_op LP select RP */
+ 219, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */
+ 219, /* (227) expr ::= EXISTS LP select RP */
+ 219, /* (228) expr ::= CASE case_operand case_exprlist case_else END */
+ 282, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ 282, /* (230) case_exprlist ::= WHEN expr THEN expr */
+ 283, /* (231) case_else ::= ELSE expr */
+ 283, /* (232) case_else ::= */
+ 281, /* (233) case_operand ::= */
+ 264, /* (234) exprlist ::= */
+ 255, /* (235) nexprlist ::= nexprlist COMMA expr */
+ 255, /* (236) nexprlist ::= expr */
+ 280, /* (237) paren_exprlist ::= */
+ 280, /* (238) paren_exprlist ::= LP exprlist RP */
+ 192, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ 284, /* (240) uniqueflag ::= UNIQUE */
+ 284, /* (241) uniqueflag ::= */
+ 223, /* (242) eidlist_opt ::= */
+ 223, /* (243) eidlist_opt ::= LP eidlist RP */
+ 234, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */
+ 234, /* (245) eidlist ::= nm collate sortorder */
+ 285, /* (246) collate ::= */
+ 285, /* (247) collate ::= COLLATE ID|STRING */
+ 192, /* (248) cmd ::= DROP INDEX ifexists fullname */
+ 192, /* (249) cmd ::= VACUUM vinto */
+ 192, /* (250) cmd ::= VACUUM nm vinto */
+ 286, /* (251) vinto ::= INTO expr */
+ 286, /* (252) vinto ::= */
+ 192, /* (253) cmd ::= PRAGMA nm dbnm */
+ 192, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ 192, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ 192, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ 192, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ 213, /* (258) plus_num ::= PLUS INTEGER|FLOAT */
+ 214, /* (259) minus_num ::= MINUS INTEGER|FLOAT */
+ 192, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ 288, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ 290, /* (262) trigger_time ::= BEFORE|AFTER */
+ 290, /* (263) trigger_time ::= INSTEAD OF */
+ 290, /* (264) trigger_time ::= */
+ 291, /* (265) trigger_event ::= DELETE|INSERT */
+ 291, /* (266) trigger_event ::= UPDATE */
+ 291, /* (267) trigger_event ::= UPDATE OF idlist */
+ 293, /* (268) when_clause ::= */
+ 293, /* (269) when_clause ::= WHEN expr */
+ 289, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ 289, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */
+ 295, /* (272) trnm ::= nm DOT nm */
+ 296, /* (273) tridxby ::= INDEXED BY nm */
+ 296, /* (274) tridxby ::= NOT INDEXED */
+ 294, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ 294, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ 294, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ 294, /* (278) trigger_cmd ::= scanpt select scanpt */
+ 219, /* (279) expr ::= RAISE LP IGNORE RP */
+ 219, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */
+ 238, /* (281) raisetype ::= ROLLBACK */
+ 238, /* (282) raisetype ::= ABORT */
+ 238, /* (283) raisetype ::= FAIL */
+ 192, /* (284) cmd ::= DROP TRIGGER ifexists fullname */
+ 192, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ 192, /* (286) cmd ::= DETACH database_kw_opt expr */
+ 298, /* (287) key_opt ::= */
+ 298, /* (288) key_opt ::= KEY expr */
+ 192, /* (289) cmd ::= REINDEX */
+ 192, /* (290) cmd ::= REINDEX nm dbnm */
+ 192, /* (291) cmd ::= ANALYZE */
+ 192, /* (292) cmd ::= ANALYZE nm dbnm */
+ 192, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ 192, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ 192, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ 299, /* (296) add_column_fullname ::= fullname */
+ 192, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ 192, /* (298) cmd ::= create_vtab */
+ 192, /* (299) cmd ::= create_vtab LP vtabarglist RP */
+ 301, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 303, /* (301) vtabarg ::= */
+ 304, /* (302) vtabargtoken ::= ANY */
+ 304, /* (303) vtabargtoken ::= lp anylist RP */
+ 305, /* (304) lp ::= LP */
+ 269, /* (305) with ::= WITH wqlist */
+ 269, /* (306) with ::= WITH RECURSIVE wqlist */
+ 308, /* (307) wqas ::= AS */
+ 308, /* (308) wqas ::= AS MATERIALIZED */
+ 308, /* (309) wqas ::= AS NOT MATERIALIZED */
+ 307, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */
+ 309, /* (311) withnm ::= nm */
+ 243, /* (312) wqlist ::= wqitem */
+ 243, /* (313) wqlist ::= wqlist COMMA wqitem */
+ 310, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ 311, /* (315) windowdefn ::= nm AS LP window RP */
+ 312, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ 312, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ 312, /* (318) window ::= ORDER BY sortlist frame_opt */
+ 312, /* (319) window ::= nm ORDER BY sortlist frame_opt */
+ 312, /* (320) window ::= nm frame_opt */
+ 313, /* (321) frame_opt ::= */
+ 313, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ 313, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ 317, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */
+ 319, /* (325) frame_bound_s ::= frame_bound */
+ 319, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */
+ 320, /* (327) frame_bound_e ::= frame_bound */
+ 320, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ 318, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */
+ 318, /* (330) frame_bound ::= CURRENT ROW */
+ 321, /* (331) frame_exclude_opt ::= */
+ 321, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ 322, /* (333) frame_exclude ::= NO OTHERS */
+ 322, /* (334) frame_exclude ::= CURRENT ROW */
+ 322, /* (335) frame_exclude ::= GROUP|TIES */
+ 253, /* (336) window_clause ::= WINDOW windowdefn_list */
+ 276, /* (337) filter_over ::= filter_clause over_clause */
+ 276, /* (338) filter_over ::= over_clause */
+ 276, /* (339) filter_over ::= filter_clause */
+ 316, /* (340) over_clause ::= OVER LP window RP */
+ 316, /* (341) over_clause ::= OVER nm */
+ 315, /* (342) filter_clause ::= FILTER LP WHERE expr RP */
+ 218, /* (343) term ::= QNUMBER */
+ 187, /* (344) input ::= cmdlist */
+ 188, /* (345) cmdlist ::= cmdlist ecmd */
+ 188, /* (346) cmdlist ::= ecmd */
+ 189, /* (347) ecmd ::= SEMI */
+ 189, /* (348) ecmd ::= cmdx SEMI */
+ 189, /* (349) ecmd ::= explain cmdx SEMI */
+ 194, /* (350) trans_opt ::= */
+ 194, /* (351) trans_opt ::= TRANSACTION */
+ 194, /* (352) trans_opt ::= TRANSACTION nm */
+ 196, /* (353) savepoint_opt ::= SAVEPOINT */
+ 196, /* (354) savepoint_opt ::= */
+ 192, /* (355) cmd ::= create_table create_table_args */
+ 205, /* (356) table_option_set ::= table_option */
+ 203, /* (357) columnlist ::= columnlist COMMA columnname carglist */
+ 203, /* (358) columnlist ::= columnname carglist */
+ 195, /* (359) nm ::= ID|INDEXED|JOIN_KW */
+ 195, /* (360) nm ::= STRING */
+ 210, /* (361) typetoken ::= typename */
+ 211, /* (362) typename ::= ID|STRING */
+ 212, /* (363) signed ::= plus_num */
+ 212, /* (364) signed ::= minus_num */
+ 209, /* (365) carglist ::= carglist ccons */
+ 209, /* (366) carglist ::= */
+ 217, /* (367) ccons ::= NULL onconf */
+ 217, /* (368) ccons ::= GENERATED ALWAYS AS generated */
+ 217, /* (369) ccons ::= AS generated */
+ 204, /* (370) conslist_opt ::= COMMA conslist */
+ 230, /* (371) conslist ::= conslist tconscomma tcons */
+ 230, /* (372) conslist ::= tcons */
+ 231, /* (373) tconscomma ::= */
+ 235, /* (374) defer_subclause_opt ::= defer_subclause */
+ 237, /* (375) resolvetype ::= raisetype */
+ 241, /* (376) selectnowith ::= oneselect */
+ 242, /* (377) oneselect ::= values */
+ 257, /* (378) sclp ::= selcollist COMMA */
+ 258, /* (379) as ::= ID|STRING */
+ 267, /* (380) indexed_opt ::= indexed_by */
+ 275, /* (381) returning ::= */
+ 219, /* (382) expr ::= term */
+ 277, /* (383) likeop ::= LIKE_KW|MATCH */
+ 281, /* (384) case_operand ::= expr */
+ 264, /* (385) exprlist ::= nexprlist */
+ 287, /* (386) nmnum ::= plus_num */
+ 287, /* (387) nmnum ::= nm */
+ 287, /* (388) nmnum ::= ON */
+ 287, /* (389) nmnum ::= DELETE */
+ 287, /* (390) nmnum ::= DEFAULT */
+ 213, /* (391) plus_num ::= INTEGER|FLOAT */
+ 292, /* (392) foreach_clause ::= */
+ 292, /* (393) foreach_clause ::= FOR EACH ROW */
+ 295, /* (394) trnm ::= nm */
+ 296, /* (395) tridxby ::= */
+ 297, /* (396) database_kw_opt ::= DATABASE */
+ 297, /* (397) database_kw_opt ::= */
+ 300, /* (398) kwcolumn_opt ::= */
+ 300, /* (399) kwcolumn_opt ::= COLUMNKW */
+ 302, /* (400) vtabarglist ::= vtabarg */
+ 302, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */
+ 303, /* (402) vtabarg ::= vtabarg vtabargtoken */
+ 306, /* (403) anylist ::= */
+ 306, /* (404) anylist ::= anylist LP anylist RP */
+ 306, /* (405) anylist ::= anylist ANY */
+ 269, /* (406) with ::= */
+ 310, /* (407) windowdefn_list ::= windowdefn */
+ 312, /* (408) window ::= frame_opt */
};
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
@@ -175936,7 +178749,7 @@ static const signed char yyRuleInfoNRhs[] = {
-6, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
-3, /* (278) trigger_cmd ::= scanpt select scanpt */
-4, /* (279) expr ::= RAISE LP IGNORE RP */
- -6, /* (280) expr ::= RAISE LP raisetype COMMA nm RP */
+ -6, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */
-1, /* (281) raisetype ::= ROLLBACK */
-1, /* (282) raisetype ::= ABORT */
-1, /* (283) raisetype ::= FAIL */
@@ -176116,16 +178929,16 @@ static YYACTIONTYPE yy_reduce(
{ sqlite3FinishCoding(pParse); }
break;
case 3: /* cmd ::= BEGIN transtype trans_opt */
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy144);}
+{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy502);}
break;
case 4: /* transtype ::= */
-{yymsp[1].minor.yy144 = TK_DEFERRED;}
+{yymsp[1].minor.yy502 = TK_DEFERRED;}
break;
case 5: /* transtype ::= DEFERRED */
case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
case 324: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==324);
-{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/}
+{yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/}
break;
case 8: /* cmd ::= COMMIT|END trans_opt */
case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
@@ -176148,11 +178961,13 @@ static YYACTIONTYPE yy_reduce(
break;
case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
- sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy144,0,0,yymsp[-2].minor.yy144);
+ sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy502,0,0,yymsp[-2].minor.yy502);
}
break;
case 14: /* createkw ::= CREATE */
-{disableLookaside(pParse);}
+{
+ disableLookaside(pParse);
+}
break;
case 15: /* ifnotexists ::= */
case 18: /* temp ::= */ yytestcase(yyruleno==18);
@@ -176162,38 +178977,38 @@ static YYACTIONTYPE yy_reduce(
case 81: /* ifexists ::= */ yytestcase(yyruleno==81);
case 100: /* distinct ::= */ yytestcase(yyruleno==100);
case 246: /* collate ::= */ yytestcase(yyruleno==246);
-{yymsp[1].minor.yy144 = 0;}
+{yymsp[1].minor.yy502 = 0;}
break;
case 16: /* ifnotexists ::= IF NOT EXISTS */
-{yymsp[-2].minor.yy144 = 1;}
+{yymsp[-2].minor.yy502 = 1;}
break;
case 17: /* temp ::= TEMP */
-{yymsp[0].minor.yy144 = pParse->db->init.busy==0;}
+{yymsp[0].minor.yy502 = pParse->db->init.busy==0;}
break;
case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */
{
- sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy391,0);
+ sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy9,0);
}
break;
case 20: /* create_table_args ::= AS select */
{
- sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy555);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
+ sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy637);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy637);
}
break;
case 21: /* table_option_set ::= */
-{yymsp[1].minor.yy391 = 0;}
+{yymsp[1].minor.yy9 = 0;}
break;
case 22: /* table_option_set ::= table_option_set COMMA table_option */
-{yylhsminor.yy391 = yymsp[-2].minor.yy391|yymsp[0].minor.yy391;}
- yymsp[-2].minor.yy391 = yylhsminor.yy391;
+{yylhsminor.yy9 = yymsp[-2].minor.yy9|yymsp[0].minor.yy9;}
+ yymsp[-2].minor.yy9 = yylhsminor.yy9;
break;
case 23: /* table_option ::= WITHOUT nm */
{
if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
- yymsp[-1].minor.yy391 = TF_WithoutRowid | TF_NoVisibleRowid;
+ yymsp[-1].minor.yy9 = TF_WithoutRowid | TF_NoVisibleRowid;
}else{
- yymsp[-1].minor.yy391 = 0;
+ yymsp[-1].minor.yy9 = 0;
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
@@ -176201,13 +179016,13 @@ static YYACTIONTYPE yy_reduce(
case 24: /* table_option ::= nm */
{
if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){
- yylhsminor.yy391 = TF_Strict;
+ yylhsminor.yy9 = TF_Strict;
}else{
- yylhsminor.yy391 = 0;
+ yylhsminor.yy9 = 0;
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
- yymsp[0].minor.yy391 = yylhsminor.yy391;
+ yymsp[0].minor.yy9 = yylhsminor.yy9;
break;
case 25: /* columnname ::= nm typetoken */
{sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);}
@@ -176233,7 +179048,7 @@ static YYACTIONTYPE yy_reduce(
case 30: /* scanpt ::= */
{
assert( yyLookahead!=YYNOCODE );
- yymsp[1].minor.yy168 = yyLookaheadToken.z;
+ yymsp[1].minor.yy342 = yyLookaheadToken.z;
}
break;
case 31: /* scantok ::= */
@@ -176244,20 +179059,20 @@ static YYACTIONTYPE yy_reduce(
break;
case 32: /* ccons ::= CONSTRAINT nm */
case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67);
-{pParse->constraintName = yymsp[0].minor.yy0;}
+{ASSERT_IS_CREATE; pParse->u1.cr.constraintName = yymsp[0].minor.yy0;}
break;
case 33: /* ccons ::= DEFAULT scantok term */
-{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
+{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
break;
case 34: /* ccons ::= DEFAULT LP expr RP */
-{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
+{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy590,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
break;
case 35: /* ccons ::= DEFAULT PLUS scantok term */
-{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
+{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
break;
case 36: /* ccons ::= DEFAULT MINUS scantok term */
{
- Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy454, 0);
+ Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy590, 0);
sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);
}
break;
@@ -176272,151 +179087,155 @@ static YYACTIONTYPE yy_reduce(
}
break;
case 38: /* ccons ::= NOT NULL onconf */
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy144);}
+{sqlite3AddNotNull(pParse, yymsp[0].minor.yy502);}
break;
case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy144,yymsp[0].minor.yy144,yymsp[-2].minor.yy144);}
+{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy502,yymsp[0].minor.yy502,yymsp[-2].minor.yy502);}
break;
case 40: /* ccons ::= UNIQUE onconf */
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy144,0,0,0,0,
+{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy502,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
case 41: /* ccons ::= CHECK LP expr RP */
-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
+{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy590,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
break;
case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy144);}
+{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy402,yymsp[0].minor.yy502);}
break;
case 43: /* ccons ::= defer_subclause */
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy144);}
+{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy502);}
break;
case 44: /* ccons ::= COLLATE ID|STRING */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
break;
case 45: /* generated ::= LP expr RP */
-{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy454,0);}
+{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy590,0);}
break;
case 46: /* generated ::= LP expr RP ID */
-{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy454,&yymsp[0].minor.yy0);}
+{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy590,&yymsp[0].minor.yy0);}
break;
case 48: /* autoinc ::= AUTOINCR */
-{yymsp[0].minor.yy144 = 1;}
+{yymsp[0].minor.yy502 = 1;}
break;
case 49: /* refargs ::= */
-{ yymsp[1].minor.yy144 = OE_None*0x0101; /* EV: R-19803-45884 */}
+{ yymsp[1].minor.yy502 = OE_None*0x0101; /* EV: R-19803-45884 */}
break;
case 50: /* refargs ::= refargs refarg */
-{ yymsp[-1].minor.yy144 = (yymsp[-1].minor.yy144 & ~yymsp[0].minor.yy383.mask) | yymsp[0].minor.yy383.value; }
+{ yymsp[-1].minor.yy502 = (yymsp[-1].minor.yy502 & ~yymsp[0].minor.yy481.mask) | yymsp[0].minor.yy481.value; }
break;
case 51: /* refarg ::= MATCH nm */
-{ yymsp[-1].minor.yy383.value = 0; yymsp[-1].minor.yy383.mask = 0x000000; }
+{ yymsp[-1].minor.yy481.value = 0; yymsp[-1].minor.yy481.mask = 0x000000; }
break;
case 52: /* refarg ::= ON INSERT refact */
-{ yymsp[-2].minor.yy383.value = 0; yymsp[-2].minor.yy383.mask = 0x000000; }
+{ yymsp[-2].minor.yy481.value = 0; yymsp[-2].minor.yy481.mask = 0x000000; }
break;
case 53: /* refarg ::= ON DELETE refact */
-{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144; yymsp[-2].minor.yy383.mask = 0x0000ff; }
+{ yymsp[-2].minor.yy481.value = yymsp[0].minor.yy502; yymsp[-2].minor.yy481.mask = 0x0000ff; }
break;
case 54: /* refarg ::= ON UPDATE refact */
-{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144<<8; yymsp[-2].minor.yy383.mask = 0x00ff00; }
+{ yymsp[-2].minor.yy481.value = yymsp[0].minor.yy502<<8; yymsp[-2].minor.yy481.mask = 0x00ff00; }
break;
case 55: /* refact ::= SET NULL */
-{ yymsp[-1].minor.yy144 = OE_SetNull; /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy502 = OE_SetNull; /* EV: R-33326-45252 */}
break;
case 56: /* refact ::= SET DEFAULT */
-{ yymsp[-1].minor.yy144 = OE_SetDflt; /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy502 = OE_SetDflt; /* EV: R-33326-45252 */}
break;
case 57: /* refact ::= CASCADE */
-{ yymsp[0].minor.yy144 = OE_Cascade; /* EV: R-33326-45252 */}
+{ yymsp[0].minor.yy502 = OE_Cascade; /* EV: R-33326-45252 */}
break;
case 58: /* refact ::= RESTRICT */
-{ yymsp[0].minor.yy144 = OE_Restrict; /* EV: R-33326-45252 */}
+{ yymsp[0].minor.yy502 = OE_Restrict; /* EV: R-33326-45252 */}
break;
case 59: /* refact ::= NO ACTION */
-{ yymsp[-1].minor.yy144 = OE_None; /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy502 = OE_None; /* EV: R-33326-45252 */}
break;
case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
-{yymsp[-2].minor.yy144 = 0;}
+{yymsp[-2].minor.yy502 = 0;}
break;
case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76);
case 173: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==173);
-{yymsp[-1].minor.yy144 = yymsp[0].minor.yy144;}
+{yymsp[-1].minor.yy502 = yymsp[0].minor.yy502;}
break;
case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80);
case 219: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==219);
case 222: /* in_op ::= NOT IN */ yytestcase(yyruleno==222);
case 247: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==247);
-{yymsp[-1].minor.yy144 = 1;}
+{yymsp[-1].minor.yy502 = 1;}
break;
case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
-{yymsp[-1].minor.yy144 = 0;}
+{yymsp[-1].minor.yy502 = 0;}
break;
case 66: /* tconscomma ::= COMMA */
-{pParse->constraintName.n = 0;}
+{ASSERT_IS_CREATE; pParse->u1.cr.constraintName.n = 0;}
break;
case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy144,yymsp[-2].minor.yy144,0);}
+{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy402,yymsp[0].minor.yy502,yymsp[-2].minor.yy502,0);}
break;
case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy144,0,0,0,0,
+{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy402,yymsp[0].minor.yy502,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
case 70: /* tcons ::= CHECK LP expr RP onconf */
-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy454,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
+{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy590,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
break;
case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
{
- sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy144);
- sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy144);
+ sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy402, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy402, yymsp[-1].minor.yy502);
+ sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy502);
}
break;
case 73: /* onconf ::= */
case 75: /* orconf ::= */ yytestcase(yyruleno==75);
-{yymsp[1].minor.yy144 = OE_Default;}
+{yymsp[1].minor.yy502 = OE_Default;}
break;
case 74: /* onconf ::= ON CONFLICT resolvetype */
-{yymsp[-2].minor.yy144 = yymsp[0].minor.yy144;}
+{yymsp[-2].minor.yy502 = yymsp[0].minor.yy502;}
break;
case 77: /* resolvetype ::= IGNORE */
-{yymsp[0].minor.yy144 = OE_Ignore;}
+{yymsp[0].minor.yy502 = OE_Ignore;}
break;
case 78: /* resolvetype ::= REPLACE */
case 174: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==174);
-{yymsp[0].minor.yy144 = OE_Replace;}
+{yymsp[0].minor.yy502 = OE_Replace;}
break;
case 79: /* cmd ::= DROP TABLE ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy203, 0, yymsp[-1].minor.yy144);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy563, 0, yymsp[-1].minor.yy502);
}
break;
case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
{
- sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[0].minor.yy555, yymsp[-7].minor.yy144, yymsp[-5].minor.yy144);
+ sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy402, yymsp[0].minor.yy637, yymsp[-7].minor.yy502, yymsp[-5].minor.yy502);
}
break;
case 83: /* cmd ::= DROP VIEW ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy203, 1, yymsp[-1].minor.yy144);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy563, 1, yymsp[-1].minor.yy502);
}
break;
case 84: /* cmd ::= select */
{
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
- sqlite3Select(pParse, yymsp[0].minor.yy555, &dest);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555);
+ if( (pParse->db->mDbFlags & DBFLAG_EncodingFixed)!=0
+ || sqlite3ReadSchema(pParse)==SQLITE_OK
+ ){
+ sqlite3Select(pParse, yymsp[0].minor.yy637, &dest);
+ }
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy637);
}
break;
case 85: /* select ::= WITH wqlist selectnowith */
-{yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
+{yymsp[-2].minor.yy637 = attachWithToSelect(pParse,yymsp[0].minor.yy637,yymsp[-1].minor.yy125);}
break;
case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */
-{yymsp[-3].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);}
+{yymsp[-3].minor.yy637 = attachWithToSelect(pParse,yymsp[0].minor.yy637,yymsp[-1].minor.yy125);}
break;
case 87: /* select ::= selectnowith */
{
- Select *p = yymsp[0].minor.yy555;
+ Select *p = yymsp[0].minor.yy637;
if( p ){
parserDoubleLinkSelect(pParse, p);
}
@@ -176424,8 +179243,8 @@ static YYACTIONTYPE yy_reduce(
break;
case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */
{
- Select *pRhs = yymsp[0].minor.yy555;
- Select *pLhs = yymsp[-2].minor.yy555;
+ Select *pRhs = yymsp[0].minor.yy637;
+ Select *pLhs = yymsp[-2].minor.yy637;
if( pRhs && pRhs->pPrior ){
SrcList *pFrom;
Token x;
@@ -176435,60 +179254,60 @@ static YYACTIONTYPE yy_reduce(
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
}
if( pRhs ){
- pRhs->op = (u8)yymsp[-1].minor.yy144;
+ pRhs->op = (u8)yymsp[-1].minor.yy502;
pRhs->pPrior = pLhs;
- if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
- pRhs->selFlags &= ~SF_MultiValue;
- if( yymsp[-1].minor.yy144!=TK_ALL ) pParse->hasCompound = 1;
+ if( ALWAYS(pLhs) ) pLhs->selFlags &= ~(u32)SF_MultiValue;
+ pRhs->selFlags &= ~(u32)SF_MultiValue;
+ if( yymsp[-1].minor.yy502!=TK_ALL ) pParse->hasCompound = 1;
}else{
sqlite3SelectDelete(pParse->db, pLhs);
}
- yymsp[-2].minor.yy555 = pRhs;
+ yymsp[-2].minor.yy637 = pRhs;
}
break;
case 89: /* multiselect_op ::= UNION */
case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91);
-{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-OP*/}
+{yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-OP*/}
break;
case 90: /* multiselect_op ::= UNION ALL */
-{yymsp[-1].minor.yy144 = TK_ALL;}
+{yymsp[-1].minor.yy502 = TK_ALL;}
break;
case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
- yymsp[-8].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy203,yymsp[-4].minor.yy454,yymsp[-3].minor.yy14,yymsp[-2].minor.yy454,yymsp[-1].minor.yy14,yymsp[-7].minor.yy144,yymsp[0].minor.yy454);
+ yymsp[-8].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy402,yymsp[-5].minor.yy563,yymsp[-4].minor.yy590,yymsp[-3].minor.yy402,yymsp[-2].minor.yy590,yymsp[-1].minor.yy402,yymsp[-7].minor.yy502,yymsp[0].minor.yy590);
}
break;
case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
{
- yymsp[-9].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy14,yymsp[-6].minor.yy203,yymsp[-5].minor.yy454,yymsp[-4].minor.yy14,yymsp[-3].minor.yy454,yymsp[-1].minor.yy14,yymsp[-8].minor.yy144,yymsp[0].minor.yy454);
- if( yymsp[-9].minor.yy555 ){
- yymsp[-9].minor.yy555->pWinDefn = yymsp[-2].minor.yy211;
+ yymsp[-9].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy402,yymsp[-6].minor.yy563,yymsp[-5].minor.yy590,yymsp[-4].minor.yy402,yymsp[-3].minor.yy590,yymsp[-1].minor.yy402,yymsp[-8].minor.yy502,yymsp[0].minor.yy590);
+ if( yymsp[-9].minor.yy637 ){
+ yymsp[-9].minor.yy637->pWinDefn = yymsp[-2].minor.yy483;
}else{
- sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy211);
+ sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy483);
}
}
break;
case 94: /* values ::= VALUES LP nexprlist RP */
{
- yymsp[-3].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0);
+ yymsp[-3].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy402,0,0,0,0,0,SF_Values,0);
}
break;
case 95: /* oneselect ::= mvalues */
{
- sqlite3MultiValuesEnd(pParse, yymsp[0].minor.yy555);
+ sqlite3MultiValuesEnd(pParse, yymsp[0].minor.yy637);
}
break;
case 96: /* mvalues ::= values COMMA LP nexprlist RP */
case 97: /* mvalues ::= mvalues COMMA LP nexprlist RP */ yytestcase(yyruleno==97);
{
- yymsp[-4].minor.yy555 = sqlite3MultiValues(pParse, yymsp[-4].minor.yy555, yymsp[-1].minor.yy14);
+ yymsp[-4].minor.yy637 = sqlite3MultiValues(pParse, yymsp[-4].minor.yy637, yymsp[-1].minor.yy402);
}
break;
case 98: /* distinct ::= DISTINCT */
-{yymsp[0].minor.yy144 = SF_Distinct;}
+{yymsp[0].minor.yy502 = SF_Distinct;}
break;
case 99: /* distinct ::= ALL */
-{yymsp[0].minor.yy144 = SF_All;}
+{yymsp[0].minor.yy502 = SF_All;}
break;
case 101: /* sclp ::= */
case 134: /* orderby_opt ::= */ yytestcase(yyruleno==134);
@@ -176496,20 +179315,20 @@ static YYACTIONTYPE yy_reduce(
case 234: /* exprlist ::= */ yytestcase(yyruleno==234);
case 237: /* paren_exprlist ::= */ yytestcase(yyruleno==237);
case 242: /* eidlist_opt ::= */ yytestcase(yyruleno==242);
-{yymsp[1].minor.yy14 = 0;}
+{yymsp[1].minor.yy402 = 0;}
break;
case 102: /* selcollist ::= sclp scanpt expr scanpt as */
{
- yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[-2].minor.yy454);
- if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[0].minor.yy0, 1);
- sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy14,yymsp[-3].minor.yy168,yymsp[-1].minor.yy168);
+ yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy402, yymsp[-2].minor.yy590);
+ if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy402, &yymsp[0].minor.yy0, 1);
+ sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy402,yymsp[-3].minor.yy342,yymsp[-1].minor.yy342);
}
break;
case 103: /* selcollist ::= sclp scanpt STAR */
{
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
- yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, p);
+ yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy402, p);
}
break;
case 104: /* selcollist ::= sclp scanpt nm DOT STAR */
@@ -176519,7 +179338,7 @@ static YYACTIONTYPE yy_reduce(
sqlite3ExprSetErrorOffset(pRight, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
- yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, pDot);
+ yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, pDot);
}
break;
case 105: /* as ::= AS nm */
@@ -176530,55 +179349,65 @@ static YYACTIONTYPE yy_reduce(
break;
case 107: /* from ::= */
case 110: /* stl_prefix ::= */ yytestcase(yyruleno==110);
-{yymsp[1].minor.yy203 = 0;}
+{yymsp[1].minor.yy563 = 0;}
break;
case 108: /* from ::= FROM seltablist */
{
- yymsp[-1].minor.yy203 = yymsp[0].minor.yy203;
- sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy203);
+ yymsp[-1].minor.yy563 = yymsp[0].minor.yy563;
+ sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy563);
}
break;
case 109: /* stl_prefix ::= seltablist joinop */
{
- if( ALWAYS(yymsp[-1].minor.yy203 && yymsp[-1].minor.yy203->nSrc>0) ) yymsp[-1].minor.yy203->a[yymsp[-1].minor.yy203->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy144;
+ if( ALWAYS(yymsp[-1].minor.yy563 && yymsp[-1].minor.yy563->nSrc>0) ) yymsp[-1].minor.yy563->a[yymsp[-1].minor.yy563->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy502;
}
break;
case 111: /* seltablist ::= stl_prefix nm dbnm as on_using */
{
- yymsp[-4].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy203,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
+ yymsp[-4].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy563,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421);
}
break;
case 112: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
{
- yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy269);
- sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-1].minor.yy0);
+ yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy421);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy563, &yymsp[-1].minor.yy0);
}
break;
case 113: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
{
- yymsp[-7].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy203,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
- sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy203, yymsp[-3].minor.yy14);
+ yymsp[-7].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy563,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421);
+ sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy563, yymsp[-3].minor.yy402);
}
break;
case 114: /* seltablist ::= stl_prefix LP select RP as on_using */
{
- yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy555,&yymsp[0].minor.yy269);
+ yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy637,&yymsp[0].minor.yy421);
}
break;
case 115: /* seltablist ::= stl_prefix LP seltablist RP as on_using */
{
- if( yymsp[-5].minor.yy203==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy269.pOn==0 && yymsp[0].minor.yy269.pUsing==0 ){
- yymsp[-5].minor.yy203 = yymsp[-3].minor.yy203;
- }else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){
- yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
- if( yymsp[-5].minor.yy203 ){
- SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1];
- SrcItem *pOld = yymsp[-3].minor.yy203->a;
+ if( yymsp[-5].minor.yy563==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy421.pOn==0 && yymsp[0].minor.yy421.pUsing==0 ){
+ yymsp[-5].minor.yy563 = yymsp[-3].minor.yy563;
+ }else if( ALWAYS(yymsp[-3].minor.yy563!=0) && yymsp[-3].minor.yy563->nSrc==1 ){
+ yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421);
+ if( yymsp[-5].minor.yy563 ){
+ SrcItem *pNew = &yymsp[-5].minor.yy563->a[yymsp[-5].minor.yy563->nSrc-1];
+ SrcItem *pOld = yymsp[-3].minor.yy563->a;
+ assert( pOld->fg.fixedSchema==0 );
pNew->zName = pOld->zName;
- pNew->zDatabase = pOld->zDatabase;
- pNew->pSelect = pOld->pSelect;
- if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){
- pNew->fg.isNestedFrom = 1;
+ assert( pOld->fg.fixedSchema==0 );
+ if( pOld->fg.isSubquery ){
+ pNew->fg.isSubquery = 1;
+ pNew->u4.pSubq = pOld->u4.pSubq;
+ pOld->u4.pSubq = 0;
+ pOld->fg.isSubquery = 0;
+ assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
+ if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
+ pNew->fg.isNestedFrom = 1;
+ }
+ }else{
+ pNew->u4.zDatabase = pOld->u4.zDatabase;
+ pOld->u4.zDatabase = 0;
}
if( pOld->fg.isTabFunc ){
pNew->u1.pFuncArg = pOld->u1.pFuncArg;
@@ -176586,15 +179415,14 @@ static YYACTIONTYPE yy_reduce(
pOld->fg.isTabFunc = 0;
pNew->fg.isTabFunc = 1;
}
- pOld->zName = pOld->zDatabase = 0;
- pOld->pSelect = 0;
+ pOld->zName = 0;
}
- sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203);
+ sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy563);
}else{
Select *pSubquery;
- sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203);
- pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy203,0,0,0,0,SF_NestedFrom,0);
- yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy269);
+ sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy563);
+ pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy563,0,0,0,0,SF_NestedFrom,0);
+ yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy421);
}
}
break;
@@ -176604,56 +179432,56 @@ static YYACTIONTYPE yy_reduce(
break;
case 118: /* fullname ::= nm */
{
- yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
- if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0);
+ yylhsminor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy563 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy563->a[0].zName, &yymsp[0].minor.yy0);
}
- yymsp[0].minor.yy203 = yylhsminor.yy203;
+ yymsp[0].minor.yy563 = yylhsminor.yy563;
break;
case 119: /* fullname ::= nm DOT nm */
{
- yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
- if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0);
+ yylhsminor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy563 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy563->a[0].zName, &yymsp[0].minor.yy0);
}
- yymsp[-2].minor.yy203 = yylhsminor.yy203;
+ yymsp[-2].minor.yy563 = yylhsminor.yy563;
break;
case 120: /* xfullname ::= nm */
-{yymsp[0].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
+{yymsp[0].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
break;
case 121: /* xfullname ::= nm DOT nm */
-{yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
+{yymsp[-2].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
case 122: /* xfullname ::= nm DOT nm AS nm */
{
- yymsp[-4].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
- if( yymsp[-4].minor.yy203 ) yymsp[-4].minor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+ yymsp[-4].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
+ if( yymsp[-4].minor.yy563 ) yymsp[-4].minor.yy563->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
break;
case 123: /* xfullname ::= nm AS nm */
{
- yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
- if( yymsp[-2].minor.yy203 ) yymsp[-2].minor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+ yymsp[-2].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
+ if( yymsp[-2].minor.yy563 ) yymsp[-2].minor.yy563->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
break;
case 124: /* joinop ::= COMMA|JOIN */
-{ yymsp[0].minor.yy144 = JT_INNER; }
+{ yymsp[0].minor.yy502 = JT_INNER; }
break;
case 125: /* joinop ::= JOIN_KW JOIN */
-{yymsp[-1].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
+{yymsp[-1].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
break;
case 126: /* joinop ::= JOIN_KW nm JOIN */
-{yymsp[-2].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
+{yymsp[-2].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
break;
case 127: /* joinop ::= JOIN_KW nm nm JOIN */
-{yymsp[-3].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
+{yymsp[-3].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
break;
case 128: /* on_using ::= ON expr */
-{yymsp[-1].minor.yy269.pOn = yymsp[0].minor.yy454; yymsp[-1].minor.yy269.pUsing = 0;}
+{yymsp[-1].minor.yy421.pOn = yymsp[0].minor.yy590; yymsp[-1].minor.yy421.pUsing = 0;}
break;
case 129: /* on_using ::= USING LP idlist RP */
-{yymsp[-3].minor.yy269.pOn = 0; yymsp[-3].minor.yy269.pUsing = yymsp[-1].minor.yy132;}
+{yymsp[-3].minor.yy421.pOn = 0; yymsp[-3].minor.yy421.pUsing = yymsp[-1].minor.yy204;}
break;
case 130: /* on_using ::= */
-{yymsp[1].minor.yy269.pOn = 0; yymsp[1].minor.yy269.pUsing = 0;}
+{yymsp[1].minor.yy421.pOn = 0; yymsp[1].minor.yy421.pUsing = 0;}
break;
case 132: /* indexed_by ::= INDEXED BY nm */
{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
@@ -176663,35 +179491,35 @@ static YYACTIONTYPE yy_reduce(
break;
case 135: /* orderby_opt ::= ORDER BY sortlist */
case 145: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==145);
-{yymsp[-2].minor.yy14 = yymsp[0].minor.yy14;}
+{yymsp[-2].minor.yy402 = yymsp[0].minor.yy402;}
break;
case 136: /* sortlist ::= sortlist COMMA expr sortorder nulls */
{
- yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14,yymsp[-2].minor.yy454);
- sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144);
+ yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402,yymsp[-2].minor.yy590);
+ sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy402,yymsp[-1].minor.yy502,yymsp[0].minor.yy502);
}
break;
case 137: /* sortlist ::= expr sortorder nulls */
{
- yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy454); /*A-overwrites-Y*/
- sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144);
+ yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy590); /*A-overwrites-Y*/
+ sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy402,yymsp[-1].minor.yy502,yymsp[0].minor.yy502);
}
break;
case 138: /* sortorder ::= ASC */
-{yymsp[0].minor.yy144 = SQLITE_SO_ASC;}
+{yymsp[0].minor.yy502 = SQLITE_SO_ASC;}
break;
case 139: /* sortorder ::= DESC */
-{yymsp[0].minor.yy144 = SQLITE_SO_DESC;}
+{yymsp[0].minor.yy502 = SQLITE_SO_DESC;}
break;
case 140: /* sortorder ::= */
case 143: /* nulls ::= */ yytestcase(yyruleno==143);
-{yymsp[1].minor.yy144 = SQLITE_SO_UNDEFINED;}
+{yymsp[1].minor.yy502 = SQLITE_SO_UNDEFINED;}
break;
case 141: /* nulls ::= NULLS FIRST */
-{yymsp[-1].minor.yy144 = SQLITE_SO_ASC;}
+{yymsp[-1].minor.yy502 = SQLITE_SO_ASC;}
break;
case 142: /* nulls ::= NULLS LAST */
-{yymsp[-1].minor.yy144 = SQLITE_SO_DESC;}
+{yymsp[-1].minor.yy502 = SQLITE_SO_DESC;}
break;
case 146: /* having_opt ::= */
case 148: /* limit_opt ::= */ yytestcase(yyruleno==148);
@@ -176700,42 +179528,42 @@ static YYACTIONTYPE yy_reduce(
case 232: /* case_else ::= */ yytestcase(yyruleno==232);
case 233: /* case_operand ::= */ yytestcase(yyruleno==233);
case 252: /* vinto ::= */ yytestcase(yyruleno==252);
-{yymsp[1].minor.yy454 = 0;}
+{yymsp[1].minor.yy590 = 0;}
break;
case 147: /* having_opt ::= HAVING expr */
case 154: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==154);
case 156: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==156);
case 231: /* case_else ::= ELSE expr */ yytestcase(yyruleno==231);
case 251: /* vinto ::= INTO expr */ yytestcase(yyruleno==251);
-{yymsp[-1].minor.yy454 = yymsp[0].minor.yy454;}
+{yymsp[-1].minor.yy590 = yymsp[0].minor.yy590;}
break;
case 149: /* limit_opt ::= LIMIT expr */
-{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,0);}
+{yymsp[-1].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy590,0);}
break;
case 150: /* limit_opt ::= LIMIT expr OFFSET expr */
-{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
+{yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);}
break;
case 151: /* limit_opt ::= LIMIT expr COMMA expr */
-{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,yymsp[-2].minor.yy454);}
+{yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy590,yymsp[-2].minor.yy590);}
break;
case 152: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
{
- sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy203, &yymsp[-1].minor.yy0);
- sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy203,yymsp[0].minor.yy454,0,0);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy563, &yymsp[-1].minor.yy0);
+ sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy563,yymsp[0].minor.yy590,0,0);
}
break;
case 157: /* where_opt_ret ::= RETURNING selcollist */
-{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-1].minor.yy454 = 0;}
+{sqlite3AddReturning(pParse,yymsp[0].minor.yy402); yymsp[-1].minor.yy590 = 0;}
break;
case 158: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
-{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-3].minor.yy454 = yymsp[-2].minor.yy454;}
+{sqlite3AddReturning(pParse,yymsp[0].minor.yy402); yymsp[-3].minor.yy590 = yymsp[-2].minor.yy590;}
break;
case 159: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
{
- sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-4].minor.yy0);
- sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy14,"set list");
- if( yymsp[-1].minor.yy203 ){
- SrcList *pFromClause = yymsp[-1].minor.yy203;
+ sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy563, &yymsp[-4].minor.yy0);
+ sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy402,"set list");
+ if( yymsp[-1].minor.yy563 ){
+ SrcList *pFromClause = yymsp[-1].minor.yy563;
if( pFromClause->nSrc>1 ){
Select *pSubquery;
Token as;
@@ -176744,90 +179572,90 @@ static YYACTIONTYPE yy_reduce(
as.z = 0;
pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
}
- yymsp[-5].minor.yy203 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy203, pFromClause);
+ yymsp[-5].minor.yy563 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy563, pFromClause);
}
- sqlite3Update(pParse,yymsp[-5].minor.yy203,yymsp[-2].minor.yy14,yymsp[0].minor.yy454,yymsp[-6].minor.yy144,0,0,0);
+ sqlite3Update(pParse,yymsp[-5].minor.yy563,yymsp[-2].minor.yy402,yymsp[0].minor.yy590,yymsp[-6].minor.yy502,0,0,0);
}
break;
case 160: /* setlist ::= setlist COMMA nm EQ expr */
{
- yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy454);
- sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, 1);
+ yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy402, yymsp[0].minor.yy590);
+ sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy402, &yymsp[-2].minor.yy0, 1);
}
break;
case 161: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
{
- yymsp[-6].minor.yy14 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy14, yymsp[-3].minor.yy132, yymsp[0].minor.yy454);
+ yymsp[-6].minor.yy402 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy402, yymsp[-3].minor.yy204, yymsp[0].minor.yy590);
}
break;
case 162: /* setlist ::= nm EQ expr */
{
- yylhsminor.yy14 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy454);
- sqlite3ExprListSetName(pParse, yylhsminor.yy14, &yymsp[-2].minor.yy0, 1);
+ yylhsminor.yy402 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy590);
+ sqlite3ExprListSetName(pParse, yylhsminor.yy402, &yymsp[-2].minor.yy0, 1);
}
- yymsp[-2].minor.yy14 = yylhsminor.yy14;
+ yymsp[-2].minor.yy402 = yylhsminor.yy402;
break;
case 163: /* setlist ::= LP idlist RP EQ expr */
{
- yymsp[-4].minor.yy14 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy132, yymsp[0].minor.yy454);
+ yymsp[-4].minor.yy402 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy204, yymsp[0].minor.yy590);
}
break;
case 164: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
{
- sqlite3Insert(pParse, yymsp[-3].minor.yy203, yymsp[-1].minor.yy555, yymsp[-2].minor.yy132, yymsp[-5].minor.yy144, yymsp[0].minor.yy122);
+ sqlite3Insert(pParse, yymsp[-3].minor.yy563, yymsp[-1].minor.yy637, yymsp[-2].minor.yy204, yymsp[-5].minor.yy502, yymsp[0].minor.yy403);
}
break;
case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
{
- sqlite3Insert(pParse, yymsp[-4].minor.yy203, 0, yymsp[-3].minor.yy132, yymsp[-6].minor.yy144, 0);
+ sqlite3Insert(pParse, yymsp[-4].minor.yy563, 0, yymsp[-3].minor.yy204, yymsp[-6].minor.yy502, 0);
}
break;
case 166: /* upsert ::= */
-{ yymsp[1].minor.yy122 = 0; }
+{ yymsp[1].minor.yy403 = 0; }
break;
case 167: /* upsert ::= RETURNING selcollist */
-{ yymsp[-1].minor.yy122 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy14); }
+{ yymsp[-1].minor.yy403 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy402); }
break;
case 168: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
-{ yymsp[-11].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy14,yymsp[-6].minor.yy454,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,yymsp[0].minor.yy122);}
+{ yymsp[-11].minor.yy403 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy402,yymsp[-6].minor.yy590,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590,yymsp[0].minor.yy403);}
break;
case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
-{ yymsp[-8].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy14,yymsp[-3].minor.yy454,0,0,yymsp[0].minor.yy122); }
+{ yymsp[-8].minor.yy403 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy402,yymsp[-3].minor.yy590,0,0,yymsp[0].minor.yy403); }
break;
case 170: /* upsert ::= ON CONFLICT DO NOTHING returning */
-{ yymsp[-4].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
+{ yymsp[-4].minor.yy403 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
break;
case 171: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
-{ yymsp[-7].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,0);}
+{ yymsp[-7].minor.yy403 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590,0);}
break;
case 172: /* returning ::= RETURNING selcollist */
-{sqlite3AddReturning(pParse,yymsp[0].minor.yy14);}
+{sqlite3AddReturning(pParse,yymsp[0].minor.yy402);}
break;
case 175: /* idlist_opt ::= */
-{yymsp[1].minor.yy132 = 0;}
+{yymsp[1].minor.yy204 = 0;}
break;
case 176: /* idlist_opt ::= LP idlist RP */
-{yymsp[-2].minor.yy132 = yymsp[-1].minor.yy132;}
+{yymsp[-2].minor.yy204 = yymsp[-1].minor.yy204;}
break;
case 177: /* idlist ::= idlist COMMA nm */
-{yymsp[-2].minor.yy132 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy132,&yymsp[0].minor.yy0);}
+{yymsp[-2].minor.yy204 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy204,&yymsp[0].minor.yy0);}
break;
case 178: /* idlist ::= nm */
-{yymsp[0].minor.yy132 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
+{yymsp[0].minor.yy204 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
break;
case 179: /* expr ::= LP expr RP */
-{yymsp[-2].minor.yy454 = yymsp[-1].minor.yy454;}
+{yymsp[-2].minor.yy590 = yymsp[-1].minor.yy590;}
break;
case 180: /* expr ::= ID|INDEXED|JOIN_KW */
-{yymsp[0].minor.yy454=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+{yymsp[0].minor.yy590=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
case 181: /* expr ::= nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0);
- yylhsminor.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
+ yylhsminor.yy590 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
- yymsp[-2].minor.yy454 = yylhsminor.yy454;
+ yymsp[-2].minor.yy590 = yylhsminor.yy590;
break;
case 182: /* expr ::= nm DOT nm DOT nm */
{
@@ -176838,27 +179666,27 @@ static YYACTIONTYPE yy_reduce(
if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, 0, temp1);
}
- yylhsminor.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
+ yylhsminor.yy590 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
- yymsp[-4].minor.yy454 = yylhsminor.yy454;
+ yymsp[-4].minor.yy590 = yylhsminor.yy590;
break;
case 183: /* term ::= NULL|FLOAT|BLOB */
case 184: /* term ::= STRING */ yytestcase(yyruleno==184);
-{yymsp[0].minor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+{yymsp[0].minor.yy590=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
case 185: /* term ::= INTEGER */
{
- yylhsminor.yy454 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
- if( yylhsminor.yy454 ) yylhsminor.yy454->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
+ yylhsminor.yy590 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
+ if( yylhsminor.yy590 ) yylhsminor.yy590->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
}
- yymsp[0].minor.yy454 = yylhsminor.yy454;
+ yymsp[0].minor.yy590 = yylhsminor.yy590;
break;
case 186: /* expr ::= VARIABLE */
{
if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
u32 n = yymsp[0].minor.yy0.n;
- yymsp[0].minor.yy454 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
- sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy454, n);
+ yymsp[0].minor.yy590 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
+ sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy590, 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
@@ -176866,81 +179694,81 @@ static YYACTIONTYPE yy_reduce(
Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
assert( t.n>=2 );
if( pParse->nested==0 ){
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
- yymsp[0].minor.yy454 = 0;
+ parserSyntaxError(pParse, &t);
+ yymsp[0].minor.yy590 = 0;
}else{
- yymsp[0].minor.yy454 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
- if( yymsp[0].minor.yy454 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable);
+ yymsp[0].minor.yy590 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
+ if( yymsp[0].minor.yy590 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy590->iTable);
}
}
}
break;
case 187: /* expr ::= expr COLLATE ID|STRING */
{
- yymsp[-2].minor.yy454 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy454, &yymsp[0].minor.yy0, 1);
+ yymsp[-2].minor.yy590 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy590, &yymsp[0].minor.yy0, 1);
}
break;
case 188: /* expr ::= CAST LP expr AS typetoken RP */
{
- yymsp[-5].minor.yy454 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
- sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy454, yymsp[-3].minor.yy454, 0);
+ yymsp[-5].minor.yy590 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
+ sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy590, yymsp[-3].minor.yy590, 0);
}
break;
case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
{
- yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy144);
+ yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy402, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy502);
}
- yymsp[-4].minor.yy454 = yylhsminor.yy454;
+ yymsp[-4].minor.yy590 = yylhsminor.yy590;
break;
case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
{
- yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy14, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy144);
- sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-1].minor.yy14);
+ yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy402, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy502);
+ sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy590, yymsp[-1].minor.yy402);
}
- yymsp[-7].minor.yy454 = yylhsminor.yy454;
+ yymsp[-7].minor.yy590 = yylhsminor.yy590;
break;
case 191: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
{
- yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
+ yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
}
- yymsp[-3].minor.yy454 = yylhsminor.yy454;
+ yymsp[-3].minor.yy590 = yylhsminor.yy590;
break;
case 192: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
{
- yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy14, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy144);
- sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
+ yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy402, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy502);
+ sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483);
}
- yymsp[-5].minor.yy454 = yylhsminor.yy454;
+ yymsp[-5].minor.yy590 = yylhsminor.yy590;
break;
case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
{
- yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy14, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy144);
- sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
- sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-2].minor.yy14);
+ yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy402, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy502);
+ sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483);
+ sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy590, yymsp[-2].minor.yy402);
}
- yymsp[-8].minor.yy454 = yylhsminor.yy454;
+ yymsp[-8].minor.yy590 = yylhsminor.yy590;
break;
case 194: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
{
- yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
- sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211);
+ yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
+ sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483);
}
- yymsp[-4].minor.yy454 = yylhsminor.yy454;
+ yymsp[-4].minor.yy590 = yylhsminor.yy590;
break;
case 195: /* term ::= CTIME_KW */
{
- yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
+ yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
}
- yymsp[0].minor.yy454 = yylhsminor.yy454;
+ yymsp[0].minor.yy590 = yylhsminor.yy590;
break;
case 196: /* expr ::= LP nexprlist COMMA expr RP */
{
- ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454);
- yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
- if( yymsp[-4].minor.yy454 ){
- yymsp[-4].minor.yy454->x.pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy402, yymsp[-1].minor.yy590);
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+ if( yymsp[-4].minor.yy590 ){
+ yymsp[-4].minor.yy590->x.pList = pList;
if( ALWAYS(pList->nExpr) ){
- yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate;
+ yymsp[-4].minor.yy590->flags |= pList->a[0].pExpr->flags & EP_Propagate;
}
}else{
sqlite3ExprListDelete(pParse->db, pList);
@@ -176948,7 +179776,7 @@ static YYACTIONTYPE yy_reduce(
}
break;
case 197: /* expr ::= expr AND expr */
-{yymsp[-2].minor.yy454=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
+{yymsp[-2].minor.yy590=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);}
break;
case 198: /* expr ::= expr OR expr */
case 199: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==199);
@@ -176957,7 +179785,7 @@ static YYACTIONTYPE yy_reduce(
case 202: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==202);
case 203: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==203);
case 204: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==204);
-{yymsp[-2].minor.yy454=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);}
+{yymsp[-2].minor.yy590=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);}
break;
case 205: /* 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*/}
@@ -176967,11 +179795,11 @@ static YYACTIONTYPE yy_reduce(
ExprList *pList;
int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
yymsp[-1].minor.yy0.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy454);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy454);
- yymsp[-2].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
- if( bNot ) yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy454, 0);
- if( yymsp[-2].minor.yy454 ) yymsp[-2].minor.yy454->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy590);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy590);
+ yymsp[-2].minor.yy590 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+ if( bNot ) yymsp[-2].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy590, 0);
+ if( yymsp[-2].minor.yy590 ) yymsp[-2].minor.yy590->flags |= EP_InfixFunc;
}
break;
case 207: /* expr ::= expr likeop expr ESCAPE expr */
@@ -176979,91 +179807,91 @@ static YYACTIONTYPE yy_reduce(
ExprList *pList;
int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
yymsp[-3].minor.yy0.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy454);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454);
- yymsp[-4].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
- if( bNot ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
- if( yymsp[-4].minor.yy454 ) yymsp[-4].minor.yy454->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy590);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy590);
+ yymsp[-4].minor.yy590 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
+ if( bNot ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0);
+ if( yymsp[-4].minor.yy590 ) yymsp[-4].minor.yy590->flags |= EP_InfixFunc;
}
break;
case 208: /* expr ::= expr ISNULL|NOTNULL */
-{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy454,0);}
+{yymsp[-1].minor.yy590 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy590,0);}
break;
case 209: /* expr ::= expr NOT NULL */
-{yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy454,0);}
+{yymsp[-2].minor.yy590 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy590,0);}
break;
case 210: /* expr ::= expr IS expr */
{
- yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-2].minor.yy454, TK_ISNULL);
+ yymsp[-2].minor.yy590 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-2].minor.yy590, TK_ISNULL);
}
break;
case 211: /* expr ::= expr IS NOT expr */
{
- yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy454,yymsp[0].minor.yy454);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-3].minor.yy454, TK_NOTNULL);
+ yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy590,yymsp[0].minor.yy590);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-3].minor.yy590, TK_NOTNULL);
}
break;
case 212: /* expr ::= expr IS NOT DISTINCT FROM expr */
{
- yymsp[-5].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy454,yymsp[0].minor.yy454);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-5].minor.yy454, TK_ISNULL);
+ yymsp[-5].minor.yy590 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy590,yymsp[0].minor.yy590);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-5].minor.yy590, TK_ISNULL);
}
break;
case 213: /* expr ::= expr IS DISTINCT FROM expr */
{
- yymsp[-4].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy454,yymsp[0].minor.yy454);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-4].minor.yy454, TK_NOTNULL);
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy590,yymsp[0].minor.yy590);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-4].minor.yy590, TK_NOTNULL);
}
break;
case 214: /* expr ::= NOT expr */
case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215);
-{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy454, 0);/*A-overwrites-B*/}
+{yymsp[-1].minor.yy590 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy590, 0);/*A-overwrites-B*/}
break;
case 216: /* expr ::= PLUS|MINUS expr */
{
- Expr *p = yymsp[0].minor.yy454;
+ Expr *p = yymsp[0].minor.yy590;
u8 op = yymsp[-1].major + (TK_UPLUS-TK_PLUS);
assert( TK_UPLUS>TK_PLUS );
assert( TK_UMINUS == TK_MINUS + (TK_UPLUS - TK_PLUS) );
if( p && p->op==TK_UPLUS ){
p->op = op;
- yymsp[-1].minor.yy454 = p;
+ yymsp[-1].minor.yy590 = p;
}else{
- yymsp[-1].minor.yy454 = sqlite3PExpr(pParse, op, p, 0);
+ yymsp[-1].minor.yy590 = sqlite3PExpr(pParse, op, p, 0);
/*A-overwrites-B*/
}
}
break;
case 217: /* expr ::= expr PTR expr */
{
- ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy454);
- pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy454);
- yylhsminor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+ ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy590);
+ pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy590);
+ yylhsminor.yy590 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
}
- yymsp[-2].minor.yy454 = yylhsminor.yy454;
+ yymsp[-2].minor.yy590 = yylhsminor.yy590;
break;
case 218: /* between_op ::= BETWEEN */
case 221: /* in_op ::= IN */ yytestcase(yyruleno==221);
-{yymsp[0].minor.yy144 = 0;}
+{yymsp[0].minor.yy502 = 0;}
break;
case 220: /* expr ::= expr between_op expr AND expr */
{
- ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454);
- yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy454, 0);
- if( yymsp[-4].minor.yy454 ){
- yymsp[-4].minor.yy454->x.pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy590);
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy590, 0);
+ if( yymsp[-4].minor.yy590 ){
+ yymsp[-4].minor.yy590->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
- if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0);
}
break;
case 223: /* expr ::= expr in_op LP exprlist RP */
{
- if( yymsp[-1].minor.yy14==0 ){
+ if( yymsp[-1].minor.yy402==0 ){
/* Expressions of the form
**
** expr1 IN ()
@@ -177072,110 +179900,110 @@ static YYACTIONTYPE yy_reduce(
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy454);
- yymsp[-4].minor.yy454 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy144 ? "true" : "false");
- if( yymsp[-4].minor.yy454 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy454);
- }else{
- Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr;
- if( yymsp[-1].minor.yy14->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy454->op!=TK_VECTOR ){
- yymsp[-1].minor.yy14->a[0].pExpr = 0;
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
+ sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy590);
+ yymsp[-4].minor.yy590 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy502 ? "true" : "false");
+ if( yymsp[-4].minor.yy590 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy590);
+ }else{
+ Expr *pRHS = yymsp[-1].minor.yy402->a[0].pExpr;
+ if( yymsp[-1].minor.yy402->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy590->op!=TK_VECTOR ){
+ yymsp[-1].minor.yy402->a[0].pExpr = 0;
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy402);
pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
- yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy454, pRHS);
- }else if( yymsp[-1].minor.yy14->nExpr==1 && pRHS->op==TK_SELECT ){
- yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pRHS->x.pSelect);
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy590, pRHS);
+ }else if( yymsp[-1].minor.yy402->nExpr==1 && pRHS->op==TK_SELECT ){
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, pRHS->x.pSelect);
pRHS->x.pSelect = 0;
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
- }else{
- yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
- if( yymsp[-4].minor.yy454==0 ){
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
- }else if( yymsp[-4].minor.yy454->pLeft->op==TK_VECTOR ){
- int nExpr = yymsp[-4].minor.yy454->pLeft->x.pList->nExpr;
- Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy14);
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy402);
+ }else{
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0);
+ if( yymsp[-4].minor.yy590==0 ){
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy402);
+ }else if( yymsp[-4].minor.yy590->pLeft->op==TK_VECTOR ){
+ int nExpr = yymsp[-4].minor.yy590->pLeft->x.pList->nExpr;
+ Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy402);
if( pSelectRHS ){
parserDoubleLinkSelect(pParse, pSelectRHS);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelectRHS);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, pSelectRHS);
}
}else{
- yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy14;
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454);
+ yymsp[-4].minor.yy590->x.pList = yymsp[-1].minor.yy402;
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy590);
}
}
- if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
+ if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0);
}
}
break;
case 224: /* expr ::= LP select RP */
{
- yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy454, yymsp[-1].minor.yy555);
+ yymsp[-2].minor.yy590 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy590, yymsp[-1].minor.yy637);
}
break;
case 225: /* expr ::= expr in_op LP select RP */
{
- yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, yymsp[-1].minor.yy555);
- if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, yymsp[-1].minor.yy637);
+ if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0);
}
break;
case 226: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
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.yy14 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy14);
- yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelect);
- if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0);
+ if( yymsp[0].minor.yy402 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy402);
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, pSelect);
+ if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0);
}
break;
case 227: /* expr ::= EXISTS LP select RP */
{
Expr *p;
- p = yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
- sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy555);
+ p = yymsp[-3].minor.yy590 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
+ sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy637);
}
break;
case 228: /* expr ::= CASE case_operand case_exprlist case_else END */
{
- yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy454, 0);
- if( yymsp[-4].minor.yy454 ){
- yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy454 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454) : yymsp[-2].minor.yy14;
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454);
+ yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy590, 0);
+ if( yymsp[-4].minor.yy590 ){
+ yymsp[-4].minor.yy590->x.pList = yymsp[-1].minor.yy590 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590) : yymsp[-2].minor.yy402;
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy590);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14);
- sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454);
+ sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy402);
+ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy590);
}
}
break;
case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
- yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy454);
- yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[0].minor.yy454);
+ yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, yymsp[-2].minor.yy590);
+ yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, yymsp[0].minor.yy590);
}
break;
case 230: /* case_exprlist ::= WHEN expr THEN expr */
{
- yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454);
- yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, yymsp[0].minor.yy454);
+ yymsp[-3].minor.yy402 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590);
+ yymsp[-3].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy402, yymsp[0].minor.yy590);
}
break;
case 235: /* nexprlist ::= nexprlist COMMA expr */
-{yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy454);}
+{yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy402,yymsp[0].minor.yy590);}
break;
case 236: /* nexprlist ::= expr */
-{yymsp[0].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy454); /*A-overwrites-Y*/}
+{yymsp[0].minor.yy402 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy590); /*A-overwrites-Y*/}
break;
case 238: /* paren_exprlist ::= LP exprlist RP */
case 243: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==243);
-{yymsp[-2].minor.yy14 = yymsp[-1].minor.yy14;}
+{yymsp[-2].minor.yy402 = yymsp[-1].minor.yy402;}
break;
case 239: /* 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,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy14, yymsp[-10].minor.yy144,
- &yymsp[-11].minor.yy0, yymsp[0].minor.yy454, SQLITE_SO_ASC, yymsp[-8].minor.yy144, SQLITE_IDXTYPE_APPDEF);
+ sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy402, yymsp[-10].minor.yy502,
+ &yymsp[-11].minor.yy0, yymsp[0].minor.yy590, SQLITE_SO_ASC, yymsp[-8].minor.yy502, SQLITE_IDXTYPE_APPDEF);
if( IN_RENAME_OBJECT && pParse->pNewIndex ){
sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0);
}
@@ -177183,29 +180011,29 @@ static YYACTIONTYPE yy_reduce(
break;
case 240: /* uniqueflag ::= UNIQUE */
case 282: /* raisetype ::= ABORT */ yytestcase(yyruleno==282);
-{yymsp[0].minor.yy144 = OE_Abort;}
+{yymsp[0].minor.yy502 = OE_Abort;}
break;
case 241: /* uniqueflag ::= */
-{yymsp[1].minor.yy144 = OE_None;}
+{yymsp[1].minor.yy502 = OE_None;}
break;
case 244: /* eidlist ::= eidlist COMMA nm collate sortorder */
{
- yymsp[-4].minor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144);
+ yymsp[-4].minor.yy402 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy402, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502);
}
break;
case 245: /* eidlist ::= nm collate sortorder */
{
- yymsp[-2].minor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); /*A-overwrites-Y*/
+ yymsp[-2].minor.yy402 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502); /*A-overwrites-Y*/
}
break;
case 248: /* cmd ::= DROP INDEX ifexists fullname */
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy203, yymsp[-1].minor.yy144);}
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy563, yymsp[-1].minor.yy502);}
break;
case 249: /* cmd ::= VACUUM vinto */
-{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy454);}
+{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy590);}
break;
case 250: /* cmd ::= VACUUM nm vinto */
-{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy454);}
+{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy590);}
break;
case 253: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
@@ -177227,50 +180055,54 @@ static YYACTIONTYPE yy_reduce(
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.yy427, &all);
+ sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy319, &all);
}
break;
case 261: /* 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.yy144, yymsp[-4].minor.yy286.a, yymsp[-4].minor.yy286.b, yymsp[-2].minor.yy203, yymsp[0].minor.yy454, yymsp[-10].minor.yy144, yymsp[-8].minor.yy144);
+ sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy502, yymsp[-4].minor.yy28.a, yymsp[-4].minor.yy28.b, yymsp[-2].minor.yy563, yymsp[0].minor.yy590, yymsp[-10].minor.yy502, yymsp[-8].minor.yy502);
yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
+#ifdef SQLITE_DEBUG
+ assert( pParse->isCreate ); /* Set by createkw reduce action */
+ pParse->isCreate = 0; /* But, should not be set for CREATE TRIGGER */
+#endif
}
break;
case 262: /* trigger_time ::= BEFORE|AFTER */
-{ yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/ }
+{ yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/ }
break;
case 263: /* trigger_time ::= INSTEAD OF */
-{ yymsp[-1].minor.yy144 = TK_INSTEAD;}
+{ yymsp[-1].minor.yy502 = TK_INSTEAD;}
break;
case 264: /* trigger_time ::= */
-{ yymsp[1].minor.yy144 = TK_BEFORE; }
+{ yymsp[1].minor.yy502 = TK_BEFORE; }
break;
case 265: /* trigger_event ::= DELETE|INSERT */
case 266: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==266);
-{yymsp[0].minor.yy286.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy286.b = 0;}
+{yymsp[0].minor.yy28.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy28.b = 0;}
break;
case 267: /* trigger_event ::= UPDATE OF idlist */
-{yymsp[-2].minor.yy286.a = TK_UPDATE; yymsp[-2].minor.yy286.b = yymsp[0].minor.yy132;}
+{yymsp[-2].minor.yy28.a = TK_UPDATE; yymsp[-2].minor.yy28.b = yymsp[0].minor.yy204;}
break;
case 268: /* when_clause ::= */
case 287: /* key_opt ::= */ yytestcase(yyruleno==287);
-{ yymsp[1].minor.yy454 = 0; }
+{ yymsp[1].minor.yy590 = 0; }
break;
case 269: /* when_clause ::= WHEN expr */
case 288: /* key_opt ::= KEY expr */ yytestcase(yyruleno==288);
-{ yymsp[-1].minor.yy454 = yymsp[0].minor.yy454; }
+{ yymsp[-1].minor.yy590 = yymsp[0].minor.yy590; }
break;
case 270: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
- assert( yymsp[-2].minor.yy427!=0 );
- yymsp[-2].minor.yy427->pLast->pNext = yymsp[-1].minor.yy427;
- yymsp[-2].minor.yy427->pLast = yymsp[-1].minor.yy427;
+ assert( yymsp[-2].minor.yy319!=0 );
+ yymsp[-2].minor.yy319->pLast->pNext = yymsp[-1].minor.yy319;
+ yymsp[-2].minor.yy319->pLast = yymsp[-1].minor.yy319;
}
break;
case 271: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
- assert( yymsp[-1].minor.yy427!=0 );
- yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427;
+ assert( yymsp[-1].minor.yy319!=0 );
+ yymsp[-1].minor.yy319->pLast = yymsp[-1].minor.yy319;
}
break;
case 272: /* trnm ::= nm DOT nm */
@@ -177296,58 +180128,58 @@ static YYACTIONTYPE yy_reduce(
}
break;
case 275: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
-{yylhsminor.yy427 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy203, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454, yymsp[-7].minor.yy144, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy168);}
- yymsp[-8].minor.yy427 = yylhsminor.yy427;
+{yylhsminor.yy319 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy563, yymsp[-3].minor.yy402, yymsp[-1].minor.yy590, yymsp[-7].minor.yy502, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy342);}
+ yymsp[-8].minor.yy319 = yylhsminor.yy319;
break;
case 276: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
{
- yylhsminor.yy427 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy132,yymsp[-2].minor.yy555,yymsp[-6].minor.yy144,yymsp[-1].minor.yy122,yymsp[-7].minor.yy168,yymsp[0].minor.yy168);/*yylhsminor.yy427-overwrites-yymsp[-6].minor.yy144*/
+ yylhsminor.yy319 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy204,yymsp[-2].minor.yy637,yymsp[-6].minor.yy502,yymsp[-1].minor.yy403,yymsp[-7].minor.yy342,yymsp[0].minor.yy342);/*yylhsminor.yy319-overwrites-yymsp[-6].minor.yy502*/
}
- yymsp[-7].minor.yy427 = yylhsminor.yy427;
+ yymsp[-7].minor.yy319 = yylhsminor.yy319;
break;
case 277: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
-{yylhsminor.yy427 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy454, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy168);}
- yymsp[-5].minor.yy427 = yylhsminor.yy427;
+{yylhsminor.yy319 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy590, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy342);}
+ yymsp[-5].minor.yy319 = yylhsminor.yy319;
break;
case 278: /* trigger_cmd ::= scanpt select scanpt */
-{yylhsminor.yy427 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy555, yymsp[-2].minor.yy168, yymsp[0].minor.yy168); /*yylhsminor.yy427-overwrites-yymsp[-1].minor.yy555*/}
- yymsp[-2].minor.yy427 = yylhsminor.yy427;
+{yylhsminor.yy319 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy637, yymsp[-2].minor.yy342, yymsp[0].minor.yy342); /*yylhsminor.yy319-overwrites-yymsp[-1].minor.yy637*/}
+ yymsp[-2].minor.yy319 = yylhsminor.yy319;
break;
case 279: /* expr ::= RAISE LP IGNORE RP */
{
- yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
- if( yymsp[-3].minor.yy454 ){
- yymsp[-3].minor.yy454->affExpr = OE_Ignore;
+ yymsp[-3].minor.yy590 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
+ if( yymsp[-3].minor.yy590 ){
+ yymsp[-3].minor.yy590->affExpr = OE_Ignore;
}
}
break;
- case 280: /* expr ::= RAISE LP raisetype COMMA nm RP */
+ case 280: /* expr ::= RAISE LP raisetype COMMA expr RP */
{
- yymsp[-5].minor.yy454 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
- if( yymsp[-5].minor.yy454 ) {
- yymsp[-5].minor.yy454->affExpr = (char)yymsp[-3].minor.yy144;
+ yymsp[-5].minor.yy590 = sqlite3PExpr(pParse, TK_RAISE, yymsp[-1].minor.yy590, 0);
+ if( yymsp[-5].minor.yy590 ) {
+ yymsp[-5].minor.yy590->affExpr = (char)yymsp[-3].minor.yy502;
}
}
break;
case 281: /* raisetype ::= ROLLBACK */
-{yymsp[0].minor.yy144 = OE_Rollback;}
+{yymsp[0].minor.yy502 = OE_Rollback;}
break;
case 283: /* raisetype ::= FAIL */
-{yymsp[0].minor.yy144 = OE_Fail;}
+{yymsp[0].minor.yy502 = OE_Fail;}
break;
case 284: /* cmd ::= DROP TRIGGER ifexists fullname */
{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy203,yymsp[-1].minor.yy144);
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy563,yymsp[-1].minor.yy502);
}
break;
case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
- sqlite3Attach(pParse, yymsp[-3].minor.yy454, yymsp[-1].minor.yy454, yymsp[0].minor.yy454);
+ sqlite3Attach(pParse, yymsp[-3].minor.yy590, yymsp[-1].minor.yy590, yymsp[0].minor.yy590);
}
break;
case 286: /* cmd ::= DETACH database_kw_opt expr */
{
- sqlite3Detach(pParse, yymsp[0].minor.yy454);
+ sqlite3Detach(pParse, yymsp[0].minor.yy590);
}
break;
case 289: /* cmd ::= REINDEX */
@@ -177364,7 +180196,7 @@ static YYACTIONTYPE yy_reduce(
break;
case 293: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
- sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy203,&yymsp[0].minor.yy0);
+ sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy563,&yymsp[0].minor.yy0);
}
break;
case 294: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
@@ -177375,18 +180207,18 @@ static YYACTIONTYPE yy_reduce(
break;
case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
{
- sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0);
+ sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy563, &yymsp[0].minor.yy0);
}
break;
case 296: /* add_column_fullname ::= fullname */
{
disableLookaside(pParse);
- sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy203);
+ sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy563);
}
break;
case 297: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
{
- sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy203, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
+ sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy563, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
}
break;
case 298: /* cmd ::= create_vtab */
@@ -177397,7 +180229,7 @@ static YYACTIONTYPE yy_reduce(
break;
case 300: /* 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.yy144);
+ sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy502);
}
break;
case 301: /* vtabarg ::= */
@@ -177410,20 +180242,20 @@ static YYACTIONTYPE yy_reduce(
break;
case 305: /* with ::= WITH wqlist */
case 306: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==306);
-{ sqlite3WithPush(pParse, yymsp[0].minor.yy59, 1); }
+{ sqlite3WithPush(pParse, yymsp[0].minor.yy125, 1); }
break;
case 307: /* wqas ::= AS */
-{yymsp[0].minor.yy462 = M10d_Any;}
+{yymsp[0].minor.yy444 = M10d_Any;}
break;
case 308: /* wqas ::= AS MATERIALIZED */
-{yymsp[-1].minor.yy462 = M10d_Yes;}
+{yymsp[-1].minor.yy444 = M10d_Yes;}
break;
case 309: /* wqas ::= AS NOT MATERIALIZED */
-{yymsp[-2].minor.yy462 = M10d_No;}
+{yymsp[-2].minor.yy444 = M10d_No;}
break;
case 310: /* wqitem ::= withnm eidlist_opt wqas LP select RP */
{
- yymsp[-5].minor.yy67 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy555, yymsp[-3].minor.yy462); /*A-overwrites-X*/
+ yymsp[-5].minor.yy361 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy402, yymsp[-1].minor.yy637, yymsp[-3].minor.yy444); /*A-overwrites-X*/
}
break;
case 311: /* withnm ::= nm */
@@ -177431,160 +180263,160 @@ static YYACTIONTYPE yy_reduce(
break;
case 312: /* wqlist ::= wqitem */
{
- yymsp[0].minor.yy59 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy67); /*A-overwrites-X*/
+ yymsp[0].minor.yy125 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy361); /*A-overwrites-X*/
}
break;
case 313: /* wqlist ::= wqlist COMMA wqitem */
{
- yymsp[-2].minor.yy59 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy59, yymsp[0].minor.yy67);
+ yymsp[-2].minor.yy125 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy125, yymsp[0].minor.yy361);
}
break;
case 314: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
{
- assert( yymsp[0].minor.yy211!=0 );
- sqlite3WindowChain(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy211);
- yymsp[0].minor.yy211->pNextWin = yymsp[-2].minor.yy211;
- yylhsminor.yy211 = yymsp[0].minor.yy211;
+ assert( yymsp[0].minor.yy483!=0 );
+ sqlite3WindowChain(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy483);
+ yymsp[0].minor.yy483->pNextWin = yymsp[-2].minor.yy483;
+ yylhsminor.yy483 = yymsp[0].minor.yy483;
}
- yymsp[-2].minor.yy211 = yylhsminor.yy211;
+ yymsp[-2].minor.yy483 = yylhsminor.yy483;
break;
case 315: /* windowdefn ::= nm AS LP window RP */
{
- if( ALWAYS(yymsp[-1].minor.yy211) ){
- yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
+ if( ALWAYS(yymsp[-1].minor.yy483) ){
+ yymsp[-1].minor.yy483->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
}
- yylhsminor.yy211 = yymsp[-1].minor.yy211;
+ yylhsminor.yy483 = yymsp[-1].minor.yy483;
}
- yymsp[-4].minor.yy211 = yylhsminor.yy211;
+ yymsp[-4].minor.yy483 = yylhsminor.yy483;
break;
case 316: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
{
- yymsp[-4].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, 0);
+ yymsp[-4].minor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy402, yymsp[-1].minor.yy402, 0);
}
break;
case 317: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
{
- yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, &yymsp[-5].minor.yy0);
+ yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy402, yymsp[-1].minor.yy402, &yymsp[-5].minor.yy0);
}
- yymsp[-5].minor.yy211 = yylhsminor.yy211;
+ yymsp[-5].minor.yy483 = yylhsminor.yy483;
break;
case 318: /* window ::= ORDER BY sortlist frame_opt */
{
- yymsp[-3].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, 0);
+ yymsp[-3].minor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, yymsp[-1].minor.yy402, 0);
}
break;
case 319: /* window ::= nm ORDER BY sortlist frame_opt */
{
- yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0);
+ yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, yymsp[-1].minor.yy402, &yymsp[-4].minor.yy0);
}
- yymsp[-4].minor.yy211 = yylhsminor.yy211;
+ yymsp[-4].minor.yy483 = yylhsminor.yy483;
break;
case 320: /* window ::= nm frame_opt */
{
- yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, 0, &yymsp[-1].minor.yy0);
+ yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, 0, &yymsp[-1].minor.yy0);
}
- yymsp[-1].minor.yy211 = yylhsminor.yy211;
+ yymsp[-1].minor.yy483 = yylhsminor.yy483;
break;
case 321: /* frame_opt ::= */
{
- yymsp[1].minor.yy211 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
+ yymsp[1].minor.yy483 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
}
break;
case 322: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
{
- yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy144, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy462);
+ yylhsminor.yy483 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy502, yymsp[-1].minor.yy205.eType, yymsp[-1].minor.yy205.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy444);
}
- yymsp[-2].minor.yy211 = yylhsminor.yy211;
+ yymsp[-2].minor.yy483 = yylhsminor.yy483;
break;
case 323: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
{
- yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy144, yymsp[-3].minor.yy509.eType, yymsp[-3].minor.yy509.pExpr, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, yymsp[0].minor.yy462);
+ yylhsminor.yy483 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy502, yymsp[-3].minor.yy205.eType, yymsp[-3].minor.yy205.pExpr, yymsp[-1].minor.yy205.eType, yymsp[-1].minor.yy205.pExpr, yymsp[0].minor.yy444);
}
- yymsp[-5].minor.yy211 = yylhsminor.yy211;
+ yymsp[-5].minor.yy483 = yylhsminor.yy483;
break;
case 325: /* frame_bound_s ::= frame_bound */
case 327: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==327);
-{yylhsminor.yy509 = yymsp[0].minor.yy509;}
- yymsp[0].minor.yy509 = yylhsminor.yy509;
+{yylhsminor.yy205 = yymsp[0].minor.yy205;}
+ yymsp[0].minor.yy205 = yylhsminor.yy205;
break;
case 326: /* frame_bound_s ::= UNBOUNDED PRECEDING */
case 328: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==328);
case 330: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==330);
-{yylhsminor.yy509.eType = yymsp[-1].major; yylhsminor.yy509.pExpr = 0;}
- yymsp[-1].minor.yy509 = yylhsminor.yy509;
+{yylhsminor.yy205.eType = yymsp[-1].major; yylhsminor.yy205.pExpr = 0;}
+ yymsp[-1].minor.yy205 = yylhsminor.yy205;
break;
case 329: /* frame_bound ::= expr PRECEDING|FOLLOWING */
-{yylhsminor.yy509.eType = yymsp[0].major; yylhsminor.yy509.pExpr = yymsp[-1].minor.yy454;}
- yymsp[-1].minor.yy509 = yylhsminor.yy509;
+{yylhsminor.yy205.eType = yymsp[0].major; yylhsminor.yy205.pExpr = yymsp[-1].minor.yy590;}
+ yymsp[-1].minor.yy205 = yylhsminor.yy205;
break;
case 331: /* frame_exclude_opt ::= */
-{yymsp[1].minor.yy462 = 0;}
+{yymsp[1].minor.yy444 = 0;}
break;
case 332: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
-{yymsp[-1].minor.yy462 = yymsp[0].minor.yy462;}
+{yymsp[-1].minor.yy444 = yymsp[0].minor.yy444;}
break;
case 333: /* frame_exclude ::= NO OTHERS */
case 334: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==334);
-{yymsp[-1].minor.yy462 = yymsp[-1].major; /*A-overwrites-X*/}
+{yymsp[-1].minor.yy444 = yymsp[-1].major; /*A-overwrites-X*/}
break;
case 335: /* frame_exclude ::= GROUP|TIES */
-{yymsp[0].minor.yy462 = yymsp[0].major; /*A-overwrites-X*/}
+{yymsp[0].minor.yy444 = yymsp[0].major; /*A-overwrites-X*/}
break;
case 336: /* window_clause ::= WINDOW windowdefn_list */
-{ yymsp[-1].minor.yy211 = yymsp[0].minor.yy211; }
+{ yymsp[-1].minor.yy483 = yymsp[0].minor.yy483; }
break;
case 337: /* filter_over ::= filter_clause over_clause */
{
- if( yymsp[0].minor.yy211 ){
- yymsp[0].minor.yy211->pFilter = yymsp[-1].minor.yy454;
+ if( yymsp[0].minor.yy483 ){
+ yymsp[0].minor.yy483->pFilter = yymsp[-1].minor.yy590;
}else{
- sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454);
+ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy590);
}
- yylhsminor.yy211 = yymsp[0].minor.yy211;
+ yylhsminor.yy483 = yymsp[0].minor.yy483;
}
- yymsp[-1].minor.yy211 = yylhsminor.yy211;
+ yymsp[-1].minor.yy483 = yylhsminor.yy483;
break;
case 338: /* filter_over ::= over_clause */
{
- yylhsminor.yy211 = yymsp[0].minor.yy211;
+ yylhsminor.yy483 = yymsp[0].minor.yy483;
}
- yymsp[0].minor.yy211 = yylhsminor.yy211;
+ yymsp[0].minor.yy483 = yylhsminor.yy483;
break;
case 339: /* filter_over ::= filter_clause */
{
- yylhsminor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
- if( yylhsminor.yy211 ){
- yylhsminor.yy211->eFrmType = TK_FILTER;
- yylhsminor.yy211->pFilter = yymsp[0].minor.yy454;
+ yylhsminor.yy483 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yylhsminor.yy483 ){
+ yylhsminor.yy483->eFrmType = TK_FILTER;
+ yylhsminor.yy483->pFilter = yymsp[0].minor.yy590;
}else{
- sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy454);
+ sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy590);
}
}
- yymsp[0].minor.yy211 = yylhsminor.yy211;
+ yymsp[0].minor.yy483 = yylhsminor.yy483;
break;
case 340: /* over_clause ::= OVER LP window RP */
{
- yymsp[-3].minor.yy211 = yymsp[-1].minor.yy211;
- assert( yymsp[-3].minor.yy211!=0 );
+ yymsp[-3].minor.yy483 = yymsp[-1].minor.yy483;
+ assert( yymsp[-3].minor.yy483!=0 );
}
break;
case 341: /* over_clause ::= OVER nm */
{
- yymsp[-1].minor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
- if( yymsp[-1].minor.yy211 ){
- yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
+ yymsp[-1].minor.yy483 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yymsp[-1].minor.yy483 ){
+ yymsp[-1].minor.yy483->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
}
}
break;
case 342: /* filter_clause ::= FILTER LP WHERE expr RP */
-{ yymsp[-4].minor.yy454 = yymsp[-1].minor.yy454; }
+{ yymsp[-4].minor.yy590 = yymsp[-1].minor.yy590; }
break;
case 343: /* term ::= QNUMBER */
{
- yylhsminor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0);
- sqlite3DequoteNumber(pParse, yylhsminor.yy454);
+ yylhsminor.yy590=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0);
+ sqlite3DequoteNumber(pParse, yylhsminor.yy590);
}
- yymsp[0].minor.yy454 = yylhsminor.yy454;
+ yymsp[0].minor.yy590 = yylhsminor.yy590;
break;
default:
/* (344) input ::= cmdlist */ yytestcase(yyruleno==344);
@@ -177714,7 +180546,7 @@ static void yy_syntax_error(
UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */
if( TOKEN.z[0] ){
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
+ parserSyntaxError(pParse, &TOKEN);
}else{
sqlite3ErrorMsg(pParse, "incomplete input");
}
@@ -178765,7 +181597,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
case CC_MINUS: {
if( z[1]=='-' ){
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
- *tokenType = TK_SPACE; /* IMP: R-22934-25134 */
+ *tokenType = TK_COMMENT;
return i;
}else if( z[1]=='>' ){
*tokenType = TK_PTR;
@@ -178801,7 +181633,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
if( c ) i++;
- *tokenType = TK_SPACE; /* IMP: R-22934-25134 */
+ *tokenType = TK_COMMENT;
return i;
}
case CC_PERCENT: {
@@ -179130,12 +181962,12 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){
if( tokenType>=TK_WINDOW ){
assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
|| tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
- || tokenType==TK_QNUMBER
+ || tokenType==TK_QNUMBER || tokenType==TK_COMMENT
);
#else
if( tokenType>=TK_SPACE ){
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL
- || tokenType==TK_QNUMBER
+ || tokenType==TK_QNUMBER || tokenType==TK_COMMENT
);
#endif /* SQLITE_OMIT_WINDOWFUNC */
if( AtomicLoad(&db->u1.isInterrupted) ){
@@ -179169,6 +182001,13 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){
assert( n==6 );
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif /* SQLITE_OMIT_WINDOWFUNC */
+ }else if( tokenType==TK_COMMENT
+ && (db->init.busy || (db->flags & SQLITE_Comments)!=0)
+ ){
+ /* Ignore SQL comments if either (1) we are reparsing the schema or
+ ** (2) SQLITE_DBCONFIG_ENABLE_COMMENTS is turned on (the default). */
+ zSql += n;
+ continue;
}else if( tokenType!=TK_QNUMBER ){
Token x;
x.z = zSql;
@@ -179205,7 +182044,9 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){
if( pParse->zErrMsg==0 ){
pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
}
- sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
+ if( (pParse->prepFlags & SQLITE_PREPARE_DONT_LOG)==0 ){
+ sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
+ }
nErr++;
}
pParse->zTail = zSql;
@@ -179273,6 +182114,7 @@ SQLITE_PRIVATE char *sqlite3Normalize(
n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType);
if( NEVER(n<=0) ) break;
switch( tokenType ){
+ case TK_COMMENT:
case TK_SPACE: {
break;
}
@@ -179915,32 +182757,6 @@ SQLITE_API char *sqlite3_temp_directory = 0;
SQLITE_API char *sqlite3_data_directory = 0;
/*
-** Determine whether or not high-precision (long double) floating point
-** math works correctly on CPU currently running.
-*/
-static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){
- if( sizeof(LONGDOUBLE_TYPE)<=8 ){
- /* If the size of "long double" is not more than 8, then
- ** high-precision math is not possible. */
- return 0;
- }else{
- /* Just because sizeof(long double)>8 does not mean that the underlying
- ** hardware actually supports high-precision floating point. For example,
- ** clearing the 0x100 bit in the floating-point control word on Intel
- ** processors will make long double work like double, even though long
- ** double takes up more space. The only way to determine if long double
- ** actually works is to run an experiment. */
- LONGDOUBLE_TYPE a, b, c;
- rc++;
- a = 1.0+rc*0.1;
- b = 1.0e+18+rc*25.0;
- c = a+b;
- return b!=c;
- }
-}
-
-
-/*
** Initialize SQLite.
**
** This routine must be called to initialize the memory allocation,
@@ -180084,6 +182900,14 @@ SQLITE_API int sqlite3_initialize(void){
if( rc==SQLITE_OK ){
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
+#ifdef SQLITE_EXTRA_INIT_MUTEXED
+ {
+ int SQLITE_EXTRA_INIT_MUTEXED(const char*);
+ rc = SQLITE_EXTRA_INIT_MUTEXED(0);
+ }
+#endif
+ }
+ if( rc==SQLITE_OK ){
sqlite3MemoryBarrier();
sqlite3GlobalConfig.isInit = 1;
#ifdef SQLITE_EXTRA_INIT
@@ -180134,13 +182958,6 @@ SQLITE_API int sqlite3_initialize(void){
rc = SQLITE_EXTRA_INIT(0);
}
#endif
-
- /* Experimentally determine if high-precision floating point is
- ** available. */
-#ifndef SQLITE_OMIT_WSD
- sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc);
-#endif
-
return rc;
}
@@ -180547,17 +183364,22 @@ SQLITE_API int sqlite3_config(int op, ...){
** If lookaside is already active, return SQLITE_BUSY.
**
** The sz parameter is the number of bytes in each lookaside slot.
-** The cnt parameter is the number of slots. If pStart is NULL the
-** space for the lookaside memory is obtained from sqlite3_malloc().
-** If pStart is not NULL then it is sz*cnt bytes of memory to use for
-** the lookaside memory.
+** The cnt parameter is the number of slots. If pBuf is NULL the
+** space for the lookaside memory is obtained from sqlite3_malloc()
+** or similar. If pBuf is not NULL then it is sz*cnt bytes of memory
+** to use for the lookaside memory.
*/
-static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
+static int setupLookaside(
+ sqlite3 *db, /* Database connection being configured */
+ void *pBuf, /* Memory to use for lookaside. May be NULL */
+ int sz, /* Desired size of each lookaside memory slot */
+ int cnt /* Number of slots to allocate */
+){
#ifndef SQLITE_OMIT_LOOKASIDE
- void *pStart;
- sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt;
- int nBig; /* Number of full-size slots */
- int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */
+ void *pStart; /* Start of the lookaside buffer */
+ sqlite3_int64 szAlloc; /* Total space set aside for lookaside memory */
+ int nBig; /* Number of full-size slots */
+ int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */
if( sqlite3LookasideUsed(db,0)>0 ){
return SQLITE_BUSY;
@@ -180570,17 +183392,22 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
sqlite3_free(db->lookaside.pStart);
}
/* The size of a lookaside slot after ROUNDDOWN8 needs to be larger
- ** than a pointer to be useful.
+ ** than a pointer and small enough to fit in a u16.
*/
- sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
+ sz = ROUNDDOWN8(sz);
if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0;
- if( cnt<0 ) cnt = 0;
- if( sz==0 || cnt==0 ){
+ if( sz>65528 ) sz = 65528;
+ /* Count must be at least 1 to be useful, but not so large as to use
+ ** more than 0x7fff0000 total bytes for lookaside. */
+ if( cnt<1 ) cnt = 0;
+ if( sz>0 && cnt>(0x7fff0000/sz) ) cnt = 0x7fff0000/sz;
+ szAlloc = (i64)sz*(i64)cnt;
+ if( szAlloc==0 ){
sz = 0;
pStart = 0;
}else if( pBuf==0 ){
sqlite3BeginBenignMalloc();
- pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */
+ pStart = sqlite3Malloc( szAlloc );
sqlite3EndBenignMalloc();
if( pStart ) szAlloc = sqlite3MallocSize(pStart);
}else{
@@ -180589,10 +183416,10 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( sz>=LOOKASIDE_SMALL*3 ){
nBig = szAlloc/(3*LOOKASIDE_SMALL+sz);
- nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
+ nSm = (szAlloc - (i64)sz*(i64)nBig)/LOOKASIDE_SMALL;
}else if( sz>=LOOKASIDE_SMALL*2 ){
nBig = szAlloc/(LOOKASIDE_SMALL+sz);
- nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
+ nSm = (szAlloc - (i64)sz*(i64)nBig)/LOOKASIDE_SMALL;
}else
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
if( sz>0 ){
@@ -180747,7 +183574,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
default: {
static const struct {
int op; /* The opcode */
- u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */
+ u64 mask; /* Mask of the bit in sqlite3.flags to set/clear */
} aFlagOp[] = {
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
@@ -180768,6 +183595,9 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema },
{ SQLITE_DBCONFIG_STMT_SCANSTATUS, SQLITE_StmtScanStatus },
{ SQLITE_DBCONFIG_REVERSE_SCANORDER, SQLITE_ReverseOrder },
+ { SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE, SQLITE_AttachCreate },
+ { SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE, SQLITE_AttachWrite },
+ { SQLITE_DBCONFIG_ENABLE_COMMENTS, SQLITE_Comments },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -181211,10 +184041,6 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */
sqlite3ValueFree(db->pErr);
sqlite3CloseExtensions(db);
-#if SQLITE_USER_AUTHENTICATION
- sqlite3_free(db->auth.zAuthUser);
- sqlite3_free(db->auth.zAuthPW);
-#endif
db->eOpenState = SQLITE_STATE_ERROR;
@@ -181558,6 +184384,9 @@ SQLITE_API int sqlite3_busy_handler(
db->busyHandler.pBusyArg = pArg;
db->busyHandler.nBusy = 0;
db->busyTimeout = 0;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ db->setlkTimeout = 0;
+#endif
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -181607,6 +184436,9 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
(void*)db);
db->busyTimeout = ms;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ db->setlkTimeout = ms;
+#endif
}else{
sqlite3_busy_handler(db, 0, 0);
}
@@ -181614,6 +184446,40 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
}
/*
+** Set the setlk timeout value.
+*/
+SQLITE_API int sqlite3_setlk_timeout(sqlite3 *db, int ms, int flags){
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int iDb;
+ int bBOC = ((flags & SQLITE_SETLK_BLOCK_ON_CONNECT) ? 1 : 0);
+#endif
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
+ if( ms<-1 ) return SQLITE_RANGE;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ sqlite3_mutex_enter(db->mutex);
+ db->setlkTimeout = ms;
+ db->setlkFlags = flags;
+ sqlite3BtreeEnterAll(db);
+ for(iDb=0; iDb<db->nDb; iDb++){
+ Btree *pBt = db->aDb[iDb].pBt;
+ if( pBt ){
+ sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pBt));
+ sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, (void*)&bBOC);
+ }
+ }
+ sqlite3BtreeLeaveAll(db);
+ sqlite3_mutex_leave(db->mutex);
+#endif
+#if !defined(SQLITE_ENABLE_API_ARMOR) && !defined(SQLITE_ENABLE_SETLK_TIMEOUT)
+ UNUSED_PARAMETER(db);
+ UNUSED_PARAMETER(flags);
+#endif
+ return SQLITE_OK;
+}
+
+/*
** Cause any pending operation to stop at its earliest opportunity.
*/
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
@@ -181681,7 +184547,8 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
- SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE);
+ SQLITE_SUBTYPE|SQLITE_INNOCUOUS|
+ SQLITE_RESULT_SUBTYPE|SQLITE_SELFORDER1);
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
/* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
@@ -182648,8 +185515,8 @@ static const int aHardLimit[] = {
#if SQLITE_MAX_VDBE_OP<40
# error SQLITE_MAX_VDBE_OP must be at least 40
#endif
-#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127
-# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127
+#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>32767
+# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 32767
#endif
#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
# error SQLITE_MAX_ATTACHED must be between 0 and 125
@@ -182716,8 +185583,8 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
if( newLimit>=0 ){ /* IMP: R-52476-28732 */
if( newLimit>aHardLimit[limitId] ){
newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */
- }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){
- newLimit = 1;
+ }else if( newLimit<SQLITE_MIN_LENGTH && limitId==SQLITE_LIMIT_LENGTH ){
+ newLimit = SQLITE_MIN_LENGTH;
}
db->aLimit[limitId] = newLimit;
}
@@ -183112,6 +185979,9 @@ static int openDatabase(
| SQLITE_EnableTrigger
| SQLITE_EnableView
| SQLITE_CacheSpill
+ | SQLITE_AttachCreate
+ | SQLITE_AttachWrite
+ | SQLITE_Comments
#if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0
| SQLITE_TrustedSchema
#endif
@@ -183236,6 +186106,7 @@ static int openDatabase(
if( ((1<<(flags&7)) & 0x46)==0 ){
rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
}else{
+ if( zFilename==0 ) zFilename = ":memory:";
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
}
if( rc!=SQLITE_OK ){
@@ -183573,7 +186444,7 @@ SQLITE_API int sqlite3_set_clientdata(
return SQLITE_OK;
}else{
size_t n = strlen(zName);
- p = sqlite3_malloc64( sizeof(DbClientData)+n+1 );
+ p = sqlite3_malloc64( SZ_DBCLIENTDATA(n+1) );
if( p==0 ){
if( xDestructor ) xDestructor(pData);
sqlite3_mutex_leave(db->mutex);
@@ -183727,13 +186598,10 @@ SQLITE_API int sqlite3_table_column_metadata(
if( zColumnName==0 ){
/* Query for existence of table only */
}else{
- for(iCol=0; iCol<pTab->nCol; iCol++){
+ iCol = sqlite3ColumnIndex(pTab, zColumnName);
+ if( iCol>=0 ){
pCol = &pTab->aCol[iCol];
- if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){
- break;
- }
- }
- if( iCol==pTab->nCol ){
+ }else{
if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){
iCol = pTab->iPKey;
pCol = iCol>=0 ? &pTab->aCol[iCol] : 0;
@@ -183942,8 +186810,8 @@ SQLITE_API int sqlite3_test_control(int op, ...){
/* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b);
**
** If b is true, then activate the SQLITE_FkNoAction setting. If b is
- ** false then clearn that setting. If the SQLITE_FkNoAction setting is
- ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if
+ ** false then clear that setting. If the SQLITE_FkNoAction setting is
+ ** enabled, all foreign key ON DELETE and ON UPDATE actions behave as if
** they were NO ACTION, regardless of how they are defined.
**
** NB: One must usually run "PRAGMA writable_schema=RESET" after
@@ -184061,7 +186929,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** issue "defined but not used" warnings. */
if( x==9999 ){
sqlite3ShowExpr(0);
- sqlite3ShowExpr(0);
sqlite3ShowExprList(0);
sqlite3ShowIdList(0);
sqlite3ShowSrcList(0);
@@ -184148,6 +187015,18 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
+ /* sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, sqlite3 *db, int *N)
+ **
+ ** Write the current optimization settings into *N. A zero bit means that
+ ** the optimization is on, and a 1 bit means that the optimization is off.
+ */
+ case SQLITE_TESTCTRL_GETOPT: {
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ int *pN = va_arg(ap, int*);
+ *pN = db->dbOptFlags;
+ break;
+ }
+
/* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt);
**
** If parameter onoff is 1, subsequent calls to localtime() fail.
@@ -184379,24 +187258,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
-#if !defined(SQLITE_OMIT_WSD)
- /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X);
- **
- ** X<0 Make no changes to the bUseLongDouble. Just report value.
- ** X==0 Disable bUseLongDouble
- ** X==1 Enable bUseLongDouble
- ** X>=2 Set bUseLongDouble to its default value for this platform
- */
- case SQLITE_TESTCTRL_USELONGDOUBLE: {
- int b = va_arg(ap, int);
- if( b>=2 ) b = hasHighPrecisionDouble(b);
- if( b>=0 ) sqlite3Config.bUseLongDouble = b>0;
- rc = sqlite3Config.bUseLongDouble!=0;
- break;
- }
-#endif
-
-
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
**
@@ -184704,7 +187565,11 @@ SQLITE_API int sqlite3_snapshot_get(
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){
+ Pager *pPager = sqlite3BtreePager(pBt);
+ i64 dummy = 0;
+ sqlite3PagerSnapshotOpen(pPager, (sqlite3_snapshot*)&dummy);
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
+ sqlite3PagerSnapshotOpen(pPager, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
}
@@ -185293,7 +188158,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
-** in the same logical place as the position element, and act as sentinals
+** in the same logical place as the position element, and act as sentinels
** 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
** than the difference from the prior position, or the just the position plus
@@ -185512,6 +188377,13 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
#ifndef _FTSINT_H
#define _FTSINT_H
+/* #include <assert.h> */
+/* #include <stdlib.h> */
+/* #include <stddef.h> */
+/* #include <stdio.h> */
+/* #include <string.h> */
+/* #include <stdarg.h> */
+
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
@@ -185981,6 +188853,19 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
#define deliberate_fall_through
+/*
+** Macros needed to provide flexible arrays in a portable way
+*/
+#ifndef offsetof
+# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+#endif
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
+#endif
+
+
#endif /* SQLITE_AMALGAMATION */
#ifdef SQLITE_DEBUG
@@ -186085,7 +188970,7 @@ struct Fts3Table {
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
- /* True to disable the incremental doclist optimization. This is controled
+ /* True to disable the incremental doclist optimization. This is controlled
** by special insert command 'test-no-incr-doclist'. */
int bNoIncrDoclist;
@@ -186137,7 +189022,7 @@ struct Fts3Cursor {
/*
** The Fts3Cursor.eSearch member is always set to one of the following.
-** Actualy, Fts3Cursor.eSearch can be greater than or equal to
+** Actually, Fts3Cursor.eSearch can be greater than or equal to
** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index
** of the column to be searched. For example, in
**
@@ -186210,9 +189095,13 @@ struct Fts3Phrase {
*/
int nToken; /* Number of tokens in the phrase */
int iColumn; /* Index of column this phrase must match */
- Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */
+ Fts3PhraseToken aToken[FLEXARRAY]; /* One for each token in the phrase */
};
+/* Size (in bytes) of an Fts3Phrase object large enough to hold N tokens */
+#define SZ_FTS3PHRASE(N) \
+ (offsetof(Fts3Phrase,aToken)+(N)*sizeof(Fts3PhraseToken))
+
/*
** A tree of these objects forms the RHS of a MATCH operator.
**
@@ -186419,6 +189308,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **);
SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
+SQLITE_PRIVATE int sqlite3Fts3MsrCancel(Fts3Cursor*, Fts3Expr*);
/* fts3_tokenize_vtab.c */
SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *, void(*xDestroy)(void*));
@@ -186445,12 +189335,6 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk);
# define SQLITE_CORE 1
#endif
-/* #include <assert.h> */
-/* #include <stdlib.h> */
-/* #include <stddef.h> */
-/* #include <stdio.h> */
-/* #include <string.h> */
-/* #include <stdarg.h> */
/* #include "fts3.h" */
#ifndef SQLITE_CORE
@@ -188494,10 +191378,15 @@ static int fts3PoslistPhraseMerge(
if( *p1==POS_COLUMN ){
p1++;
p1 += fts3GetVarint32(p1, &iCol1);
+ /* iCol1==0 indicates corruption. Column 0 does not have a POS_COLUMN
+ ** entry, so this is actually end-of-doclist. */
+ if( iCol1==0 ) return 0;
}
if( *p2==POS_COLUMN ){
p2++;
p2 += fts3GetVarint32(p2, &iCol2);
+ /* As above, iCol2==0 indicates corruption. */
+ if( iCol2==0 ) return 0;
}
while( 1 ){
@@ -188784,7 +191673,7 @@ static int fts3DoclistOrMerge(
** sizes of the two inputs, plus enough space for exactly one of the input
** docids to grow.
**
- ** A symetric argument may be made if the doclists are in descending
+ ** A symmetric argument may be made if the doclists are in descending
** order.
*/
aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING);
@@ -190583,7 +193472,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
nDistance = iPrev - nMaxUndeferred;
}
- aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING);
+ aOut = (char *)sqlite3Fts3MallocZero(((i64)nPoslist)+FTS3_BUFFER_PADDING);
if( !aOut ){
sqlite3_free(aPoslist);
return SQLITE_NOMEM;
@@ -190882,7 +193771,7 @@ static int incrPhraseTokenNext(
**
** * does not contain any deferred tokens.
**
-** Advance it to the next matching documnent in the database and populate
+** Advance it to the next matching document in the database and populate
** the Fts3Doclist.pList and nList fields.
**
** If there is no "next" entry and no error occurs, then *pbEof is set to
@@ -191668,7 +194557,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
nTmp += p->pRight->pPhrase->doclist.nList;
}
nTmp += p->pPhrase->doclist.nList;
- aTmp = sqlite3_malloc64(nTmp*2);
+ aTmp = sqlite3_malloc64(nTmp*2 + FTS3_VARINT_MAX);
if( !aTmp ){
*pRc = SQLITE_NOMEM;
res = 0;
@@ -191889,7 +194778,7 @@ static int fts3EvalNext(Fts3Cursor *pCsr){
}
/*
-** Restart interation for expression pExpr so that the next call to
+** Restart iteration for expression pExpr so that the next call to
** fts3EvalNext() visits the first row. Do not allow incremental
** loading or merging of phrase doclists for this iteration.
**
@@ -191933,6 +194822,24 @@ static void fts3EvalRestart(
}
/*
+** Expression node pExpr is an MSR phrase. This function restarts pExpr
+** so that it is a regular phrase query, not an MSR. SQLITE_OK is returned
+** if successful, or an SQLite error code otherwise.
+*/
+SQLITE_PRIVATE int sqlite3Fts3MsrCancel(Fts3Cursor *pCsr, Fts3Expr *pExpr){
+ int rc = SQLITE_OK;
+ if( pExpr->bEof==0 ){
+ i64 iDocid = pExpr->iDocid;
+ fts3EvalRestart(pCsr, pExpr, &rc);
+ while( rc==SQLITE_OK && pExpr->iDocid!=iDocid ){
+ fts3EvalNextRow(pCsr, pExpr, &rc);
+ if( pExpr->bEof ) rc = FTS_CORRUPT_VTAB;
+ }
+ }
+ return rc;
+}
+
+/*
** 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
@@ -192319,7 +195226,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
}
#endif
-#if !SQLITE_CORE
+#if !defined(SQLITE_CORE)
/*
** Initialize API pointer table, if required.
*/
@@ -193064,6 +195971,23 @@ SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(
static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *);
/*
+** Search buffer z[], size n, for a '"' character. Or, if enable_parenthesis
+** is defined, search for '(' and ')' as well. Return the index of the first
+** such character in the buffer. If there is no such character, return -1.
+*/
+static int findBarredChar(const char *z, int n){
+ int ii;
+ for(ii=0; ii<n; ii++){
+ if( (z[ii]=='"')
+ || (sqlite3_fts3_enable_parentheses && (z[ii]=='(' || z[ii]==')'))
+ ){
+ return ii;
+ }
+ }
+ return -1;
+}
+
+/*
** Extract the next token from buffer z (length n) using the tokenizer
** and other information (column names etc.) in pParse. Create an Fts3Expr
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
@@ -193087,16 +196011,9 @@ static int getNextToken(
int rc;
sqlite3_tokenizer_cursor *pCursor;
Fts3Expr *pRet = 0;
- int i = 0;
-
- /* Set variable i to the maximum number of bytes of input to tokenize. */
- for(i=0; i<n; i++){
- if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break;
- if( z[i]=='"' ) break;
- }
- *pnConsumed = i;
- rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor);
+ *pnConsumed = n;
+ rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor);
if( rc==SQLITE_OK ){
const char *zToken;
int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
@@ -193104,7 +196021,18 @@ static int getNextToken(
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
if( rc==SQLITE_OK ){
- nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
+ /* Check that this tokenization did not gobble up any " characters. Or,
+ ** if enable_parenthesis is true, that it did not gobble up any
+ ** open or close parenthesis characters either. If it did, call
+ ** getNextToken() again, but pass only that part of the input buffer
+ ** up to the first such character. */
+ int iBarred = findBarredChar(z, iEnd);
+ if( iBarred>=0 ){
+ pModule->xClose(pCursor);
+ return getNextToken(pParse, iCol, z, iBarred, ppExpr, pnConsumed);
+ }
+
+ nByte = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1) + nToken;
pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte);
if( !pRet ){
rc = SQLITE_NOMEM;
@@ -193114,7 +196042,7 @@ static int getNextToken(
pRet->pPhrase->nToken = 1;
pRet->pPhrase->iColumn = iCol;
pRet->pPhrase->aToken[0].n = nToken;
- pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1];
+ pRet->pPhrase->aToken[0].z = (char*)&pRet->pPhrase->aToken[1];
memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken);
if( iEnd<n && z[iEnd]=='*' ){
@@ -193138,7 +196066,11 @@ static int getNextToken(
}
*pnConsumed = iEnd;
- }else if( i && rc==SQLITE_DONE ){
+ }else if( n && rc==SQLITE_DONE ){
+ int iBarred = findBarredChar(z, n);
+ if( iBarred>=0 ){
+ *pnConsumed = iBarred;
+ }
rc = SQLITE_OK;
}
@@ -193185,9 +196117,9 @@ static int getNextString(
Fts3Expr *p = 0;
sqlite3_tokenizer_cursor *pCursor = 0;
char *zTemp = 0;
- int nTemp = 0;
+ i64 nTemp = 0;
- const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
+ const int nSpace = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1);
int nToken = 0;
/* The final Fts3Expr data structure, including the Fts3Phrase,
@@ -193221,10 +196153,11 @@ static int getNextString(
Fts3PhraseToken *pToken;
p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken));
- if( !p ) goto no_mem;
-
zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte);
- if( !zTemp ) goto no_mem;
+ if( !zTemp || !p ){
+ rc = SQLITE_NOMEM;
+ goto getnextstring_out;
+ }
assert( nToken==ii );
pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii];
@@ -193239,9 +196172,6 @@ static int getNextString(
nToken = ii+1;
}
}
-
- pModule->xClose(pCursor);
- pCursor = 0;
}
if( rc==SQLITE_DONE ){
@@ -193249,7 +196179,10 @@ static int getNextString(
char *zBuf = 0;
p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp);
- if( !p ) goto no_mem;
+ if( !p ){
+ rc = SQLITE_NOMEM;
+ goto getnextstring_out;
+ }
memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p);
p->eType = FTSQUERY_PHRASE;
p->pPhrase = (Fts3Phrase *)&p[1];
@@ -193257,11 +196190,9 @@ static int getNextString(
p->pPhrase->nToken = nToken;
zBuf = (char *)&p->pPhrase->aToken[nToken];
+ assert( nTemp==0 || zTemp );
if( zTemp ){
memcpy(zBuf, zTemp, nTemp);
- sqlite3_free(zTemp);
- }else{
- assert( nTemp==0 );
}
for(jj=0; jj<p->pPhrase->nToken; jj++){
@@ -193271,17 +196202,17 @@ static int getNextString(
rc = SQLITE_OK;
}
- *ppExpr = p;
- return rc;
-no_mem:
-
+ getnextstring_out:
if( pCursor ){
pModule->xClose(pCursor);
}
sqlite3_free(zTemp);
- sqlite3_free(p);
- *ppExpr = 0;
- return SQLITE_NOMEM;
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(p);
+ p = 0;
+ }
+ *ppExpr = p;
+ return rc;
}
/*
@@ -193560,7 +196491,7 @@ static int fts3ExprParse(
/* The isRequirePhrase variable is set to true if a phrase or
** an expression contained in parenthesis is required. If a
- ** binary operator (AND, OR, NOT or NEAR) is encounted when
+ ** binary operator (AND, OR, NOT or NEAR) is encountered when
** isRequirePhrase is set, this is a syntax error.
*/
if( !isPhrase && isRequirePhrase ){
@@ -194142,7 +197073,6 @@ static void fts3ExprTestCommon(
}
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
- sqlite3Fts3ExprFree(pExpr);
sqlite3_result_error(context, "Error parsing expression", -1);
}else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
sqlite3_result_error_nomem(context);
@@ -194385,7 +197315,7 @@ static void fts3HashInsertElement(
}
-/* Resize the hash table so that it cantains "new_size" buckets.
+/* Resize the hash table so that it contains "new_size" buckets.
** "new_size" must be a power of 2. The hash table might fail
** to resize if sqliteMalloc() fails.
**
@@ -194840,7 +197770,7 @@ 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 precedes the zFrom ending, then change the
** ending to zTo.
**
** The input word *pz and zFrom are both in reverse order. zTo
@@ -195475,11 +198405,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
#ifdef SQLITE_TEST
-#if defined(INCLUDE_SQLITE_TCL_H)
-# include "sqlite_tcl.h"
-#else
-# include "tcl.h"
-#endif
+#include "tclsqlite.h"
/* #include <string.h> */
/*
@@ -196355,7 +199281,7 @@ static int fts3tokFilterMethod(
fts3tokResetCursor(pCsr);
if( idxNum==1 ){
const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
- int nByte = sqlite3_value_bytes(apVal[0]);
+ sqlite3_int64 nByte = sqlite3_value_bytes(apVal[0]);
pCsr->zInput = sqlite3_malloc64(nByte+1);
if( pCsr->zInput==0 ){
rc = SQLITE_NOMEM;
@@ -200427,7 +203353,7 @@ static int fts3IncrmergePush(
**
** It is assumed that the buffer associated with pNode is already large
** enough to accommodate the new entry. The buffer associated with pPrev
-** is extended by this function if requrired.
+** is extended by this function if required.
**
** If an error (i.e. OOM condition) occurs, an SQLite error code is
** returned. Otherwise, SQLITE_OK.
@@ -202090,7 +205016,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
/*
** SQLite value pRowid contains the rowid of a row that may or may not be
** present in the FTS3 table. If it is, delete it and adjust the contents
-** of subsiduary data structures accordingly.
+** of subsidiary data structures accordingly.
*/
static int fts3DeleteByRowid(
Fts3Table *p,
@@ -202416,9 +205342,13 @@ struct MatchinfoBuffer {
int nElem;
int bGlobal; /* Set if global data is loaded */
char *zMatchinfo;
- u32 aMatchinfo[1];
+ u32 aMI[FLEXARRAY];
};
+/* Size (in bytes) of a MatchinfoBuffer sufficient for N elements */
+#define SZ_MATCHINFOBUFFER(N) \
+ (offsetof(MatchinfoBuffer,aMI)+(((N)+1)/2)*sizeof(u64))
+
/*
** The snippet() and offsets() functions both return text values. An instance
@@ -202443,13 +205373,13 @@ struct StrBuffer {
static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
MatchinfoBuffer *pRet;
sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1)
- + sizeof(MatchinfoBuffer);
+ + SZ_MATCHINFOBUFFER(1);
sqlite3_int64 nStr = strlen(zMatchinfo);
pRet = sqlite3Fts3MallocZero(nByte + nStr+1);
if( pRet ){
- pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet;
- pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0]
+ pRet->aMI[0] = (u8*)(&pRet->aMI[1]) - (u8*)pRet;
+ pRet->aMI[1+nElem] = pRet->aMI[0]
+ sizeof(u32)*((int)nElem+1);
pRet->nElem = (int)nElem;
pRet->zMatchinfo = ((char*)pRet) + nByte;
@@ -202463,10 +205393,10 @@ static MatchinfoBuffer *fts3MIBufferNew(size_t 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->aMI[1]
+ || (u32*)p==&pBuf->aMI[pBuf->nElem+2]
);
- if( (u32*)p==&pBuf->aMatchinfo[1] ){
+ if( (u32*)p==&pBuf->aMI[1] ){
pBuf->aRef[1] = 0;
}else{
pBuf->aRef[2] = 0;
@@ -202483,18 +205413,18 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
if( p->aRef[1]==0 ){
p->aRef[1] = 1;
- aOut = &p->aMatchinfo[1];
+ aOut = &p->aMI[1];
xRet = fts3MIBufferFree;
}
else if( p->aRef[2]==0 ){
p->aRef[2] = 1;
- aOut = &p->aMatchinfo[p->nElem+2];
+ aOut = &p->aMI[p->nElem+2];
xRet = fts3MIBufferFree;
}else{
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));
+ if( p->bGlobal ) memcpy(aOut, &p->aMI[1], p->nElem*sizeof(u32));
}
}
@@ -202504,7 +205434,7 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){
p->bGlobal = 1;
- memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32));
+ memcpy(&p->aMI[2+p->nElem], &p->aMI[1], p->nElem*sizeof(u32));
}
/*
@@ -202706,6 +205636,7 @@ static int fts3SnippetNextCandidate(SnippetIter *pIter){
return 1;
}
+ assert( pIter->nSnippet>=0 );
pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1;
for(i=0; i<pIter->nPhrase; i++){
SnippetPhrase *pPhrase = &pIter->aPhrase[i];
@@ -202918,7 +205849,7 @@ static int fts3StringAppend(
}
/* If there is insufficient space allocated at StrBuffer.z, use realloc()
- ** to grow the buffer until so that it is big enough to accomadate the
+ ** to grow the buffer until so that it is big enough to accommodate the
** appended data.
*/
if( pStr->n+nAppend+1>=pStr->nAlloc ){
@@ -203330,16 +206261,16 @@ static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
break;
case FTS3_MATCHINFO_LHITS:
- nVal = pInfo->nCol * pInfo->nPhrase;
+ nVal = (size_t)pInfo->nCol * pInfo->nPhrase;
break;
case FTS3_MATCHINFO_LHITS_BM:
- nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32);
+ nVal = (size_t)pInfo->nPhrase * ((pInfo->nCol + 31) / 32);
break;
default:
assert( cArg==FTS3_MATCHINFO_HITS );
- nVal = pInfo->nCol * pInfo->nPhrase * 3;
+ nVal = (size_t)pInfo->nCol * pInfo->nPhrase * 3;
break;
}
@@ -203894,6 +206825,22 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
}
/*
+** If expression pExpr is a phrase expression that uses an MSR query,
+** restart it as a regular, non-incremental query. Return SQLITE_OK
+** if successful, or an SQLite error code otherwise.
+*/
+static int fts3ExprRestartIfCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ TermOffsetCtx *p = (TermOffsetCtx*)ctx;
+ int rc = SQLITE_OK;
+ UNUSED_PARAMETER(iPhrase);
+ if( pExpr->pPhrase && pExpr->pPhrase->bIncr ){
+ rc = sqlite3Fts3MsrCancel(p->pCsr, pExpr);
+ pExpr->pPhrase->bIncr = 0;
+ }
+ return rc;
+}
+
+/*
** Implementation of offsets() function.
*/
SQLITE_PRIVATE void sqlite3Fts3Offsets(
@@ -203929,6 +206876,12 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
sCtx.iDocid = pCsr->iPrevId;
sCtx.pCsr = pCsr;
+ /* If a query restart will be required, do it here, rather than later of
+ ** after pointers to poslist buffers that may be invalidated by a restart
+ ** have been saved. */
+ rc = sqlite3Fts3ExprIterate(pCsr->pExpr, fts3ExprRestartIfCb, (void*)&sCtx);
+ if( rc!=SQLITE_OK ) goto offsets_out;
+
/* Loop through the table columns, appending offset information to
** string-buffer res for each column.
*/
@@ -204875,8 +207828,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
** Beginning with version 3.45.0 (circa 2024-01-01), these routines also
** accept BLOB values that have JSON encoded using a binary representation
** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk
-** format SQLite JSONB is completely different and incompatible with
-** PostgreSQL JSONB.
+** format for SQLite-JSONB is completely different and incompatible with
+** PostgreSQL-JSONB.
**
** Decoding and interpreting JSONB is still O(N) where N is the size of
** the input, the same as text JSON. However, the constant of proportionality
@@ -204933,7 +207886,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
**
** The payload size need not be expressed in its minimal form. For example,
** if the payload size is 10, the size can be expressed in any of 5 different
-** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte,
+** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by one 0x0a byte,
** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by
** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and
** a single byte of 0x0a. The shorter forms are preferred, of course, but
@@ -204943,7 +207896,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
** the size when it becomes known, resulting in a non-minimal encoding.
**
** The value (X>>4)==15 is not actually used in the current implementation
-** (as SQLite is currently unable handle BLOBs larger than about 2GB)
+** (as SQLite is currently unable to handle BLOBs larger than about 2GB)
** but is included in the design to allow for future enhancements.
**
** The payload follows the header. NULL, TRUE, and FALSE have no payload and
@@ -205003,23 +207956,47 @@ static const char * const jsonbType[] = {
** increase for the text-JSON 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,
+#ifdef SQLITE_ASCII
+/*0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ 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, 0, /* 1 */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */
+#endif
+#ifdef SQLITE_EBCDIC
+/*0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ 0, 0, 0, 0, 0, 1, 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, /* 1 */
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */
+#endif
+
};
#define jsonIsspace(x) (jsonIsSpace[(unsigned char)x])
@@ -205027,7 +208004,13 @@ static const char jsonIsSpace[] = {
** The set of all space characters recognized by jsonIsspace().
** Useful as the second argument to strspn().
*/
+#ifdef SQLITE_ASCII
static const char jsonSpaces[] = "\011\012\015\040";
+#endif
+#ifdef SQLITE_EBCDIC
+static const char jsonSpaces[] = "\005\045\015\100";
+#endif
+
/*
** Characters that are special to JSON. Control characters,
@@ -205036,23 +208019,46 @@ static const char jsonSpaces[] = "\011\012\015\040";
** it in the set of special characters.
*/
static const char jsonIsOk[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+#ifdef SQLITE_ASCII
+/*0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
+ 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 5 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */
+#endif
+#ifdef SQLITE_EBCDIC
+/*0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, /* 2 */
+ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 3 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, /* 7 */
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */
+#endif
};
/* Objects */
@@ -205197,7 +208203,7 @@ struct JsonParse {
** Forward references
**************************************************************************/
static void jsonReturnStringAsBlob(JsonString*);
-static int jsonFuncArgMightBeBinary(sqlite3_value *pJson);
+static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p);
static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*);
static void jsonReturnParse(sqlite3_context*,JsonParse*);
static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32);
@@ -205271,7 +208277,7 @@ static int jsonCacheInsert(
** most-recently used entry if it isn't so already.
**
** The JsonParse object returned still belongs to the Cache and might
-** be deleted at any moment. If the caller whants the JsonParse to
+** be deleted at any moment. If the caller wants the JsonParse to
** linger, it needs to increment the nPJRef reference counter.
*/
static JsonParse *jsonCacheSearch(
@@ -205615,11 +208621,9 @@ static void jsonAppendSqlValue(
break;
}
default: {
- if( jsonFuncArgMightBeBinary(pValue) ){
- JsonParse px;
- memset(&px, 0, sizeof(px));
- px.aBlob = (u8*)sqlite3_value_blob(pValue);
- px.nBlob = sqlite3_value_bytes(pValue);
+ JsonParse px;
+ memset(&px, 0, sizeof(px));
+ if( jsonArgIsJsonb(pValue, &px) ){
jsonTranslateBlobToText(&px, 0, p);
}else if( p->eErr==0 ){
sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
@@ -205938,7 +208942,7 @@ static void jsonWrongNumArgs(
*/
static int jsonBlobExpand(JsonParse *pParse, u32 N){
u8 *aNew;
- u32 t;
+ u64 t;
assert( N>pParse->nBlobAlloc );
if( pParse->nBlobAlloc==0 ){
t = 100;
@@ -205948,8 +208952,9 @@ static int jsonBlobExpand(JsonParse *pParse, u32 N){
if( t<N ) t = N+100;
aNew = sqlite3DbRealloc(pParse->db, pParse->aBlob, t);
if( aNew==0 ){ pParse->oom = 1; return 1; }
+ assert( t<0x7fffffff );
pParse->aBlob = aNew;
- pParse->nBlobAlloc = t;
+ pParse->nBlobAlloc = (u32)t;
return 0;
}
@@ -206016,7 +209021,7 @@ static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode(
}
-/* Append an node type byte together with the payload size and
+/* Append a node type byte together with the payload size and
** possibly also the payload.
**
** If aPayload is not NULL, then it is a pointer to the payload which
@@ -206085,8 +209090,10 @@ static int jsonBlobChangePayloadSize(
nExtra = 1;
}else if( szType==13 ){
nExtra = 2;
- }else{
+ }else if( szType==14 ){
nExtra = 4;
+ }else{
+ nExtra = 8;
}
if( szPayload<=11 ){
nNeeded = 0;
@@ -206556,7 +209563,12 @@ json_parse_restart:
|| c=='n' || c=='r' || c=='t'
|| (c=='u' && jsonIs4Hex(&z[j+1])) ){
if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ;
- }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
+ }else if( c=='\'' || c=='v' || c=='\n'
+#ifdef SQLITE_BUG_COMPATIBLE_20250510
+ || (c=='0') /* Legacy bug compatible */
+#else
+ || (c=='0' && !sqlite3Isdigit(z[j+1])) /* Correct implementation */
+#endif
|| (0xe2==(u8)c && 0x80==(u8)z[j+1]
&& (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
|| (c=='x' && jsonIs2Hex(&z[j+1])) ){
@@ -206906,10 +209918,7 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
u8 x;
u32 sz;
u32 n;
- if( NEVER(i>pParse->nBlob) ){
- *pSz = 0;
- return 0;
- }
+ assert( i<=pParse->nBlob );
x = pParse->aBlob[i]>>4;
if( x<=11 ){
sz = x;
@@ -206946,15 +209955,15 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
*pSz = 0;
return 0;
}
- sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) +
+ sz = ((u32)pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) +
(pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8];
n = 9;
}
if( (i64)i+sz+n > pParse->nBlob
&& (i64)i+sz+n > pParse->nBlob-pParse->delta
){
- sz = 0;
- n = 0;
+ *pSz = 0;
+ return 0;
}
*pSz = sz;
return n;
@@ -207051,9 +210060,12 @@ static u32 jsonTranslateBlobToText(
}
case JSONB_TEXT:
case JSONB_TEXTJ: {
- jsonAppendChar(pOut, '"');
- jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
- jsonAppendChar(pOut, '"');
+ if( pOut->nUsed+sz+2<=pOut->nAlloc || jsonStringGrow(pOut, sz+2)==0 ){
+ pOut->zBuf[pOut->nUsed] = '"';
+ memcpy(pOut->zBuf+pOut->nUsed+1,(const char*)&pParse->aBlob[i+n],sz);
+ pOut->zBuf[pOut->nUsed+sz+1] = '"';
+ pOut->nUsed += sz+2;
+ }
break;
}
case JSONB_TEXT5: {
@@ -207292,33 +210304,6 @@ static u32 jsonTranslateBlobToPrettyText(
return i;
}
-
-/* Return true if the input pJson
-**
-** For performance reasons, this routine does not do a detailed check of the
-** input BLOB to ensure that it is well-formed. Hence, false positives are
-** possible. False negatives should never occur, however.
-*/
-static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){
- u32 sz, n;
- const u8 *aBlob;
- int nBlob;
- JsonParse s;
- if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0;
- aBlob = sqlite3_value_blob(pJson);
- nBlob = sqlite3_value_bytes(pJson);
- if( nBlob<1 ) return 0;
- if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0;
- memset(&s, 0, sizeof(s));
- s.aBlob = (u8*)aBlob;
- s.nBlob = nBlob;
- n = jsonbPayloadSize(&s, 0, &sz);
- if( n==0 ) return 0;
- if( sz+n!=(u32)nBlob ) return 0;
- if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0;
- return sz+n==(u32)nBlob;
-}
-
/*
** Given that a JSONB_ARRAY object starts at offset i, return
** the number of entries in that array.
@@ -207352,6 +210337,82 @@ static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){
}
/*
+** If the JSONB at aIns[0..nIns-1] can be expanded (by denormalizing the
+** size field) by d bytes, then write the expansion into aOut[] and
+** return true. In this way, an overwrite happens without changing the
+** size of the JSONB, which reduces memcpy() operations and also make it
+** faster and easier to update the B-Tree entry that contains the JSONB
+** in the database.
+**
+** If the expansion of aIns[] by d bytes cannot be (easily) accomplished
+** then return false.
+**
+** The d parameter is guaranteed to be between 1 and 8.
+**
+** This routine is an optimization. A correct answer is obtained if it
+** always leaves the output unchanged and returns false.
+*/
+static int jsonBlobOverwrite(
+ u8 *aOut, /* Overwrite here */
+ const u8 *aIns, /* New content */
+ u32 nIns, /* Bytes of new content */
+ u32 d /* Need to expand new content by this much */
+){
+ u32 szPayload; /* Bytes of payload */
+ u32 i; /* New header size, after expansion & a loop counter */
+ u8 szHdr; /* Size of header before expansion */
+
+ /* Lookup table for finding the upper 4 bits of the first byte of the
+ ** expanded aIns[], based on the size of the expanded aIns[] header:
+ **
+ ** 2 3 4 5 6 7 8 9 */
+ static const u8 aType[] = { 0xc0, 0xd0, 0, 0xe0, 0, 0, 0, 0xf0 };
+
+ if( (aIns[0]&0x0f)<=2 ) return 0; /* Cannot enlarge NULL, true, false */
+ switch( aIns[0]>>4 ){
+ default: { /* aIns[] header size 1 */
+ if( ((1<<d)&0x116)==0 ) return 0; /* d must be 1, 2, 4, or 8 */
+ i = d + 1; /* New hdr sz: 2, 3, 5, or 9 */
+ szHdr = 1;
+ break;
+ }
+ case 12: { /* aIns[] header size is 2 */
+ if( ((1<<d)&0x8a)==0) return 0; /* d must be 1, 3, or 7 */
+ i = d + 2; /* New hdr sz: 2, 5, or 9 */
+ szHdr = 2;
+ break;
+ }
+ case 13: { /* aIns[] header size is 3 */
+ if( d!=2 && d!=6 ) return 0; /* d must be 2 or 6 */
+ i = d + 3; /* New hdr sz: 5 or 9 */
+ szHdr = 3;
+ break;
+ }
+ case 14: { /* aIns[] header size is 5 */
+ if( d!=4 ) return 0; /* d must be 4 */
+ i = 9; /* New hdr sz: 9 */
+ szHdr = 5;
+ break;
+ }
+ case 15: { /* aIns[] header size is 9 */
+ return 0; /* No solution */
+ }
+ }
+ assert( i>=2 && i<=9 && aType[i-2]!=0 );
+ aOut[0] = (aIns[0] & 0x0f) | aType[i-2];
+ memcpy(&aOut[i], &aIns[szHdr], nIns-szHdr);
+ szPayload = nIns - szHdr;
+ while( 1/*edit-by-break*/ ){
+ i--;
+ aOut[i] = szPayload & 0xff;
+ if( i==1 ) break;
+ szPayload >>= 8;
+ }
+ assert( (szPayload>>8)==0 );
+ return 1;
+}
+
+/*
** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of
** content beginning at iDel, and replacing them with nIns bytes of
** content given by aIns.
@@ -207372,6 +210433,11 @@ static void jsonBlobEdit(
u32 nIns /* Bytes of content to insert */
){
i64 d = (i64)nIns - (i64)nDel;
+ if( d<0 && d>=(-8) && aIns!=0
+ && jsonBlobOverwrite(&pParse->aBlob[iDel], aIns, nIns, (int)-d)
+ ){
+ return;
+ }
if( d!=0 ){
if( pParse->nBlob + d > pParse->nBlobAlloc ){
jsonBlobExpand(pParse, pParse->nBlob+d);
@@ -207383,7 +210449,9 @@ static void jsonBlobEdit(
pParse->nBlob += d;
pParse->delta += d;
}
- if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns);
+ if( nIns && aIns ){
+ memcpy(&pParse->aBlob[iDel], aIns, nIns);
+ }
}
/*
@@ -207468,7 +210536,21 @@ static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){
case 'r': { *piOut = '\r'; return 2; }
case 't': { *piOut = '\t'; return 2; }
case 'v': { *piOut = '\v'; return 2; }
- case '0': { *piOut = 0; return 2; }
+ case '0': {
+ /* JSON5 requires that the \0 escape not be followed by a digit.
+ ** But SQLite did not enforce this restriction in versions 3.42.0
+ ** through 3.49.2. That was a bug. But some applications might have
+ ** come to depend on that bug. Use the SQLITE_BUG_COMPATIBLE_20250510
+ ** option to restore the old buggy behavior. */
+#ifdef SQLITE_BUG_COMPATIBLE_20250510
+ /* Legacy bug-compatible behavior */
+ *piOut = 0;
+#else
+ /* Correct behavior */
+ *piOut = (n>2 && sqlite3Isdigit(z[2])) ? JSON_INVALID_CHAR : 0;
+#endif
+ return 2;
+ }
case '\'':
case '"':
case '/':
@@ -207699,7 +210781,9 @@ static u32 jsonLookupStep(
zPath++;
if( zPath[0]=='"' ){
zKey = zPath + 1;
- for(i=1; zPath[i] && zPath[i]!='"'; i++){}
+ for(i=1; zPath[i] && zPath[i]!='"'; i++){
+ if( zPath[i]=='\\' && zPath[i+1]!=0 ) i++;
+ }
nKey = i-1;
if( zPath[i] ){
i++;
@@ -207966,7 +211050,7 @@ static void jsonReturnFromBlob(
char *zOut;
u32 nOut = sz;
z = (const char*)&pParse->aBlob[i+n];
- zOut = sqlite3DbMallocRaw(db, nOut+1);
+ zOut = sqlite3DbMallocRaw(db, ((u64)nOut)+1);
if( zOut==0 ) goto returnfromblob_oom;
for(iIn=iOut=0; iIn<sz; iIn++){
char c = z[iIn];
@@ -208061,10 +211145,7 @@ static int jsonFunctionArgToBlob(
return 0;
}
case SQLITE_BLOB: {
- if( jsonFuncArgMightBeBinary(pArg) ){
- pParse->aBlob = (u8*)sqlite3_value_blob(pArg);
- pParse->nBlob = sqlite3_value_bytes(pArg);
- }else{
+ if( !jsonArgIsJsonb(pArg, pParse) ){
sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1);
return 1;
}
@@ -208144,7 +211225,7 @@ static char *jsonBadPathError(
}
/* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent
-** arguments come in parse where each pair contains a JSON path and
+** arguments come in pairs where each pair contains a JSON path and
** content to insert or set at that patch. Do the updates
** and return the result.
**
@@ -208215,27 +211296,46 @@ jsonInsertIntoBlob_patherror:
/*
** If pArg is a blob that seems like a JSONB blob, then initialize
** p to point to that JSONB and return TRUE. If pArg does not seem like
-** a JSONB blob, then return FALSE;
-**
-** This routine is only called if it is already known that pArg is a
-** blob. The only open question is whether or not the blob appears
-** to be a JSONB blob.
+** a JSONB blob, then return FALSE.
+**
+** For small BLOBs (having no more than 7 bytes of payload) a full
+** validity check is done. So for small BLOBs this routine only returns
+** true if the value is guaranteed to be a valid JSONB. For larger BLOBs
+** (8 byte or more of payload) only the size of the outermost element is
+** checked to verify that the BLOB is superficially valid JSONB.
+**
+** A full JSONB validation is done on smaller BLOBs because those BLOBs might
+** also be text JSON that has been incorrectly cast into a BLOB.
+** (See tag-20240123-a and https://sqlite.org/forum/forumpost/012136abd5)
+** If the BLOB is 9 bytes are larger, then it is not possible for the
+** superficial size check done here to pass if the input is really text
+** JSON so we do not need to look deeper in that case.
+**
+** Why we only need to do full JSONB validation for smaller BLOBs:
+**
+** The first byte of valid JSON text must be one of: '{', '[', '"', ' ', '\n',
+** '\r', '\t', '-', or a digit '0' through '9'. Of these, only a subset
+** can also be the first byte of JSONB: '{', '[', and digits '3'
+** through '9'. In every one of those cases, the payload size is 7 bytes
+** or less. So if we do full JSONB validation for every BLOB where the
+** payload is less than 7 bytes, we will never get a false positive for
+** JSONB on an input that is really text JSON.
*/
static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){
u32 n, sz = 0;
+ u8 c;
+ if( sqlite3_value_type(pArg)!=SQLITE_BLOB ) return 0;
p->aBlob = (u8*)sqlite3_value_blob(pArg);
p->nBlob = (u32)sqlite3_value_bytes(pArg);
- if( p->nBlob==0 ){
- p->aBlob = 0;
- return 0;
- }
- if( NEVER(p->aBlob==0) ){
- return 0;
- }
- if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT
+ if( p->nBlob>0
+ && ALWAYS(p->aBlob!=0)
+ && ((c = p->aBlob[0]) & 0x0f)<=JSONB_OBJECT
&& (n = jsonbPayloadSize(p, 0, &sz))>0
&& sz+n==p->nBlob
- && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0)
+ && ((c & 0x0f)>JSONB_FALSE || sz==0)
+ && (sz>7
+ || (c!=0x7b && c!=0x5b && !sqlite3Isdigit(c))
+ || jsonbValidityCheck(p, 0, p->nBlob, 1)==0)
){
return 1;
}
@@ -208313,7 +211413,7 @@ rebuild_from_cache:
** JSON functions were suppose to work. From the beginning, blob was
** reserved for expansion and a blob value should have raised an error.
** But it did not, due to a bug. And many applications came to depend
- ** upon this buggy behavior, espeically when using the CLI and reading
+ ** upon this buggy behavior, especially when using the CLI and reading
** JSON text using readfile(), which returns a blob. For this reason
** we will continue to support the bug moving forward.
** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d
@@ -208709,10 +211809,16 @@ static void jsonExtractFunc(
** NUMBER ==> $[NUMBER] // PG compatible
** LABEL ==> $.LABEL // PG compatible
** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
+ **
+ ** Updated 2024-05-27: If the NUMBER is negative, then PG counts from
+ ** the right of the array. Hence for negative NUMBER:
+ **
+ ** NUMBER ==> $[#NUMBER] // PG compatible
*/
jsonStringInit(&jx, ctx);
if( sqlite3_value_type(argv[i])==SQLITE_INTEGER ){
jsonAppendRawNZ(&jx, "[", 1);
+ if( zPath[0]=='-' ) jsonAppendRawNZ(&jx,"#",1);
jsonAppendRaw(&jx, zPath, nPath);
jsonAppendRawNZ(&jx, "]", 2);
}else if( jsonAllAlphanum(zPath, nPath) ){
@@ -209322,21 +212428,17 @@ static void jsonValidFunc(
return;
}
case SQLITE_BLOB: {
- if( jsonFuncArgMightBeBinary(argv[0]) ){
+ JsonParse py;
+ memset(&py, 0, sizeof(py));
+ if( jsonArgIsJsonb(argv[0], &py) ){
if( flags & 0x04 ){
/* Superficial checking only - accomplished by the
- ** jsonFuncArgMightBeBinary() call above. */
+ ** jsonArgIsJsonb() call above. */
res = 1;
}else if( flags & 0x08 ){
/* Strict checking. Check by translating BLOB->TEXT->BLOB. If
** no errors occur, call that a "strict check". */
- JsonParse px;
- u32 iErr;
- memset(&px, 0, sizeof(px));
- px.aBlob = (u8*)sqlite3_value_blob(argv[0]);
- px.nBlob = sqlite3_value_bytes(argv[0]);
- iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1);
- res = iErr==0;
+ res = 0==jsonbValidityCheck(&py, 0, py.nBlob, 1);
}
break;
}
@@ -209394,9 +212496,7 @@ static void jsonErrorFunc(
UNUSED_PARAMETER(argc);
memset(&s, 0, sizeof(s));
s.db = sqlite3_context_db_handle(ctx);
- if( jsonFuncArgMightBeBinary(argv[0]) ){
- s.aBlob = (u8*)sqlite3_value_blob(argv[0]);
- s.nBlob = sqlite3_value_bytes(argv[0]);
+ if( jsonArgIsJsonb(argv[0], &s) ){
iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1);
}else{
s.zJson = (char*)sqlite3_value_text(argv[0]);
@@ -209557,18 +212657,20 @@ static void jsonObjectStep(
UNUSED_PARAMETER(argc);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
+ z = (const char*)sqlite3_value_text(argv[0]);
+ n = sqlite3Strlen30(z);
if( pStr->zBuf==0 ){
jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '{');
- }else if( pStr->nUsed>1 ){
+ }else if( pStr->nUsed>1 && z!=0 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
- z = (const char*)sqlite3_value_text(argv[0]);
- n = sqlite3Strlen30(z);
- jsonAppendString(pStr, z, n);
- jsonAppendChar(pStr, ':');
- jsonAppendSqlValue(pStr, argv[1]);
+ if( z!=0 ){
+ jsonAppendString(pStr, z, n);
+ jsonAppendChar(pStr, ':');
+ jsonAppendSqlValue(pStr, argv[1]);
+ }
}
}
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
@@ -210081,9 +213183,8 @@ static int jsonEachFilter(
memset(&p->sParse, 0, sizeof(p->sParse));
p->sParse.nJPRef = 1;
p->sParse.db = p->db;
- if( jsonFuncArgMightBeBinary(argv[0]) ){
- p->sParse.nBlob = sqlite3_value_bytes(argv[0]);
- p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]);
+ if( jsonArgIsJsonb(argv[0], &p->sParse) ){
+ /* We have JSONB */
}else{
p->sParse.zJson = (char*)sqlite3_value_text(argv[0]);
p->sParse.nJson = sqlite3_value_bytes(argv[0]);
@@ -210377,6 +213478,8 @@ SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3 *db){
#endif
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */
+/* #include <stddef.h> */
+
/*
** If building separately, we will need some setup that is normally
** found in sqliteInt.h
@@ -210407,6 +213510,14 @@ typedef unsigned int u32;
# define ALWAYS(X) (X)
# define NEVER(X) (X)
#endif
+#ifndef offsetof
+#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+#endif
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
+#endif
#endif /* !defined(SQLITE_AMALGAMATION) */
/* Macro to check for 4-byte alignment. Only used inside of assert() */
@@ -210727,9 +213838,13 @@ struct RtreeMatchArg {
RtreeGeomCallback cb; /* Info about the callback functions */
int nParam; /* Number of parameters to the SQL function */
sqlite3_value **apSqlParam; /* Original SQL parameter values */
- RtreeDValue aParam[1]; /* Values for parameters to the SQL function */
+ RtreeDValue aParam[FLEXARRAY]; /* Values for parameters to the SQL function */
};
+/* Size of an RtreeMatchArg object with N parameters */
+#define SZ_RTREEMATCHARG(N) \
+ (offsetof(RtreeMatchArg,aParam)+(N)*sizeof(RtreeDValue))
+
#ifndef MAX
# define MAX(x,y) ((x) < (y) ? (y) : (x))
#endif
@@ -212418,7 +215533,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
}
/*
-** Return the N-dimensional volumn of the cell stored in *p.
+** Return the N-dimensional volume of the cell stored in *p.
*/
static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
RtreeDValue area = (RtreeDValue)1;
@@ -214088,8 +217203,8 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
sqlite3_str_append(pOut, "}", 1);
}
errCode = sqlite3_str_errcode(pOut);
- sqlite3_result_text(ctx, sqlite3_str_finish(pOut), -1, sqlite3_free);
sqlite3_result_error_code(ctx, errCode);
+ sqlite3_result_text(ctx, sqlite3_str_finish(pOut), -1, sqlite3_free);
}
/* This routine implements an SQL function that returns the "depth" parameter
@@ -214184,7 +217299,7 @@ static sqlite3_stmt *rtreeCheckPrepare(
/*
** 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.
+** appends it to the report being accumulated in pCheck.
*/
static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
va_list ap;
@@ -215372,7 +218487,7 @@ static void geopolyBBoxFinal(
** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2).
** Returns:
**
-** +2 x0,y0 is on the line segement
+** +2 x0,y0 is on the line segment
**
** +1 x0,y0 is beneath line segment
**
@@ -215478,7 +218593,7 @@ static void geopolyWithinFunc(
sqlite3_free(p2);
}
-/* Objects used by the overlap algorihm. */
+/* Objects used by the overlap algorithm. */
typedef struct GeoEvent GeoEvent;
typedef struct GeoSegment GeoSegment;
typedef struct GeoOverlap GeoOverlap;
@@ -216525,8 +219640,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
sqlite3_int64 nBlob;
int memErr = 0;
- nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue)
- + nArg*sizeof(sqlite3_value*);
+ nBlob = SZ_RTREEMATCHARG(nArg) + nArg*sizeof(sqlite3_value*);
pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob);
if( !pBlob ){
sqlite3_result_error_nomem(ctx);
@@ -216605,7 +219719,7 @@ SQLITE_API int sqlite3_rtree_query_callback(
);
}
-#if !SQLITE_CORE
+#ifndef SQLITE_CORE
#ifdef _WIN32
__declspec(dllexport)
#endif
@@ -217196,7 +220310,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
return rc;
}
-#if !SQLITE_CORE
+#ifndef SQLITE_CORE
#ifdef _WIN32
__declspec(dllexport)
#endif
@@ -217621,7 +220735,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
**
** "RBU" stands for "Resumable Bulk Update". As in a large database update
** transmitted via a wireless network to a mobile device. A transaction
-** applied using this extension is hence refered to as an "RBU update".
+** applied using this extension is hence referred to as an "RBU update".
**
**
** LIMITATIONS
@@ -217918,7 +221032,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
** 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
+** As with sqlite3rbu_open(), Zipvfs users should refer to the comment
** describing the sqlite3rbu_create_vfs() API function below for
** a description of the complications associated with using RBU with
** zipvfs databases.
@@ -218014,7 +221128,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
**
** If the RBU update has been completely applied, mark the RBU database
** as fully applied. Otherwise, assuming no error has occurred, save the
-** current state of the RBU update appliation to the RBU database.
+** current state of the RBU update application to the RBU database.
**
** If an error has already occurred as part of an sqlite3rbu_step()
** or sqlite3rbu_open() call, or if one occurs within this function, an
@@ -218454,6 +221568,27 @@ struct RbuFrame {
u32 iWalFrame;
};
+#ifndef UNUSED_PARAMETER
+/*
+** The following macros are used to suppress compiler warnings and to
+** make it clear to human readers when a function parameter is deliberately
+** left unused within the body of a function. This usually happens when
+** a function is called via a function pointer. For example the
+** implementation of an SQL aggregate step callback may not use the
+** parameter indicating the number of arguments passed to the aggregate,
+** if it knows that this is enforced elsewhere.
+**
+** When a function parameter is not used at all within the body of a function,
+** it is generally named "NotUsed" or "NotUsed2" to make things even clearer.
+** However, these macros may also be used to suppress warnings related to
+** parameters that may or may not be used depending on compilation options.
+** For example those parameters only used in assert() statements. In these
+** cases the parameters are named as per the usual conventions.
+*/
+#define UNUSED_PARAMETER(x) (void)(x)
+#define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y)
+#endif
+
/*
** RBU handle.
**
@@ -218505,7 +221640,7 @@ struct sqlite3rbu {
int rc; /* Value returned by last rbu_step() call */
char *zErrmsg; /* Error message if rc!=SQLITE_OK */
int nStep; /* Rows processed for current object */
- int nProgress; /* Rows processed for all objects */
+ sqlite3_int64 nProgress; /* Rows processed for all objects */
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 */
@@ -218622,7 +221757,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
v = (v<<6) + c;
}
z--;
- *pLen -= z - zStart;
+ *pLen -= (int)(z - zStart);
*pz = (char*)z;
return v;
}
@@ -218807,6 +221942,7 @@ static void rbuFossilDeltaFunc(
char *aOut;
assert( argc==2 );
+ UNUSED_PARAMETER(argc);
nOrig = sqlite3_value_bytes(argv[0]);
aOrig = (const char*)sqlite3_value_blob(argv[0]);
@@ -220386,13 +223522,13 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
else if( c==')' ){
nParen--;
if( nParen==0 ){
- int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
+ int nSpan = (int)(&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;
+ int nSpan = (int)(&zSql[i] - pIter->aIdxCol[iIdxCol].zSpan);
pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1];
}else if( c=='"' || c=='\'' || c=='`' ){
@@ -221082,6 +224218,8 @@ static void rbuFileSuffix3(const char *zBase, char *z){
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
}
+#else
+ UNUSED_PARAMETER2(zBase,z);
#endif
}
@@ -221666,7 +224804,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
"(%d, %Q), "
"(%d, %Q), "
"(%d, %d), "
- "(%d, %d), "
+ "(%d, %lld), "
"(%d, %lld), "
"(%d, %lld), "
"(%d, %lld), "
@@ -222024,6 +225162,7 @@ static void rbuIndexCntFunc(
sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
assert( nVal==1 );
+ UNUSED_PARAMETER(nVal);
rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
@@ -222299,7 +225438,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
){
if( zTarget==0 ){ return rbuMisuseError(); }
if( zState ){
- int n = strlen(zState);
+ size_t n = strlen(zState);
if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
return rbuMisuseError();
}
@@ -222516,6 +225655,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
*/
static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
int rc = SQLITE_OK;
+ UNUSED_PARAMETER(pArg);
#if defined(_WIN32_WCE)
{
LPWSTR zWideOld;
@@ -222914,7 +226054,7 @@ 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 existence of a *-wal file. rbuVfsRead() contains
** similar logic. */
if( rc==SQLITE_OK && *pSize==0
&& p->pRbu && rbuIsVacuum(p->pRbu)
@@ -223420,6 +226560,9 @@ static int rbuVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
** No-op.
*/
static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ UNUSED_PARAMETER(pVfs);
+ UNUSED_PARAMETER(a);
+ UNUSED_PARAMETER(b);
return 0;
}
@@ -223818,6 +226961,7 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
pIdxInfo->orderByConsumed = 1;
pIdxInfo->idxNum |= 0x08;
}
+ pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_HEX;
return SQLITE_OK;
}
@@ -224475,7 +227619,13 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
**
** 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.
+** update fails. INSERT operations also work, and operate as if they
+** where REPLACE. The size of the database can be extended by INSERT-ing
+** new pages on the end.
+**
+** Rows may not be deleted. However, doing an INSERT to page number N
+** with NULL page data causes the N-th page and all subsequent pages to be
+** deleted and the database to be truncated.
*/
/* #include "sqliteInt.h" ** Requires access to internal data structures ** */
@@ -224498,6 +227648,8 @@ struct DbpageCursor {
struct DbpageTable {
sqlite3_vtab base; /* Base class. Must be first */
sqlite3 *db; /* The database */
+ int iDbTrunc; /* Database to truncate */
+ Pgno pgnoTrunc; /* Size to truncate to */
};
/* Columns */
@@ -224506,7 +227658,6 @@ struct DbpageTable {
#define DBPAGE_COLUMN_SCHEMA 2
-
/*
** Connect to or create a dbpagevfs virtual table.
*/
@@ -224757,6 +227908,24 @@ static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
return SQLITE_OK;
}
+/*
+** Open write transactions. 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.
+**
+** Return SQLITE_OK if successful, or an SQLite error code otherwise.
+*/
+static int dbpageBeginTrans(DbpageTable *pTab){
+ sqlite3 *db = pTab->db;
+ int rc = SQLITE_OK;
+ int i;
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
+ }
+ return rc;
+}
+
static int dbpageUpdate(
sqlite3_vtab *pVtab,
int argc,
@@ -224768,11 +227937,11 @@ static int dbpageUpdate(
DbPage *pDbPage = 0;
int rc = SQLITE_OK;
char *zErr = 0;
- const char *zSchema;
int iDb;
Btree *pBt;
Pager *pPager;
int szPage;
+ int isInsert;
(void)pRowid;
if( pTab->db->flags & SQLITE_Defensive ){
@@ -224783,21 +227952,29 @@ static int dbpageUpdate(
zErr = "cannot delete";
goto update_fail;
}
- pgno = sqlite3_value_int(argv[0]);
- if( sqlite3_value_type(argv[0])==SQLITE_NULL
- || (Pgno)sqlite3_value_int(argv[1])!=pgno
- ){
- zErr = "cannot insert";
- goto update_fail;
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+ pgno = (Pgno)sqlite3_value_int(argv[2]);
+ isInsert = 1;
+ }else{
+ pgno = sqlite3_value_int(argv[0]);
+ if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
+ zErr = "cannot insert";
+ goto update_fail;
+ }
+ isInsert = 0;
}
- zSchema = (const char*)sqlite3_value_text(argv[4]);
- iDb = ALWAYS(zSchema) ? sqlite3FindDbName(pTab->db, zSchema) : -1;
- if( NEVER(iDb<0) ){
- zErr = "no such schema";
- goto update_fail;
+ if( sqlite3_value_type(argv[4])==SQLITE_NULL ){
+ iDb = 0;
+ }else{
+ const char *zSchema = (const char*)sqlite3_value_text(argv[4]);
+ iDb = sqlite3FindDbName(pTab->db, zSchema);
+ if( iDb<0 ){
+ zErr = "no such schema";
+ goto update_fail;
+ }
}
pBt = pTab->db->aDb[iDb].pBt;
- if( NEVER(pgno<1) || NEVER(pBt==0) || NEVER(pgno>sqlite3BtreeLastPage(pBt)) ){
+ if( pgno<1 || NEVER(pBt==0) ){
zErr = "bad page number";
goto update_fail;
}
@@ -224805,51 +227982,83 @@ static int dbpageUpdate(
if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
|| sqlite3_value_bytes(argv[3])!=szPage
){
- zErr = "bad page value";
+ if( sqlite3_value_type(argv[3])==SQLITE_NULL && isInsert && pgno>1 ){
+ /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and
+ ** all subsequent pages to be deleted. */
+ pTab->iDbTrunc = iDb;
+ pTab->pgnoTrunc = pgno-1;
+ pgno = 1;
+ }else{
+ zErr = "bad page value";
+ goto update_fail;
+ }
+ }
+
+ if( dbpageBeginTrans(pTab)!=SQLITE_OK ){
+ zErr = "failed to open transaction";
goto update_fail;
}
+
pPager = sqlite3BtreePager(pBt);
rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){
const void *pData = sqlite3_value_blob(argv[3]);
- assert( pData!=0 || pTab->db->mallocFailed );
- if( pData
- && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK
- ){
- memcpy(sqlite3PagerGetData(pDbPage), pData, szPage);
+ if( (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK && pData ){
+ unsigned char *aPage = sqlite3PagerGetData(pDbPage);
+ memcpy(aPage, pData, szPage);
+ pTab->pgnoTrunc = 0;
}
+ }else{
+ pTab->pgnoTrunc = 0;
}
sqlite3PagerUnref(pDbPage);
return rc;
update_fail:
+ pTab->pgnoTrunc = 0;
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 ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0);
+ pTab->pgnoTrunc = 0;
+ return SQLITE_OK;
+}
+
+/* Invoke sqlite3PagerTruncate() as necessary, just prior to COMMIT
+*/
+static int dbpageSync(sqlite3_vtab *pVtab){
+ DbpageTable *pTab = (DbpageTable *)pVtab;
+ if( pTab->pgnoTrunc>0 ){
+ Btree *pBt = pTab->db->aDb[pTab->iDbTrunc].pBt;
+ Pager *pPager = sqlite3BtreePager(pBt);
+ sqlite3BtreeEnter(pBt);
+ if( pTab->pgnoTrunc<sqlite3BtreeLastPage(pBt) ){
+ sqlite3PagerTruncateImage(pPager, pTab->pgnoTrunc);
+ }
+ sqlite3BtreeLeave(pBt);
}
+ pTab->pgnoTrunc = 0;
return SQLITE_OK;
}
+/* Cancel any pending truncate.
+*/
+static int dbpageRollbackTo(sqlite3_vtab *pVtab, int notUsed1){
+ DbpageTable *pTab = (DbpageTable *)pVtab;
+ pTab->pgnoTrunc = 0;
+ (void)notUsed1;
+ 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 */
+ 2, /* iVersion */
dbpageConnect, /* xCreate */
dbpageConnect, /* xConnect */
dbpageBestIndex, /* xBestIndex */
@@ -224864,14 +228073,14 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
dbpageRowid, /* xRowid - read data */
dbpageUpdate, /* xUpdate */
dbpageBegin, /* xBegin */
- 0, /* xSync */
+ dbpageSync, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0, /* xRollbackTo */
+ dbpageRollbackTo, /* xRollbackTo */
0, /* xShadowName */
0 /* xIntegrity */
};
@@ -224959,6 +228168,10 @@ struct SessionBuffer {
** 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()).
+**
+** bNoDiscard:
+** If true, then the only time data is discarded is as a result of explicit
+** sessionDiscardData() calls. Not within every sessionInputBuffer() call.
*/
struct SessionInput {
int bNoDiscard; /* If true, do not discard in InputBuffer() */
@@ -225020,11 +228233,13 @@ struct sqlite3_changeset_iter {
struct SessionTable {
SessionTable *pNext;
char *zName; /* Local name of table */
- int nCol; /* Number of columns in table zName */
+ int nCol; /* Number of non-hidden columns */
+ int nTotalCol; /* Number of columns including hidden */
int bStat1; /* True if this is sqlite_stat1 */
int bRowid; /* True if this table uses rowid for PK */
const char **azCol; /* Column names */
const char **azDflt; /* Default value expressions */
+ int *aiIdx; /* Index to pass to xNew/xOld */
u8 *abPK; /* Array of primary key flags */
int nEntry; /* Total number of entries in hash table */
int nChange; /* Size of apChange[] array */
@@ -225427,22 +228642,22 @@ static int sessionPreupdateHash(
unsigned int h = 0; /* Hash value to return */
int i; /* Used to iterate through columns */
+ assert( pTab->nTotalCol==pSession->hook.xCount(pSession->hook.pCtx) );
if( pTab->bRowid ){
- assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) );
h = sessionHashAppendI64(h, iRowid);
}else{
assert( *pbNullPK==0 );
- assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
for(i=0; i<pTab->nCol; i++){
if( pTab->abPK[i] ){
int rc;
int eType;
sqlite3_value *pVal;
+ int iIdx = pTab->aiIdx[i];
if( bNew ){
- rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
+ rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal);
}else{
- rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal);
}
if( rc!=SQLITE_OK ) return rc;
@@ -225779,6 +228994,7 @@ static int sessionPreupdateEqual(
sqlite3_value *pVal; /* Value returned by preupdate_new/old */
int rc; /* Error code from preupdate_new/old */
int eType = *a++; /* Type of value from change record */
+ int iIdx = pTab->aiIdx[iCol];
/* The following calls to preupdate_new() and preupdate_old() can not
** fail. This is because they cache their return values, and by the
@@ -225787,10 +229003,10 @@ static int sessionPreupdateEqual(
** this (that the method has already been called). */
if( op==SQLITE_INSERT ){
/* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */
- rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
+ rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal);
}else{
/* assert( db->pPreUpdate->pUnpacked ); */
- rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal);
}
assert( rc==SQLITE_OK );
(void)rc; /* Suppress warning about unused variable */
@@ -225915,9 +229131,11 @@ static int sessionTableInfo(
const char *zDb, /* Name of attached database (e.g. "main") */
const char *zThis, /* Table name */
int *pnCol, /* OUT: number of columns */
+ int *pnTotalCol, /* OUT: number of hidden columns */
const char **pzTab, /* OUT: Copy of zThis */
const char ***pazCol, /* OUT: Array of column names for table */
const char ***pazDflt, /* OUT: Array of default value expressions */
+ int **paiIdx, /* OUT: Array of xNew/xOld indexes */
u8 **pabPK, /* OUT: Array of booleans - true for PK col */
int *pbRowid /* OUT: True if only PK is a rowid */
){
@@ -225932,6 +229150,7 @@ static int sessionTableInfo(
char **azCol = 0;
char **azDflt = 0;
u8 *abPK = 0;
+ int *aiIdx = 0;
int bRowid = 0; /* Set to true to use rowid as PK */
assert( pazCol && pabPK );
@@ -225939,6 +229158,8 @@ static int sessionTableInfo(
*pazCol = 0;
*pabPK = 0;
*pnCol = 0;
+ if( pnTotalCol ) *pnTotalCol = 0;
+ if( paiIdx ) *paiIdx = 0;
if( pzTab ) *pzTab = 0;
if( pazDflt ) *pazDflt = 0;
@@ -225948,9 +229169,9 @@ static int sessionTableInfo(
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"
+ "SELECT 0, 'tbl', '', 0, '', 1, 0 UNION ALL "
+ "SELECT 1, 'idx', '', 0, '', 2, 0 UNION ALL "
+ "SELECT 2, 'stat', '', 0, '', 0, 0"
);
}else if( rc==SQLITE_ERROR ){
zPragma = sqlite3_mprintf("");
@@ -225958,7 +229179,7 @@ static int sessionTableInfo(
return rc;
}
}else{
- zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
+ zPragma = sqlite3_mprintf("PRAGMA '%q'.table_xinfo('%q')", zDb, zThis);
}
if( !zPragma ){
return SQLITE_NOMEM;
@@ -225975,7 +229196,9 @@ static int sessionTableInfo(
while( SQLITE_ROW==sqlite3_step(pStmt) ){
nByte += sqlite3_column_bytes(pStmt, 1); /* name */
nByte += sqlite3_column_bytes(pStmt, 4); /* dflt_value */
- nDbCol++;
+ if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */
+ nDbCol++;
+ }
if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */
}
if( nDbCol==0 ) bRowid = 0;
@@ -225984,7 +229207,7 @@ static int sessionTableInfo(
rc = sqlite3_reset(pStmt);
if( rc==SQLITE_OK ){
- nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1);
+ nByte += nDbCol * (sizeof(const char *)*2 +sizeof(int)+sizeof(u8) + 1 + 1);
pAlloc = sessionMalloc64(pSession, nByte);
if( pAlloc==0 ){
rc = SQLITE_NOMEM;
@@ -225995,8 +229218,8 @@ static int sessionTableInfo(
if( rc==SQLITE_OK ){
azCol = (char **)pAlloc;
azDflt = (char**)&azCol[nDbCol];
- pAlloc = (u8 *)&azDflt[nDbCol];
- abPK = (u8 *)pAlloc;
+ aiIdx = (int*)&azDflt[nDbCol];
+ abPK = (u8 *)&aiIdx[nDbCol];
pAlloc = &abPK[nDbCol];
if( pzTab ){
memcpy(pAlloc, zThis, nThis+1);
@@ -226011,27 +229234,32 @@ static int sessionTableInfo(
azCol[i] = (char*)pAlloc;
pAlloc += nName+1;
abPK[i] = 1;
+ aiIdx[i] = -1;
i++;
}
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- int nName = sqlite3_column_bytes(pStmt, 1);
- int nDflt = sqlite3_column_bytes(pStmt, 4);
- const unsigned char *zName = sqlite3_column_text(pStmt, 1);
- const unsigned char *zDflt = sqlite3_column_text(pStmt, 4);
-
- if( zName==0 ) break;
- memcpy(pAlloc, zName, nName+1);
- azCol[i] = (char *)pAlloc;
- pAlloc += nName+1;
- if( zDflt ){
- memcpy(pAlloc, zDflt, nDflt+1);
- azDflt[i] = (char *)pAlloc;
- pAlloc += nDflt+1;
- }else{
- azDflt[i] = 0;
+ if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */
+ int nName = sqlite3_column_bytes(pStmt, 1);
+ int nDflt = sqlite3_column_bytes(pStmt, 4);
+ const unsigned char *zName = sqlite3_column_text(pStmt, 1);
+ const unsigned char *zDflt = sqlite3_column_text(pStmt, 4);
+
+ if( zName==0 ) break;
+ memcpy(pAlloc, zName, nName+1);
+ azCol[i] = (char *)pAlloc;
+ pAlloc += nName+1;
+ if( zDflt ){
+ memcpy(pAlloc, zDflt, nDflt+1);
+ azDflt[i] = (char *)pAlloc;
+ pAlloc += nDflt+1;
+ }else{
+ azDflt[i] = 0;
+ }
+ abPK[i] = sqlite3_column_int(pStmt, 5);
+ aiIdx[i] = sqlite3_column_int(pStmt, 0);
+ i++;
}
- abPK[i] = sqlite3_column_int(pStmt, 5);
- i++;
+ if( pnTotalCol ) (*pnTotalCol)++;
}
rc = sqlite3_reset(pStmt);
}
@@ -226044,6 +229272,7 @@ static int sessionTableInfo(
if( pazDflt ) *pazDflt = (const char**)azDflt;
*pabPK = abPK;
*pnCol = nDbCol;
+ if( paiIdx ) *paiIdx = aiIdx;
}else{
sessionFree(pSession, azCol);
}
@@ -226055,7 +229284,7 @@ static int sessionTableInfo(
/*
** This function is called to initialize the SessionTable.nCol, azCol[]
** abPK[] and azDflt[] members of SessionTable object pTab. If these
-** fields are already initilialized, this function is a no-op.
+** fields are already initialized, this function is a no-op.
**
** 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
@@ -226074,8 +229303,11 @@ static int sessionInitTable(
if( pTab->nCol==0 ){
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
+ sqlite3_free(pTab->azCol);
+ pTab->abPK = 0;
rc = sessionTableInfo(pSession, db, zDb,
- pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK,
+ pTab->zName, &pTab->nCol, &pTab->nTotalCol, 0, &pTab->azCol,
+ &pTab->azDflt, &pTab->aiIdx, &abPK,
((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0)
);
if( rc==SQLITE_OK ){
@@ -226110,15 +229342,17 @@ static int sessionInitTable(
*/
static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){
int nCol = 0;
+ int nTotalCol = 0;
const char **azCol = 0;
const char **azDflt = 0;
+ int *aiIdx = 0;
u8 *abPK = 0;
int bRowid = 0;
assert( pSession->rc==SQLITE_OK );
pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
- pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK,
+ pTab->zName, &nCol, &nTotalCol, 0, &azCol, &azDflt, &aiIdx, &abPK,
(pSession->bImplicitPK ? &bRowid : 0)
);
if( pSession->rc==SQLITE_OK ){
@@ -226141,8 +229375,10 @@ static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){
const char **a = pTab->azCol;
pTab->azCol = azCol;
pTab->nCol = nCol;
+ pTab->nTotalCol = nTotalCol;
pTab->azDflt = azDflt;
pTab->abPK = abPK;
+ pTab->aiIdx = aiIdx;
azCol = a;
}
if( pSession->bEnableSize ){
@@ -226460,7 +229696,7 @@ static int sessionUpdateMaxSize(
int ii;
for(ii=0; ii<pTab->nCol; ii++){
sqlite3_value *p = 0;
- pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, pTab->aiIdx[ii], &p);
sessionSerializeValue(0, p, &nNew);
}
}
@@ -226480,8 +229716,9 @@ static int sessionUpdateMaxSize(
int bChanged = 1;
int nOld = 0;
int eType;
+ int iIdx = pTab->aiIdx[ii];
sqlite3_value *p = 0;
- pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p);
if( p==0 ){
return SQLITE_NOMEM;
}
@@ -226578,11 +229815,11 @@ static void sessionPreupdateOneChange(
/* Check the number of columns in this xPreUpdate call matches the
** number of columns in the table. */
nExpect = pSession->hook.xCount(pSession->hook.pCtx);
- if( (pTab->nCol-pTab->bRowid)<nExpect ){
+ if( pTab->nTotalCol<nExpect ){
if( sessionReinitTable(pSession, pTab) ) return;
if( sessionUpdateChanges(pSession, pTab) ) return;
}
- if( (pTab->nCol-pTab->bRowid)!=nExpect ){
+ if( pTab->nTotalCol!=nExpect ){
pSession->rc = SQLITE_SCHEMA;
return;
}
@@ -226639,19 +229876,23 @@ static void sessionPreupdateOneChange(
/* Figure out how large an allocation is required */
nByte = sizeof(SessionChange);
- for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
+ for(i=pTab->bRowid; i<pTab->nCol; i++){
+ int iIdx = pTab->aiIdx[i];
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
- TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
- assert( trc==SQLITE_OK );
+ /* This may fail if the column has a non-NULL default and was added
+ ** using ALTER TABLE ADD COLUMN after this record was created. */
+ rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p);
}else if( pTab->abPK[i] ){
- TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
+ TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx,iIdx,&p);
assert( trc==SQLITE_OK );
}
- /* This may fail if SQLite value p contains a utf-16 string that must
- ** be converted to utf-8 and an OOM error occurs while doing so. */
- rc = sessionSerializeValue(0, p, &nByte);
+ if( rc==SQLITE_OK ){
+ /* This may fail if SQLite value p contains a utf-16 string that must
+ ** be converted to utf-8 and an OOM error occurs while doing so. */
+ rc = sessionSerializeValue(0, p, &nByte);
+ }
if( rc!=SQLITE_OK ) goto error_out;
}
if( pTab->bRowid ){
@@ -226678,12 +229919,13 @@ static void sessionPreupdateOneChange(
sessionPutI64(&pC->aRecord[1], iRowid);
nByte = 9;
}
- for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
+ for(i=pTab->bRowid; i<pTab->nCol; i++){
sqlite3_value *p = 0;
+ int iIdx = pTab->aiIdx[i];
if( op!=SQLITE_INSERT ){
- pSession->hook.xOld(pSession->hook.pCtx, i, &p);
+ pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p);
}else if( pTab->abPK[i] ){
- pSession->hook.xNew(pSession->hook.pCtx, i, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p);
}
sessionSerializeValue(&pC->aRecord[nByte], p, &nByte);
}
@@ -227070,7 +230312,9 @@ SQLITE_API int sqlite3session_diff(
SessionTable *pTo; /* Table zTbl */
/* Locate and if necessary initialize the target table object */
+ pSession->bAutoAttach++;
rc = sessionFindTable(pSession, zTbl, &pTo);
+ pSession->bAutoAttach--;
if( pTo==0 ) goto diff_out;
if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){
rc = pSession->rc;
@@ -227081,16 +230325,43 @@ SQLITE_API int sqlite3session_diff(
if( rc==SQLITE_OK ){
int bHasPk = 0;
int bMismatch = 0;
- int nCol; /* Columns in zFrom.zTbl */
+ int nCol = 0; /* Columns in zFrom.zTbl */
int bRowid = 0;
- u8 *abPK;
+ u8 *abPK = 0;
const char **azCol = 0;
- rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK,
- pSession->bImplicitPK ? &bRowid : 0
- );
+ char *zDbExists = 0;
+
+ /* Check that database zFrom is attached. */
+ zDbExists = sqlite3_mprintf("SELECT * FROM %Q.sqlite_schema", zFrom);
+ if( zDbExists==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ sqlite3_stmt *pDbExists = 0;
+ rc = sqlite3_prepare_v2(db, zDbExists, -1, &pDbExists, 0);
+ if( rc==SQLITE_ERROR ){
+ rc = SQLITE_OK;
+ nCol = -1;
+ }
+ sqlite3_finalize(pDbExists);
+ sqlite3_free(zDbExists);
+ }
+
+ if( rc==SQLITE_OK && nCol==0 ){
+ rc = sessionTableInfo(0, db, zFrom, zTbl,
+ &nCol, 0, 0, &azCol, 0, 0, &abPK,
+ pSession->bImplicitPK ? &bRowid : 0
+ );
+ }
if( rc==SQLITE_OK ){
if( pTo->nCol!=nCol ){
- bMismatch = 1;
+ if( nCol<=0 ){
+ rc = SQLITE_SCHEMA;
+ if( pzErrMsg ){
+ *pzErrMsg = sqlite3_mprintf("no such table: %s.%s", zFrom, zTbl);
+ }
+ }else{
+ bMismatch = 1;
+ }
}else{
int i;
for(i=0; i<nCol; i++){
@@ -227409,9 +230680,11 @@ static void sessionAppendIdent(
char *zOut = (char *)&p->aBuf[p->nBuf];
const char *zIn = zStr;
*zOut++ = '"';
- while( *zIn ){
- if( *zIn=='"' ) *zOut++ = '"';
- *zOut++ = *(zIn++);
+ if( zIn!=0 ){
+ while( *zIn ){
+ if( *zIn=='"' ) *zOut++ = '"';
+ *zOut++ = *(zIn++);
+ }
}
*zOut++ = '"';
p->nBuf = (int)((u8 *)zOut - p->aBuf);
@@ -227662,10 +230935,10 @@ static int sessionSelectStmt(
int rc = SQLITE_OK;
char *zSql = 0;
const char *zSep = "";
- const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*";
int nSql = -1;
int i;
+ SessionBuffer cols = {0, 0, 0};
SessionBuffer nooptest = {0, 0, 0};
SessionBuffer pkfield = {0, 0, 0};
SessionBuffer pkvar = {0, 0, 0};
@@ -227678,9 +230951,16 @@ static int sessionSelectStmt(
sessionAppendStr(&pkvar,
"?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc
);
- zCols = "tbl, ?2, stat";
+ sessionAppendStr(&cols, "tbl, ?2, stat", &rc);
}else{
+ #if 0
+ if( bRowid ){
+ sessionAppendStr(&cols, SESSIONS_ROWID, &rc);
+ }
+ #endif
for(i=0; i<nCol; i++){
+ if( cols.nBuf ) sessionAppendStr(&cols, ", ", &rc);
+ sessionAppendIdent(&cols, azCol[i], &rc);
if( abPK[i] ){
sessionAppendStr(&pkfield, zSep, &rc);
sessionAppendStr(&pkvar, zSep, &rc);
@@ -227698,7 +230978,7 @@ static int sessionSelectStmt(
if( rc==SQLITE_OK ){
zSql = sqlite3_mprintf(
"SELECT %s%s FROM %Q.%Q WHERE (%s) IS (%s)",
- zCols, (bIgnoreNoop ? (char*)nooptest.aBuf : ""),
+ (char*)cols.aBuf, (bIgnoreNoop ? (char*)nooptest.aBuf : ""),
zDb, zTab, (char*)pkfield.aBuf, (char*)pkvar.aBuf
);
if( zSql==0 ) rc = SQLITE_NOMEM;
@@ -227741,6 +231021,7 @@ static int sessionSelectStmt(
sqlite3_free(nooptest.aBuf);
sqlite3_free(pkfield.aBuf);
sqlite3_free(pkvar.aBuf);
+ sqlite3_free(cols.aBuf);
return rc;
}
@@ -227856,7 +231137,7 @@ static int sessionGenerateChangeset(
){
sqlite3 *db = pSession->db; /* Source database handle */
SessionTable *pTab; /* Used to iterate through attached tables */
- SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */
+ SessionBuffer buf = {0,0,0}; /* Buffer in which to accumulate changeset */
int rc; /* Return code */
assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0) );
@@ -228209,14 +231490,15 @@ SQLITE_API int sqlite3changeset_start_v2_strm(
** object and the buffer is full, discard some data to free up space.
*/
static void sessionDiscardData(SessionInput *pIn){
- if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){
- int nMove = pIn->buf.nBuf - pIn->iNext;
+ if( pIn->xInput && pIn->iCurrent>=sessions_strm_chunk_size ){
+ int nMove = pIn->buf.nBuf - pIn->iCurrent;
assert( nMove>=0 );
if( nMove>0 ){
- memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove);
+ memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iCurrent], nMove);
}
- pIn->buf.nBuf -= pIn->iNext;
- pIn->iNext = 0;
+ pIn->buf.nBuf -= pIn->iCurrent;
+ pIn->iNext -= pIn->iCurrent;
+ pIn->iCurrent = 0;
pIn->nData = pIn->buf.nBuf;
}
}
@@ -228570,8 +231852,8 @@ static int sessionChangesetNextOne(
p->rc = sessionInputBuffer(&p->in, 2);
if( p->rc!=SQLITE_OK ) return p->rc;
- sessionDiscardData(&p->in);
p->in.iCurrent = p->in.iNext;
+ sessionDiscardData(&p->in);
/* If the iterator is already at the end of the changeset, return DONE. */
if( p->in.iNext>=p->in.nData ){
@@ -230009,15 +233291,21 @@ static int sessionChangesetApply(
int nTab = 0; /* Result of sqlite3Strlen30(zTab) */
SessionApplyCtx sApply; /* changeset_apply() context object */
int bPatchset;
+ u64 savedFlag = db->flags & SQLITE_FkNoAction;
assert( xConflict!=0 );
+ sqlite3_mutex_enter(sqlite3_db_mutex(db));
+ if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
+ db->flags |= ((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
+
pIter->in.bNoDiscard = 1;
memset(&sApply, 0, sizeof(sApply));
sApply.bRebase = (ppRebase && pnRebase);
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
- sqlite3_mutex_enter(sqlite3_db_mutex(db));
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
}
@@ -230075,7 +233363,8 @@ static int sessionChangesetApply(
sqlite3changeset_pk(pIter, &abPK, 0);
rc = sessionTableInfo(0, db, "main", zNew,
- &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid
+ &sApply.nCol, 0, &zTab, &sApply.azCol, 0, 0,
+ &sApply.abPK, &sApply.bRowid
);
if( rc!=SQLITE_OK ) break;
for(i=0; i<sApply.nCol; i++){
@@ -230155,12 +233444,17 @@ static int sessionChangesetApply(
}
}
}
- sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
+
+ {
+ int rc2 = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
if( rc==SQLITE_OK ){
rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
- }else{
+ }
+ if( rc!=SQLITE_OK ){
sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
}
@@ -230179,6 +233473,12 @@ static int sessionChangesetApply(
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
sqlite3_free((char*)sApply.constraints.aBuf);
sqlite3_free((char*)sApply.rebase.aBuf);
+
+ if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
+ assert( db->flags & SQLITE_FkNoAction );
+ db->flags &= ~((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
sqlite3_mutex_leave(sqlite3_db_mutex(db));
return rc;
}
@@ -230207,12 +233507,6 @@ SQLITE_API int sqlite3changeset_apply_v2(
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
- u64 savedFlag = db->flags & SQLITE_FkNoAction;
-
- if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
- db->flags |= ((u64)SQLITE_FkNoAction);
- db->aDb[0].pSchema->schema_cookie -= 32;
- }
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
@@ -230220,11 +233514,6 @@ SQLITE_API int sqlite3changeset_apply_v2(
);
}
- if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
- assert( db->flags & SQLITE_FkNoAction );
- db->flags &= ~((u64)SQLITE_FkNoAction);
- db->aDb[0].pSchema->schema_cookie -= 32;
- }
return rc;
}
@@ -230545,6 +233834,9 @@ static int sessionChangesetExtendRecord(
sessionAppendBlob(pOut, aRec, nRec, &rc);
if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
+ if( rc==SQLITE_OK && SQLITE_ROW!=sqlite3_step(pTab->pDfltStmt) ){
+ rc = sqlite3_errcode(pGrp->db);
+ }
}
for(ii=nCol; rc==SQLITE_OK && ii<pTab->nCol; ii++){
int eType = sqlite3_column_type(pTab->pDfltStmt, ii);
@@ -230561,6 +233853,7 @@ static int sessionChangesetExtendRecord(
}
if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
+ pOut->nBuf += 8;
}
break;
}
@@ -230700,6 +233993,8 @@ static int sessionOneChangeToHash(
u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2];
int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2;
+ assert( nRec>0 );
+
/* Ensure that only changesets, or only patchsets, but not a mixture
** of both, are being combined. It is an error to try to combine a
** changeset and a patchset. */
@@ -230777,6 +234072,7 @@ static int sessionChangesetToHash(
int nRec;
int rc = SQLITE_OK;
+ pIter->in.bNoDiscard = 1;
while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){
rc = sessionOneChangeToHash(pGrp, pIter, bRebase);
if( rc!=SQLITE_OK ) break;
@@ -230916,14 +234212,19 @@ SQLITE_API int sqlite3changegroup_add_change(
sqlite3_changegroup *pGrp,
sqlite3_changeset_iter *pIter
){
+ int rc = SQLITE_OK;
+
if( pIter->in.iCurrent==pIter->in.iNext
|| pIter->rc!=SQLITE_OK
|| pIter->bInvert
){
/* Iterator does not point to any valid entry or is an INVERT iterator. */
- return SQLITE_ERROR;
+ rc = SQLITE_ERROR;
+ }else{
+ pIter->in.bNoDiscard = 1;
+ rc = sessionOneChangeToHash(pGrp, pIter, 0);
}
- return sessionOneChangeToHash(pGrp, pIter, 0);
+ return rc;
}
/*
@@ -231408,7 +234709,27 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){
/************** End of sqlite3session.c **************************************/
/************** Begin file fts5.c ********************************************/
-
+/*
+** This, the "fts5.c" source file, is a composite file that is itself
+** assembled from the following files:
+**
+** fts5.h
+** fts5Int.h
+** fts5parse.h <--- Generated from fts5parse.y by Lemon
+** fts5parse.c <--- Generated from fts5parse.y by Lemon
+** fts5_aux.c
+** fts5_buffer.c
+** fts5_config.c
+** fts5_expr.c
+** fts5_hash.c
+** fts5_index.c
+** fts5_main.c
+** fts5_storage.c
+** fts5_tokenize.c
+** fts5_unicode2.c
+** fts5_varint.c
+** fts5_vocab.c
+*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
@@ -231418,6 +234739,12 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){
# undef NDEBUG
#endif
+#ifdef HAVE_STDINT_H
+/* #include <stdint.h> */
+#endif
+#ifdef HAVE_INTTYPES_H
+/* #include <inttypes.h> */
+#endif
/*
** 2014 May 31
**
@@ -231658,6 +234985,10 @@ struct Fts5PhraseIter {
** (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).
**
+** In all cases, matches are visited in (column ASC, offset ASC) order.
+** i.e. all those in column 0, sorted by offset, followed by those in
+** column 1, etc.
+**
** xPhraseNext()
** See xPhraseFirst above.
**
@@ -231714,19 +235045,57 @@ struct Fts5PhraseIter {
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
** output variable (*ppToken) is set to point to a buffer containing the
** matching document token, and (*pnToken) to the size of that buffer in
-** bytes. This API is not available if the specified token matches a
-** prefix query term. In that case both output variables are always set
-** to 0.
+** bytes.
**
** The output text is not a copy of the document text that was tokenized.
** It is the output of the tokenizer module. For tokendata=1 tables, this
** includes any embedded 0x00 and trailing data.
**
+** This API may be slow in some cases if the token identified by parameters
+** iIdx and iToken matched a prefix token in the query. In most cases, the
+** first call to this API for each prefix token in the query is forced
+** to scan the portion of the full-text index that matches the prefix
+** token to collect the extra data required by this API. If the prefix
+** token matches a large number of token instances in the document set,
+** this may be a performance problem.
+**
+** If the user knows in advance that a query may use this API for a
+** prefix token, FTS5 may be configured to collect all required data as part
+** of the initial querying of the full-text index, avoiding the second scan
+** entirely. This also causes prefix queries that do not use this API to
+** run more slowly and use more memory. FTS5 may be configured in this way
+** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
+** option, or on a per-query basis using the
+** [fts5_insttoken | fts5_insttoken()] user function.
+**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
+**
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the locale associated
+** with column iCol of the current row. Usually, there is no associated
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
+** to NULL and 0, respectively. However, if the fts5_locale() function
+** was used to associate a locale with the value when it was inserted
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
+** is set to the size in bytes of the buffer, not including the
+** nul-terminator.
+**
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
+** SQLite error code is returned. The final value of the output parameters
+** is undefined in this case.
+**
+** xTokenize_v2:
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
+** API is the same as the xTokenize() API, except that it allows a tokenizer
+** locale to be specified.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
+ int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*);
@@ -231768,6 +235137,15 @@ struct Fts5ExtensionApi {
const char **ppToken, int *pnToken
);
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
+
+ /* Below this point are iVersion>=4 only */
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
+ int (*xTokenize_v2)(Fts5Context*,
+ const char *pText, int nText, /* Text to tokenize */
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
+ void *pCtx, /* Context passed to xToken() */
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
+ );
};
/*
@@ -231788,7 +235166,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
+** pointer provided by the application when the fts5_tokenizer_v2 object
** 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
@@ -231812,7 +235190,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
-** The second argument indicates the reason that FTS5 is requesting
+** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
@@ -231836,6 +235214,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database.
** </ul>
**
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
+** nLocale - are a pointer to a buffer containing the locale to use for
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
+** which case nLocale is always 0) to indicate that the tokenizer should
+** use its default locale.
+**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
@@ -231859,6 +235244,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
+** then the xTokenize() method has two additional arguments - pLocale
+** and nLocale. These specify the locale that the tokenizer should use
+** for the current request. If pLocale and nLocale are both 0, then the
+** tokenizer should use its default locale. Otherwise, pLocale points to
+** an nLocale byte buffer containing the name of the locale to use as utf-8
+** text. pLocale is not nul-terminated.
+**
+** FTS5_TOKENIZER
+**
+** There is also an fts5_tokenizer object. This is an older, deprecated,
+** version of fts5_tokenizer_v2. It is similar except that:
+**
+** <ul>
+** <li> There is no "iVersion" field, and
+** <li> The xTokenize() method does not take a locale argument.
+** </ul>
+**
+** Legacy fts5_tokenizer tokenizers must be registered using the
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
+**
+** Tokenizer implementations registered using either API may be retrieved
+** using both xFindTokenizer() and xFindTokenizer_v2().
+**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -231967,6 +235376,33 @@ struct Fts5ExtensionApi {
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
+struct fts5_tokenizer_v2 {
+ int iVersion; /* Currently always 2 */
+
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+ void (*xDelete)(Fts5Tokenizer*);
+ int (*xTokenize)(Fts5Tokenizer*,
+ void *pCtx,
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Pointer to buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStart, /* Byte offset of token within input text */
+ int iEnd /* Byte offset of end of token within input text */
+ )
+ );
+};
+
+/*
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
+** implementations. The following type is included for legacy applications
+** that still use it.
+*/
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -231986,6 +235422,7 @@ struct fts5_tokenizer {
);
};
+
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
@@ -232005,7 +235442,7 @@ struct fts5_tokenizer {
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
@@ -232032,6 +235469,25 @@ struct fts5_api {
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
+
+ /* APIs below this point are only available if iVersion>=3 */
+
+ /* Create a new tokenizer */
+ int (*xCreateTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void *pUserData,
+ fts5_tokenizer_v2 *pTokenizer,
+ void (*xDestroy)(void*)
+ );
+
+ /* Find an existing tokenizer */
+ int (*xFindTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer
+ );
};
/*
@@ -232066,6 +235522,7 @@ SQLITE_EXTENSION_INIT1
/* #include <string.h> */
/* #include <assert.h> */
+/* #include <stddef.h> */
#ifndef SQLITE_AMALGAMATION
@@ -232105,6 +235562,34 @@ typedef sqlite3_uint64 u64;
# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
+/* The uptr type is an unsigned integer large enough to hold a pointer
+*/
+#if defined(HAVE_STDINT_H)
+ typedef uintptr_t uptr;
+#elif SQLITE_PTRSIZE==4
+ typedef u32 uptr;
+#else
+ typedef u64 uptr;
+#endif
+
+#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0)
+#else
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
+#endif
+
+/*
+** Macros needed to provide flexible arrays in a portable way
+*/
+#ifndef offsetof
+# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+#endif
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define FLEXARRAY
+#else
+# define FLEXARRAY 1
+#endif
+
#endif
/* Truncate very long tokens to this many bytes. Hard limit is
@@ -232177,10 +235662,11 @@ typedef struct Fts5Colset Fts5Colset;
*/
struct Fts5Colset {
int nCol;
- int aiCol[1];
+ int aiCol[FLEXARRAY];
};
-
+/* Size (int bytes) of a complete Fts5Colset object with N columns. */
+#define SZ_FTS5COLSET(N) (sizeof(i64)*((N+2)/2))
/**************************************************************************
** Interface to code in fts5_config.c. fts5_config.c contains contains code
@@ -232188,6 +235674,18 @@ struct Fts5Colset {
*/
typedef struct Fts5Config Fts5Config;
+typedef struct Fts5TokenizerConfig Fts5TokenizerConfig;
+
+struct Fts5TokenizerConfig {
+ Fts5Tokenizer *pTok;
+ fts5_tokenizer_v2 *pApi2;
+ fts5_tokenizer *pApi1;
+ const char **azArg;
+ int nArg;
+ int ePattern; /* FTS_PATTERN_XXX constant */
+ const char *pLocale; /* Current locale to use */
+ int nLocale; /* Size of pLocale in bytes */
+};
/*
** An instance of the following structure encodes all information that can
@@ -232227,9 +235725,12 @@ typedef struct Fts5Config Fts5Config;
**
** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);
**
+** bLocale:
+** Set to true if locale=1 was specified when the table was created.
*/
struct Fts5Config {
sqlite3 *db; /* Database handle */
+ Fts5Global *pGlobal; /* Global fts5 object for handle db */
char *zDb; /* Database holding FTS index (e.g. "main") */
char *zName; /* Name of FTS index */
int nCol; /* Number of columns */
@@ -232239,16 +235740,17 @@ struct Fts5Config {
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
int eContent; /* An FTS5_CONTENT value */
int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
+ int bContentlessUnindexed; /* "contentless_unindexed=" option (dflt=0) */
char *zContent; /* content table */
char *zContentRowid; /* "content_rowid=" option value */
int bColumnsize; /* "columnsize=" option value (dflt==1) */
int bTokendata; /* "tokendata=" option value (dflt==0) */
+ int bLocale; /* "locale=" option value (dflt==0) */
int eDetail; /* FTS5_DETAIL_XXX value */
char *zContentExprlist;
- Fts5Tokenizer *pTok;
- fts5_tokenizer *pTokApi;
+ Fts5TokenizerConfig t;
int bLock; /* True when table is preparing statement */
- int ePattern; /* FTS_PATTERN_XXX constant */
+
/* Values loaded from the %_config table */
int iVersion; /* fts5 file format 'version' */
@@ -232261,7 +235763,8 @@ struct Fts5Config {
char *zRank; /* Name of rank function */
char *zRankArgs; /* Arguments to rank function */
int bSecureDelete; /* 'secure-delete' */
- int nDeleteMerge; /* 'deletemerge' */
+ int nDeleteMerge; /* 'deletemerge' */
+ int bPrefixInsttoken; /* 'prefix-insttoken' */
/* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
char **pzErrmsg;
@@ -232277,9 +235780,10 @@ struct Fts5Config {
#define FTS5_CURRENT_VERSION 4
#define FTS5_CURRENT_VERSION_SECUREDELETE 5
-#define FTS5_CONTENT_NORMAL 0
-#define FTS5_CONTENT_NONE 1
-#define FTS5_CONTENT_EXTERNAL 2
+#define FTS5_CONTENT_NORMAL 0
+#define FTS5_CONTENT_NONE 1
+#define FTS5_CONTENT_EXTERNAL 2
+#define FTS5_CONTENT_UNINDEXED 3
#define FTS5_DETAIL_FULL 0
#define FTS5_DETAIL_NONE 1
@@ -232314,6 +235818,8 @@ static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, i
static int sqlite3Fts5ConfigParseRank(const char*, char**, char**);
+static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...);
+
/*
** End of interface to code in fts5_config.c.
**************************************************************************/
@@ -232358,7 +235864,7 @@ static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
static void sqlite3Fts5Put32(u8*, int);
static int sqlite3Fts5Get32(const u8*);
-#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
+#define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF)
#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
typedef struct Fts5PoslistReader Fts5PoslistReader;
@@ -232515,7 +236021,14 @@ static int sqlite3Fts5StructureTest(Fts5Index*, void*);
/*
** Used by xInstToken():
*/
-static int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*);
+static int sqlite3Fts5IterToken(
+ Fts5IndexIter *pIndexIter,
+ const char *pToken, int nToken,
+ i64 iRowid,
+ int iCol,
+ int iOff,
+ const char **ppOut, int *pnOut
+);
/*
** Insert or remove data to or from the index. Each time a document is
@@ -232643,18 +236156,20 @@ struct Fts5Table {
Fts5Index *pIndex; /* Full-text index */
};
-static int sqlite3Fts5GetTokenizer(
- Fts5Global*,
- const char **azArg,
- int nArg,
- Fts5Config*,
- char **pzErr
-);
+static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig);
static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
static int sqlite3Fts5FlushToDisk(Fts5Table*);
+static void sqlite3Fts5ClearLocale(Fts5Config *pConfig);
+static void sqlite3Fts5SetLocale(Fts5Config *pConfig, const char *pLoc, int nLoc);
+
+static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal);
+static int sqlite3Fts5DecodeLocaleValue(sqlite3_value *pVal,
+ const char **ppText, int *pnText, const char **ppLoc, int *pnLoc
+);
+
/*
** End of interface to code in fts5.c.
**************************************************************************/
@@ -232734,8 +236249,8 @@ static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
static int sqlite3Fts5DropAll(Fts5Config*);
static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
-static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
+static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int);
+static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, int, sqlite3_value**, i64*);
static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
@@ -232760,6 +236275,9 @@ static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
static int sqlite3Fts5StorageReset(Fts5Storage *p);
+static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*);
+static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel);
+
/*
** End of interface to code in fts5_storage.c.
**************************************************************************/
@@ -232912,6 +236430,7 @@ static int sqlite3Fts5TokenizerPattern(
int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
Fts5Tokenizer *pTok
);
+static int sqlite3Fts5TokenizerPreload(Fts5TokenizerConfig*);
/*
** End of interface to code in fts5_tokenizer.c.
**************************************************************************/
@@ -232976,7 +236495,7 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*);
**
** The "lemon" program processes an LALR(1) input grammar file, then uses
** this template to construct a parser. The "lemon" program inserts text
-** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
+** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the
** interstitial "-" characters) contained in this template is changed into
** the value of the %name directive from the grammar. Otherwise, the content
** of this template is copied straight through into the generate parser
@@ -234689,6 +238208,7 @@ static int fts5HighlightCb(
return rc;
}
+
/*
** Implementation of highlight() function.
*/
@@ -234719,12 +238239,19 @@ static void fts5HighlightFunction(
sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
rc = SQLITE_OK;
}else if( ctx.zIn ){
+ const char *pLoc = 0; /* Locale of column iCol */
+ int nLoc = 0; /* Size of pLoc in bytes */
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
}
if( rc==SQLITE_OK ){
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
+ rc = pApi->xColumnLocale(pFts, iCol, &pLoc, &nLoc);
+ }
+ if( rc==SQLITE_OK ){
+ rc = pApi->xTokenize_v2(
+ pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx, fts5HighlightCb
+ );
}
if( ctx.bOpen ){
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
@@ -234921,6 +238448,8 @@ static void fts5SnippetFunction(
memset(&sFinder, 0, sizeof(Fts5SFinder));
for(i=0; i<nCol; i++){
if( iCol<0 || iCol==i ){
+ const char *pLoc = 0; /* Locale of column iCol */
+ int nLoc = 0; /* Size of pLoc in bytes */
int nDoc;
int nDocsize;
int ii;
@@ -234928,8 +238457,10 @@ static void fts5SnippetFunction(
sFinder.nFirst = 0;
rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
if( rc!=SQLITE_OK ) break;
- rc = pApi->xTokenize(pFts,
- sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
+ rc = pApi->xColumnLocale(pFts, i, &pLoc, &nLoc);
+ if( rc!=SQLITE_OK ) break;
+ rc = pApi->xTokenize_v2(pFts,
+ sFinder.zDoc, nDoc, pLoc, nLoc, (void*)&sFinder, fts5SentenceFinderCb
);
if( rc!=SQLITE_OK ) break;
rc = pApi->xColumnSize(pFts, i, &nDocsize);
@@ -234987,6 +238518,9 @@ static void fts5SnippetFunction(
rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
}
if( ctx.zIn ){
+ const char *pLoc = 0; /* Locale of column iBestCol */
+ int nLoc = 0; /* Bytes in pLoc */
+
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
}
@@ -235005,7 +238539,12 @@ static void fts5SnippetFunction(
}
if( rc==SQLITE_OK ){
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
+ rc = pApi->xColumnLocale(pFts, iBestCol, &pLoc, &nLoc);
+ }
+ if( rc==SQLITE_OK ){
+ rc = pApi->xTokenize_v2(
+ pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx,fts5HighlightCb
+ );
}
if( ctx.bOpen ){
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
@@ -235110,7 +238649,7 @@ static int fts5Bm25GetData(
** under consideration.
**
** The problem with this is that if (N < 2*nHit), the IDF is
- ** negative. Which is undesirable. So the mimimum allowable IDF is
+ ** negative. Which is undesirable. So the minimum allowable IDF is
** (1e-6) - roughly the same as a term that appears in just over
** half of set of 5,000,000 documents. */
double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) );
@@ -235189,6 +238728,53 @@ static void fts5Bm25Function(
}
}
+/*
+** Implementation of fts5_get_locale() function.
+*/
+static void fts5GetLocaleFunction(
+ const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
+ Fts5Context *pFts, /* First arg to pass to pApi functions */
+ sqlite3_context *pCtx, /* Context for returning result/error */
+ int nVal, /* Number of values in apVal[] array */
+ sqlite3_value **apVal /* Array of trailing arguments */
+){
+ int iCol = 0;
+ int eType = 0;
+ int rc = SQLITE_OK;
+ const char *zLocale = 0;
+ int nLocale = 0;
+
+ /* xColumnLocale() must be available */
+ assert( pApi->iVersion>=4 );
+
+ if( nVal!=1 ){
+ const char *z = "wrong number of arguments to function fts5_get_locale()";
+ sqlite3_result_error(pCtx, z, -1);
+ return;
+ }
+
+ eType = sqlite3_value_numeric_type(apVal[0]);
+ if( eType!=SQLITE_INTEGER ){
+ const char *z = "non-integer argument passed to function fts5_get_locale()";
+ sqlite3_result_error(pCtx, z, -1);
+ return;
+ }
+
+ iCol = sqlite3_value_int(apVal[0]);
+ if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){
+ sqlite3_result_error_code(pCtx, SQLITE_RANGE);
+ return;
+ }
+
+ rc = pApi->xColumnLocale(pFts, iCol, &zLocale, &nLocale);
+ if( rc!=SQLITE_OK ){
+ sqlite3_result_error_code(pCtx, rc);
+ return;
+ }
+
+ sqlite3_result_text(pCtx, zLocale, nLocale, SQLITE_TRANSIENT);
+}
+
static int sqlite3Fts5AuxInit(fts5_api *pApi){
struct Builtin {
const char *zFunc; /* Function name (nul-terminated) */
@@ -235196,9 +238782,10 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){
fts5_extension_function xFunc;/* Callback function */
void (*xDestroy)(void*); /* Destructor function */
} aBuiltin [] = {
- { "snippet", 0, fts5SnippetFunction, 0 },
- { "highlight", 0, fts5HighlightFunction, 0 },
- { "bm25", 0, fts5Bm25Function, 0 },
+ { "snippet", 0, fts5SnippetFunction, 0 },
+ { "highlight", 0, fts5HighlightFunction, 0 },
+ { "bm25", 0, fts5Bm25Function, 0 },
+ { "fts5_get_locale", 0, fts5GetLocaleFunction, 0 },
};
int rc = SQLITE_OK; /* Return code */
int i; /* To iterate through builtin functions */
@@ -235525,7 +239112,7 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
** * The 52 upper and lower case ASCII characters, and
** * The 10 integer ASCII characters.
** * The underscore character "_" (0x5F).
-** * The unicode "subsitute" character (0x1A).
+** * The unicode "substitute" character (0x1A).
*/
static int sqlite3Fts5IsBareword(char t){
u8 aBareword[128] = {
@@ -235863,7 +239450,6 @@ static int fts5ConfigSetEnum(
** eventually free any such error message using sqlite3_free().
*/
static int fts5ConfigParseSpecial(
- Fts5Global *pGlobal,
Fts5Config *pConfig, /* Configuration object to update */
const char *zCmd, /* Special command to parse */
const char *zArg, /* Argument to parse */
@@ -235871,6 +239457,7 @@ static int fts5ConfigParseSpecial(
){
int rc = SQLITE_OK;
int nCmd = (int)strlen(zCmd);
+
if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
const char *p;
@@ -235927,12 +239514,11 @@ static int fts5ConfigParseSpecial(
if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
const char *p = (const char*)zArg;
sqlite3_int64 nArg = strlen(zArg) + 1;
- char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
- char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
- char *pSpace = pDel;
+ char **azArg = sqlite3Fts5MallocZero(&rc, (sizeof(char*) + 2) * nArg);
- if( azArg && pSpace ){
- if( pConfig->pTok ){
+ if( azArg ){
+ char *pSpace = (char*)&azArg[nArg];
+ if( pConfig->t.azArg ){
*pzErr = sqlite3_mprintf("multiple tokenize=... directives");
rc = SQLITE_ERROR;
}else{
@@ -235955,16 +239541,14 @@ static int fts5ConfigParseSpecial(
*pzErr = sqlite3_mprintf("parse error in tokenize directive");
rc = SQLITE_ERROR;
}else{
- rc = sqlite3Fts5GetTokenizer(pGlobal,
- (const char**)azArg, (int)nArg, pConfig,
- pzErr
- );
+ pConfig->t.azArg = (const char**)azArg;
+ pConfig->t.nArg = nArg;
+ azArg = 0;
}
}
}
-
sqlite3_free(azArg);
- sqlite3_free(pDel);
+
return rc;
}
@@ -235993,6 +239577,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlite3_strnicmp("contentless_unindexed", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlite3_mprintf("malformed contentless_delete=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bContentlessUnindexed = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
if( pConfig->zContentRowid ){
*pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
@@ -236013,6 +239607,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlite3_strnicmp("locale", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlite3_mprintf("malformed locale=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bLocale = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
const Fts5Enum aDetail[] = {
{ "none", FTS5_DETAIL_NONE },
@@ -236042,16 +239646,6 @@ static int fts5ConfigParseSpecial(
}
/*
-** 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.
-*/
-static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){
- assert( pConfig->pTok==0 && pConfig->pTokApi==0 );
- return sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0);
-}
-
-/*
** Gobble up the first bareword or quoted word from the input buffer zIn.
** Return a pointer to the character immediately following the last in
** the gobbled word if successful, or a NULL pointer otherwise (failed
@@ -236110,7 +239704,8 @@ static int fts5ConfigParseColumn(
Fts5Config *p,
char *zCol,
char *zArg,
- char **pzErr
+ char **pzErr,
+ int *pbUnindexed
){
int rc = SQLITE_OK;
if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
@@ -236121,6 +239716,7 @@ static int fts5ConfigParseColumn(
}else if( zArg ){
if( 0==sqlite3_stricmp(zArg, "unindexed") ){
p->abUnindexed[p->nCol] = 1;
+ *pbUnindexed = 1;
}else{
*pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg);
rc = SQLITE_ERROR;
@@ -236141,11 +239737,26 @@ static int fts5ConfigMakeExprlist(Fts5Config *p){
sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid);
if( p->eContent!=FTS5_CONTENT_NONE ){
+ assert( p->eContent==FTS5_CONTENT_EXTERNAL
+ || p->eContent==FTS5_CONTENT_NORMAL
+ || p->eContent==FTS5_CONTENT_UNINDEXED
+ );
for(i=0; i<p->nCol; i++){
if( p->eContent==FTS5_CONTENT_EXTERNAL ){
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]);
- }else{
+ }else if( p->eContent==FTS5_CONTENT_NORMAL || p->abUnindexed[i] ){
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i);
+ }else{
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
+ }
+ }
+ }
+ if( p->eContent==FTS5_CONTENT_NORMAL && p->bLocale ){
+ for(i=0; i<p->nCol; i++){
+ if( p->abUnindexed[i]==0 ){
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.l%d", i);
+ }else{
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
}
}
}
@@ -236179,10 +239790,12 @@ static int sqlite3Fts5ConfigParse(
Fts5Config *pRet; /* New object to return */
int i;
sqlite3_int64 nByte;
+ int bUnindexed = 0; /* True if there are one or more UNINDEXED */
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
if( pRet==0 ) return SQLITE_NOMEM;
memset(pRet, 0, sizeof(Fts5Config));
+ pRet->pGlobal = pGlobal;
pRet->db = db;
pRet->iCookie = -1;
@@ -236231,13 +239844,13 @@ static int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}else{
if( bOption ){
- rc = fts5ConfigParseSpecial(pGlobal, pRet,
+ rc = fts5ConfigParseSpecial(pRet,
ALWAYS(zOne)?zOne:"",
zTwo?zTwo:"",
pzErr
);
}else{
- rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
+ rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr, &bUnindexed);
zOne = 0;
}
}
@@ -236269,11 +239882,17 @@ static int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}
- /* If a tokenizer= option was successfully parsed, the tokenizer has
- ** already been allocated. Otherwise, allocate an instance of the default
- ** tokenizer (unicode61) now. */
- if( rc==SQLITE_OK && pRet->pTok==0 ){
- rc = fts5ConfigDefaultTokenizer(pGlobal, pRet);
+ /* We only allow contentless_unindexed=1 if the table is actually a
+ ** contentless one.
+ */
+ if( rc==SQLITE_OK
+ && pRet->bContentlessUnindexed
+ && pRet->eContent!=FTS5_CONTENT_NONE
+ ){
+ *pzErr = sqlite3_mprintf(
+ "contentless_unindexed=1 requires a contentless table"
+ );
+ rc = SQLITE_ERROR;
}
/* If no zContent option was specified, fill in the default values. */
@@ -236284,6 +239903,9 @@ static int sqlite3Fts5ConfigParse(
);
if( pRet->eContent==FTS5_CONTENT_NORMAL ){
zTail = "content";
+ }else if( bUnindexed && pRet->bContentlessUnindexed ){
+ pRet->eContent = FTS5_CONTENT_UNINDEXED;
+ zTail = "content";
}else if( pRet->bColumnsize ){
zTail = "docsize";
}
@@ -236317,9 +239939,14 @@ static int sqlite3Fts5ConfigParse(
static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){
if( pConfig ){
int i;
- if( pConfig->pTok ){
- pConfig->pTokApi->xDelete(pConfig->pTok);
+ if( pConfig->t.pTok ){
+ if( pConfig->t.pApi1 ){
+ pConfig->t.pApi1->xDelete(pConfig->t.pTok);
+ }else{
+ pConfig->t.pApi2->xDelete(pConfig->t.pTok);
+ }
}
+ sqlite3_free((char*)pConfig->t.azArg);
sqlite3_free(pConfig->zDb);
sqlite3_free(pConfig->zName);
for(i=0; i<pConfig->nCol; i++){
@@ -236394,10 +240021,24 @@ static int sqlite3Fts5Tokenize(
void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
){
- if( pText==0 ) return SQLITE_OK;
- return pConfig->pTokApi->xTokenize(
- pConfig->pTok, pCtx, flags, pText, nText, xToken
- );
+ int rc = SQLITE_OK;
+ if( pText ){
+ if( pConfig->t.pTok==0 ){
+ rc = sqlite3Fts5LoadTokenizer(pConfig);
+ }
+ if( rc==SQLITE_OK ){
+ if( pConfig->t.pApi1 ){
+ rc = pConfig->t.pApi1->xTokenize(
+ pConfig->t.pTok, pCtx, flags, pText, nText, xToken
+ );
+ }else{
+ rc = pConfig->t.pApi2->xTokenize(pConfig->t.pTok, pCtx, flags,
+ pText, nText, pConfig->t.pLocale, pConfig->t.nLocale, xToken
+ );
+ }
+ }
+ }
+ return rc;
}
/*
@@ -236601,6 +240242,19 @@ static int sqlite3Fts5ConfigSetValue(
}else{
pConfig->bSecureDelete = (bVal ? 1 : 0);
}
+ }
+
+ else if( 0==sqlite3_stricmp(zKey, "insttoken") ){
+ int bVal = -1;
+ if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+ bVal = sqlite3_value_int(pVal);
+ }
+ if( bVal<0 ){
+ *pbBadkey = 1;
+ }else{
+ pConfig->bPrefixInsttoken = (bVal ? 1 : 0);
+ }
+
}else{
*pbBadkey = 1;
}
@@ -236651,13 +240305,10 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
&& iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
){
rc = SQLITE_ERROR;
- if( pConfig->pzErrmsg ){
- assert( 0==*pConfig->pzErrmsg );
- *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format "
- "(found %d, expected %d or %d) - run 'rebuild'",
- iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
- );
- }
+ sqlite3Fts5ConfigErrmsg(pConfig, "invalid fts5 file format "
+ "(found %d, expected %d or %d) - run 'rebuild'",
+ iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
+ );
}else{
pConfig->iVersion = iVersion;
}
@@ -236669,6 +240320,29 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
}
/*
+** Set (*pConfig->pzErrmsg) to point to an sqlite3_malloc()ed buffer
+** containing the error message created using printf() style formatting
+** string zFmt and its trailing arguments.
+*/
+static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){
+ va_list ap; /* ... printf arguments */
+ char *zMsg = 0;
+
+ va_start(ap, zFmt);
+ zMsg = sqlite3_vmprintf(zFmt, ap);
+ if( pConfig->pzErrmsg ){
+ assert( *pConfig->pzErrmsg==0 );
+ *pConfig->pzErrmsg = zMsg;
+ }else{
+ sqlite3_free(zMsg);
+ }
+
+ va_end(ap);
+}
+
+
+
+/*
** 2014 May 31
**
** The author disclaims copyright to this source code. In place of
@@ -236724,7 +240398,7 @@ struct Fts5Expr {
/*
** eType:
-** Expression node type. Always one of:
+** Expression node type. Usually one of:
**
** FTS5_AND (nChild, apChild valid)
** FTS5_OR (nChild, apChild valid)
@@ -236732,6 +240406,10 @@ struct Fts5Expr {
** FTS5_STRING (pNear valid)
** FTS5_TERM (pNear valid)
**
+** An expression node with eType==0 may also exist. It always matches zero
+** rows. This is created when a phrase containing no tokens is parsed.
+** e.g. "".
+**
** iHeight:
** Distance from this node to furthest leaf. This is always 0 for nodes
** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one
@@ -236752,9 +240430,13 @@ struct Fts5ExprNode {
/* 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 */
+ Fts5ExprNode *apChild[FLEXARRAY]; /* Array of child nodes */
};
+/* Size (in bytes) of an Fts5ExprNode object that holds up to N children */
+#define SZ_FTS5EXPRNODE(N) \
+ (offsetof(Fts5ExprNode,apChild) + (N)*sizeof(Fts5ExprNode*))
+
#define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING)
/*
@@ -236785,9 +240467,13 @@ struct Fts5ExprPhrase {
Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */
Fts5Buffer poslist; /* Current position list */
int nTerm; /* Number of entries in aTerm[] */
- Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */
+ Fts5ExprTerm aTerm[FLEXARRAY]; /* Terms that make up this phrase */
};
+/* Size (in bytes) of an Fts5ExprPhrase object that holds up to N terms */
+#define SZ_FTS5EXPRPHRASE(N) \
+ (offsetof(Fts5ExprPhrase,aTerm) + (N)*sizeof(Fts5ExprTerm))
+
/*
** One or more phrases that must appear within a certain token distance of
** each other within each matching document.
@@ -236796,9 +240482,12 @@ struct Fts5ExprNearset {
int nNear; /* NEAR parameter */
Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */
int nPhrase; /* Number of entries in aPhrase[] array */
- Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */
+ Fts5ExprPhrase *apPhrase[FLEXARRAY]; /* Array of phrase pointers */
};
+/* Size (in bytes) of an Fts5ExprNearset object covering up to N phrases */
+#define SZ_FTS5EXPRNEARSET(N) \
+ (offsetof(Fts5ExprNearset,apPhrase)+(N)*sizeof(Fts5ExprPhrase*))
/*
** Parse context.
@@ -236952,12 +240641,13 @@ static int sqlite3Fts5ExprNew(
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+ assert( sParse.pExpr || sParse.rc!=SQLITE_OK );
assert_expr_depth_ok(sParse.rc, sParse.pExpr);
/* 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);
+ if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){
+ int n = SZ_FTS5COLSET(1);
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
if( pColset ){
pColset->nCol = 1;
@@ -236973,15 +240663,7 @@ static int sqlite3Fts5ExprNew(
sParse.rc = SQLITE_NOMEM;
sqlite3Fts5ParseNodeFree(sParse.pExpr);
}else{
- if( !sParse.pExpr ){
- const int nByte = sizeof(Fts5ExprNode);
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte);
- if( pNew->pRoot ){
- pNew->pRoot->bEof = 1;
- }
- }else{
- pNew->pRoot = sParse.pExpr;
- }
+ pNew->pRoot = sParse.pExpr;
pNew->pIndex = 0;
pNew->pConfig = pConfig;
pNew->apExprPhrase = sParse.apPhrase;
@@ -237799,7 +241481,7 @@ static int fts5ExprNodeTest_STRING(
}
}else{
Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
- if( pIter->iRowid==iLast || pIter->bEof ) continue;
+ if( pIter->iRowid==iLast ) continue;
bMatch = 0;
if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
return rc;
@@ -238321,12 +242003,9 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset(
Fts5ExprNearset *pRet = 0;
if( pParse->rc==SQLITE_OK ){
- if( pPhrase==0 ){
- return pNear;
- }
if( pNear==0 ){
sqlite3_int64 nByte;
- nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
+ nByte = SZ_FTS5EXPRNEARSET(SZALLOC+1);
pRet = sqlite3_malloc64(nByte);
if( pRet==0 ){
pParse->rc = SQLITE_NOMEM;
@@ -238337,7 +242016,7 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset(
int nNew = pNear->nPhrase + SZALLOC;
sqlite3_int64 nByte;
- nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
+ nByte = SZ_FTS5EXPRNEARSET(nNew+1);
pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte);
if( pRet==0 ){
pParse->rc = SQLITE_NOMEM;
@@ -238428,12 +242107,12 @@ static int fts5ParseTokenize(
int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
- sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew
+ SZ_FTS5EXPRPHRASE(nNew+1)
);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
- if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase));
+ if( pPhrase==0 ) memset(pNew, 0, SZ_FTS5EXPRPHRASE(1));
pCtx->pPhrase = pPhrase = pNew;
pNew->nTerm = nNew - SZALLOC;
}
@@ -238541,10 +242220,11 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
if( sCtx.pPhrase==0 ){
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
- sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase));
+ sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, SZ_FTS5EXPRPHRASE(1));
}else if( sCtx.pPhrase->nTerm ){
sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix;
}
+ assert( pParse->apPhrase!=0 );
pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
}
@@ -238564,7 +242244,7 @@ static int sqlite3Fts5ExprClonePhrase(
Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */
- if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ if( !pExpr || iPhrase<0 || iPhrase>=pExpr->nPhrase ){
rc = SQLITE_RANGE;
}else{
pOrig = pExpr->apExprPhrase[iPhrase];
@@ -238575,19 +242255,18 @@ static int sqlite3Fts5ExprClonePhrase(
sizeof(Fts5ExprPhrase*));
}
if( rc==SQLITE_OK ){
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc,
- sizeof(Fts5ExprNode));
+ pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRNODE(1));
}
if( rc==SQLITE_OK ){
pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
- sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
+ SZ_FTS5EXPRNEARSET(2));
}
if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
if( pColsetOrig ){
sqlite3_int64 nByte;
Fts5Colset *pColset;
- nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
+ nByte = SZ_FTS5COLSET(pColsetOrig->nCol);
pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
if( pColset ){
memcpy(pColset, pColsetOrig, (size_t)nByte);
@@ -238615,7 +242294,7 @@ static int sqlite3Fts5ExprClonePhrase(
}else{
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
- sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
+ sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRPHRASE(1));
}
}
@@ -238680,7 +242359,8 @@ static void sqlite3Fts5ParseSetDistance(
);
return;
}
- nNear = nNear * 10 + (p->p[i] - '0');
+ if( nNear<214748363 ) nNear = nNear * 10 + (p->p[i] - '0');
+ /* ^^^^^^^^^^^^^^^--- Prevent integer overflow */
}
}else{
nNear = FTS5_DEFAULT_NEARDIST;
@@ -238709,7 +242389,7 @@ static Fts5Colset *fts5ParseColset(
assert( pParse->rc==SQLITE_OK );
assert( iCol>=0 && iCol<pParse->pConfig->nCol );
- pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
+ pNew = sqlite3_realloc64(p, SZ_FTS5COLSET(nCol+1));
if( pNew==0 ){
pParse->rc = SQLITE_NOMEM;
}else{
@@ -238744,7 +242424,7 @@ static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p
int nCol = pParse->pConfig->nCol;
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
- sizeof(Fts5Colset) + sizeof(int)*nCol
+ SZ_FTS5COLSET(nCol+1)
);
if( pRet ){
int i;
@@ -238805,7 +242485,7 @@ static Fts5Colset *sqlite3Fts5ParseColset(
static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
Fts5Colset *pRet;
if( pOrig ){
- sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
+ sqlite3_int64 nByte = SZ_FTS5COLSET(pOrig->nCol);
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
if( pRet ){
memcpy(pRet, pOrig, (size_t)nByte);
@@ -238932,6 +242612,9 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
}
}
+/*
+** Add pSub as a child of p.
+*/
static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
int ii = p->nChild;
if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
@@ -238970,7 +242653,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
assert( pNear->nPhrase==1 );
assert( pParse->bPhraseToAnd );
- nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*);
+ nByte = SZ_FTS5EXPRNODE(nTerm+1);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
pRet->eType = FTS5_AND;
@@ -238980,7 +242663,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
pParse->nPhrase--;
for(ii=0; ii<nTerm; ii++){
Fts5ExprPhrase *pPhrase = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(
- &pParse->rc, sizeof(Fts5ExprPhrase)
+ &pParse->rc, SZ_FTS5EXPRPHRASE(1)
);
if( pPhrase ){
if( parseGrowPhraseArray(pParse) ){
@@ -239049,7 +242732,7 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
if( pRight->eType==eType ) nChild += pRight->nChild-1;
}
- nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
+ nByte = SZ_FTS5EXPRNODE(nChild);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
@@ -239076,19 +242759,23 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
"fts5: %s queries are not supported (detail!=full)",
pNear->nPhrase==1 ? "phrase": "NEAR"
);
- sqlite3_free(pRet);
+ sqlite3Fts5ParseNodeFree(pRet);
pRet = 0;
+ pNear = 0;
+ assert( pLeft==0 && pRight==0 );
}
}
}else{
+ assert( pNear==0 );
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
+ pLeft = pRight = 0;
if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
sqlite3Fts5ParseError(pParse,
"fts5 expression tree is too large (maximum depth %d)",
SQLITE_FTS5_MAX_EXPR_DEPTH
);
- sqlite3_free(pRet);
+ sqlite3Fts5ParseNodeFree(pRet);
pRet = 0;
}
}
@@ -239140,6 +242827,8 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
);
if( pRight->eType==FTS5_EOF ){
+ assert( pParse->apPhrase!=0 );
+ assert( pParse->nPhrase>0 );
assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] );
sqlite3Fts5ParseNodeFree(pRight);
pRet = pLeft;
@@ -239712,7 +243401,7 @@ static int fts5ExprPopulatePoslistsCb(
int rc = sqlite3Fts5PoslistWriterAppend(
&pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
);
- if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){
+ if( rc==SQLITE_OK && (pExpr->pConfig->bTokendata || pT->bPrefix) ){
int iCol = p->iOff>>32;
int iTokOff = p->iOff & 0x7FFFFFFF;
rc = sqlite3Fts5IndexIterWriteTokendata(
@@ -239772,6 +243461,7 @@ static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
pNode->iRowid = iRowid;
pNode->bEof = 0;
switch( pNode->eType ){
+ case 0:
case FTS5_TERM:
case FTS5_STRING:
return (pNode->pNear->apPhrase[0]->poslist.n>0);
@@ -239904,21 +243594,20 @@ static int sqlite3Fts5ExprInstToken(
return SQLITE_RANGE;
}
pTerm = &pPhrase->aTerm[iToken];
- if( pTerm->bPrefix==0 ){
- if( pExpr->pConfig->bTokendata ){
- rc = sqlite3Fts5IterToken(
- pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut
- );
- }else{
- *ppOut = pTerm->pTerm;
- *pnOut = pTerm->nFullTerm;
- }
+ if( pExpr->pConfig->bTokendata || pTerm->bPrefix ){
+ rc = sqlite3Fts5IterToken(
+ pTerm->pIter, pTerm->pTerm, pTerm->nQueryTerm,
+ iRowid, iCol, iOff+iToken, ppOut, pnOut
+ );
+ }else{
+ *ppOut = pTerm->pTerm;
+ *pnOut = pTerm->nFullTerm;
}
return rc;
}
/*
-** Clear the token mappings for all Fts5IndexIter objects mannaged by
+** Clear the token mappings for all Fts5IndexIter objects managed by
** the expression passed as the only argument.
*/
static void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
@@ -239953,7 +243642,7 @@ typedef struct Fts5HashEntry Fts5HashEntry;
/*
** This file contains the implementation of an in-memory hash table used
-** to accumuluate "term -> doclist" content before it is flused to a level-0
+** to accumulate "term -> doclist" content before it is flushed to a level-0
** segment.
*/
@@ -240010,7 +243699,7 @@ struct Fts5HashEntry {
};
/*
-** Eqivalent to:
+** Equivalent to:
**
** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; }
*/
@@ -240946,9 +244635,13 @@ struct Fts5Structure {
u64 nOriginCntr; /* Origin value for next top-level segment */
int nSegment; /* Total segments in this structure */
int nLevel; /* Number of levels in this index */
- Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */
+ Fts5StructureLevel aLevel[FLEXARRAY]; /* Array of nLevel level objects */
};
+/* Size (in bytes) of an Fts5Structure object holding up to N levels */
+#define SZ_FTS5STRUCTURE(N) \
+ (offsetof(Fts5Structure,aLevel) + (N)*sizeof(Fts5StructureLevel))
+
/*
** An object of type Fts5SegWriter is used to write to segments.
*/
@@ -241078,11 +244771,15 @@ struct Fts5SegIter {
** Array of tombstone pages. Reference counted.
*/
struct Fts5TombstoneArray {
- int nRef; /* Number of pointers to this object */
+ int nRef; /* Number of pointers to this object */
int nTombstone;
- Fts5Data *apTombstone[1]; /* Array of tombstone pages */
+ Fts5Data *apTombstone[FLEXARRAY]; /* Array of tombstone pages */
};
+/* Size (in bytes) of an Fts5TombstoneArray holding up to N tombstones */
+#define SZ_FTS5TOMBSTONEARRAY(N) \
+ (offsetof(Fts5TombstoneArray,apTombstone)+(N)*sizeof(Fts5Data*))
+
/*
** Argument is a pointer to an Fts5Data structure that contains a
** leaf page.
@@ -241151,9 +244848,12 @@ struct Fts5Iter {
i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */
Fts5CResult *aFirst; /* Current merge state (see above) */
- Fts5SegIter aSeg[1]; /* Array of segment iterators */
+ Fts5SegIter aSeg[FLEXARRAY]; /* Array of segment iterators */
};
+/* Size (in bytes) of an Fts5Iter object holding up to N segment iterators */
+#define SZ_FTS5ITER(N) (offsetof(Fts5Iter,aSeg)+(N)*sizeof(Fts5SegIter))
+
/*
** An instance of the following type is used to iterate through the contents
** of a doclist-index record.
@@ -241180,9 +244880,13 @@ struct Fts5DlidxLvl {
struct Fts5DlidxIter {
int nLvl;
int iSegid;
- Fts5DlidxLvl aLvl[1];
+ Fts5DlidxLvl aLvl[FLEXARRAY];
};
+/* Size (in bytes) of an Fts5DlidxIter object with up to N levels */
+#define SZ_FTS5DLIDXITER(N) \
+ (offsetof(Fts5DlidxIter,aLvl)+(N)*sizeof(Fts5DlidxLvl))
+
static void fts5PutU16(u8 *aOut, u16 iVal){
aOut[0] = (iVal>>8);
aOut[1] = (iVal&0xFF);
@@ -241302,11 +245006,13 @@ static int fts5LeafFirstTermOff(Fts5Data *pLeaf){
/*
** Close the read-only blob handle, if it is open.
*/
-static void sqlite3Fts5IndexCloseReader(Fts5Index *p){
+static void fts5IndexCloseReader(Fts5Index *p){
if( p->pReader ){
+ int rc;
sqlite3_blob *pReader = p->pReader;
p->pReader = 0;
- sqlite3_blob_close(pReader);
+ rc = sqlite3_blob_close(pReader);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
}
}
@@ -241331,7 +245037,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
assert( p->pReader==0 );
p->pReader = pBlob;
if( rc!=SQLITE_OK ){
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
}
if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
}
@@ -241355,11 +245061,12 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
if( rc==SQLITE_OK ){
u8 *aOut = 0; /* Read blob data into this buffer */
int nByte = sqlite3_blob_bytes(p->pReader);
- sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
+ int szData = (sizeof(Fts5Data) + 7) & ~7;
+ sqlite3_int64 nAlloc = szData + nByte + FTS5_DATA_PADDING;
pRet = (Fts5Data*)sqlite3_malloc64(nAlloc);
if( pRet ){
pRet->nn = nByte;
- aOut = pRet->p = (u8*)&pRet[1];
+ aOut = pRet->p = (u8*)pRet + szData;
}else{
rc = SQLITE_NOMEM;
}
@@ -241382,6 +245089,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
}
assert( (pRet==0)==(p->rc!=SQLITE_OK) );
+ assert( pRet==0 || EIGHT_BYTE_ALIGNMENT( pRet->p ) );
return pRet;
}
@@ -241413,9 +245121,13 @@ static int fts5IndexPrepareStmt(
){
if( p->rc==SQLITE_OK ){
if( zSql ){
- p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
+ int rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB,
ppStmt, 0);
+ /* If this prepare() call fails with SQLITE_ERROR, then one of the
+ ** %_idx or %_data tables has been removed or modified. Call this
+ ** corruption. */
+ p->rc = (rc==SQLITE_ERROR ? SQLITE_CORRUPT : rc);
}else{
p->rc = SQLITE_NOMEM;
}
@@ -241542,7 +245254,7 @@ static int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){
static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){
Fts5Structure *p = *pp;
if( *pRc==SQLITE_OK && p->nRef>1 ){
- i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel);
+ i64 nByte = SZ_FTS5STRUCTURE(p->nLevel);
Fts5Structure *pNew;
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte);
if( pNew ){
@@ -241616,10 +245328,7 @@ static int fts5StructureDecode(
){
return FTS5_CORRUPT;
}
- nByte = (
- sizeof(Fts5Structure) + /* Main structure */
- sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */
- );
+ nByte = SZ_FTS5STRUCTURE(nLevel);
pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte);
if( pRet ){
@@ -241699,10 +245408,7 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
- sqlite3_int64 nByte = (
- sizeof(Fts5Structure) + /* Main structure */
- sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */
- );
+ sqlite3_int64 nByte = SZ_FTS5STRUCTURE(nLevel+2);
pStruct = sqlite3_realloc64(pStruct, nByte);
if( pStruct ){
@@ -242241,7 +245947,7 @@ static Fts5DlidxIter *fts5DlidxIterInit(
int bDone = 0;
for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
- sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
+ sqlite3_int64 nByte = SZ_FTS5DLIDXITER(i+1);
Fts5DlidxIter *pNew;
pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte);
@@ -242459,7 +246165,7 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
const int nTomb = pIter->pSeg->nPgTombstone;
if( nTomb>0 ){
- int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray);
+ int nByte = SZ_FTS5TOMBSTONEARRAY(nTomb+1);
Fts5TombstoneArray *pNew;
pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
@@ -242707,7 +246413,7 @@ static void fts5SegIterNext_None(
if( iOff<pIter->iEndofDoclist ){
/* Next entry is on the current page */
- i64 iDelta;
+ u64 iDelta;
iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
pIter->iLeafOffset = iOff;
pIter->iRowid += iDelta;
@@ -243920,8 +247626,7 @@ static Fts5Iter *fts5MultiIterAlloc(
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
pNew = fts5IdxMalloc(p,
- sizeof(Fts5Iter) + /* pNew */
- sizeof(Fts5SegIter) * (nSlot-1) + /* pNew->aSeg[] */
+ SZ_FTS5ITER(nSlot) + /* pNew + pNew->aSeg[] */
sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */
);
if( pNew ){
@@ -245411,6 +249116,11 @@ static int fts5IndexFindDeleteMerge(Fts5Index *p, Fts5Structure *pStruct){
nBest = nPercent;
}
}
+
+ /* If pLvl is already the input level to an ongoing merge, look no
+ ** further for a merge candidate. The caller should be allowed to
+ ** continue merging from pLvl first. */
+ if( pLvl->nMerge ) break;
}
}
return iRet;
@@ -245522,6 +249232,14 @@ static int fts5IndexReturn(Fts5Index *p){
return rc;
}
+/*
+** Close the read-only blob handle, if it is open.
+*/
+static void sqlite3Fts5IndexCloseReader(Fts5Index *p){
+ fts5IndexCloseReader(p);
+ fts5IndexReturn(p);
+}
+
typedef struct Fts5FlushCtx Fts5FlushCtx;
struct Fts5FlushCtx {
Fts5Index *pIdx;
@@ -245709,7 +249427,7 @@ static void fts5DoSecureDelete(
int iDelKeyOff = 0; /* Offset of deleted key, if any */
nIdx = nPg-iPgIdx;
- aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16);
+ aIdx = sqlite3Fts5MallocZero(&p->rc, ((i64)nIdx)+16);
if( p->rc ) return;
memcpy(aIdx, &aPg[iPgIdx], nIdx);
@@ -245979,8 +249697,11 @@ static void fts5DoSecureDelete(
** This is called as part of flushing a delete to disk in 'secure-delete'
** mode. It edits the segments within the database described by argument
** pStruct to remove the entries for term zTerm, rowid iRowid.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** has occurred. Any error code is also stored in the Fts5Index handle.
*/
-static void fts5FlushSecureDelete(
+static int fts5FlushSecureDelete(
Fts5Index *p,
Fts5Structure *pStruct,
const char *zTerm,
@@ -245990,6 +249711,24 @@ static void fts5FlushSecureDelete(
const int f = FTS5INDEX_QUERY_SKIPHASH;
Fts5Iter *pIter = 0; /* Used to find term instance */
+ /* If the version number has not been set to SECUREDELETE, do so now. */
+ if( p->pConfig->iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE ){
+ Fts5Config *pConfig = p->pConfig;
+ sqlite3_stmt *pStmt = 0;
+ fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf(
+ "REPLACE INTO %Q.'%q_config' VALUES ('version', %d)",
+ pConfig->zDb, pConfig->zName, FTS5_CURRENT_VERSION_SECUREDELETE
+ ));
+ if( p->rc==SQLITE_OK ){
+ int rc;
+ sqlite3_step(pStmt);
+ rc = sqlite3_finalize(pStmt);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
+ pConfig->iCookie++;
+ pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
+ }
+ }
+
fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
if( fts5MultiIterEof(p, pIter)==0 ){
i64 iThis = fts5MultiIterRowid(pIter);
@@ -246007,6 +249746,7 @@ static void fts5FlushSecureDelete(
}
fts5MultiIterFree(pIter);
+ return p->rc;
}
@@ -246090,8 +249830,9 @@ static void fts5FlushOneHash(Fts5Index *p){
** using fts5FlushSecureDelete(). */
if( bSecureDelete ){
if( eDetail==FTS5_DETAIL_NONE ){
- if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
- fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ if( iOff<nDoclist && pDoclist[iOff]==0x00
+ && !fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid)
+ ){
iOff++;
if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
iOff++;
@@ -246100,8 +249841,9 @@ static void fts5FlushOneHash(Fts5Index *p){
continue;
}
}
- }else if( (pDoclist[iOff] & 0x01) ){
- fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ }else if( (pDoclist[iOff] & 0x01)
+ && !fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid)
+ ){
if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
iOff++;
continue;
@@ -246250,7 +249992,7 @@ static Fts5Structure *fts5IndexOptimizeStruct(
Fts5Structure *pStruct
){
Fts5Structure *pNew = 0;
- sqlite3_int64 nByte = sizeof(Fts5Structure);
+ sqlite3_int64 nByte = SZ_FTS5STRUCTURE(1);
int nSeg = pStruct->nSegment;
int i;
@@ -246279,7 +250021,8 @@ static Fts5Structure *fts5IndexOptimizeStruct(
assert( pStruct->aLevel[i].nMerge<=nThis );
}
- nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
+ nByte += (((i64)pStruct->nLevel)+1) * sizeof(Fts5StructureLevel);
+ assert( nByte==SZ_FTS5STRUCTURE(pStruct->nLevel+2) );
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
@@ -246720,6 +250463,387 @@ static void fts5MergePrefixLists(
*p1 = out;
}
+
+/*
+** Iterate through a range of entries in the FTS index, invoking the xVisit
+** callback for each of them.
+**
+** Parameter pToken points to an nToken buffer containing an FTS index term
+** (i.e. a document term with the preceding 1 byte index identifier -
+** FTS5_MAIN_PREFIX or similar). If bPrefix is true, then the call visits
+** all entries for terms that have pToken/nToken as a prefix. If bPrefix
+** is false, then only entries with pToken/nToken as the entire key are
+** visited.
+**
+** If the current table is a tokendata=1 table, then if bPrefix is true then
+** each index term is treated separately. However, if bPrefix is false, then
+** all index terms corresponding to pToken/nToken are collapsed into a single
+** term before the callback is invoked.
+**
+** The callback invoked for each entry visited is specified by paramter xVisit.
+** Each time it is invoked, it is passed a pointer to the Fts5Index object,
+** a copy of the 7th paramter to this function (pCtx) and a pointer to the
+** iterator that indicates the current entry. If the current entry is the
+** first with a new term (i.e. different from that of the previous entry,
+** including the very first term), then the final two parameters are passed
+** a pointer to the term and its size in bytes, respectively. If the current
+** entry is not the first associated with its term, these two parameters
+** are passed 0.
+**
+** If parameter pColset is not NULL, then it is used to filter entries before
+** the callback is invoked.
+*/
+static int fts5VisitEntries(
+ Fts5Index *p, /* Fts5 index object */
+ Fts5Colset *pColset, /* Columns filter to apply, or NULL */
+ u8 *pToken, /* Buffer containing token */
+ int nToken, /* Size of buffer pToken in bytes */
+ int bPrefix, /* True for a prefix scan */
+ void (*xVisit)(Fts5Index*, void *pCtx, Fts5Iter *pIter, const u8*, int),
+ void *pCtx /* Passed as second argument to xVisit() */
+){
+ const int flags = (bPrefix ? FTS5INDEX_QUERY_SCAN : 0)
+ | FTS5INDEX_QUERY_SKIPEMPTY
+ | FTS5INDEX_QUERY_NOOUTPUT;
+ Fts5Iter *p1 = 0; /* Iterator used to gather data from index */
+ int bNewTerm = 1;
+ Fts5Structure *pStruct = fts5StructureRead(p);
+
+ fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
+ fts5IterSetOutputCb(&p->rc, p1);
+ for( /* no-op */ ;
+ fts5MultiIterEof(p, p1)==0;
+ fts5MultiIterNext2(p, p1, &bNewTerm)
+ ){
+ Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
+ int nNew = 0;
+ const u8 *pNew = 0;
+
+ p1->xSetOutputs(p1, pSeg);
+ if( p->rc ) break;
+
+ if( bNewTerm ){
+ nNew = pSeg->term.n;
+ pNew = pSeg->term.p;
+ if( nNew<nToken || memcmp(pToken, pNew, nToken) ) break;
+ }
+
+ xVisit(p, pCtx, p1, pNew, nNew);
+ }
+ fts5MultiIterFree(p1);
+
+ fts5StructureRelease(pStruct);
+ return p->rc;
+}
+
+
+/*
+** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
+** array of these for each row it visits (so all iRowid fields are the same).
+** Or, for an iterator used by an "ORDER BY rank" query, it accumulates an
+** array of these for the entire query (in which case iRowid fields may take
+** a variety of values).
+**
+** Each instance in the array indicates the iterator (and therefore term)
+** associated with position iPos of rowid iRowid. This is used by the
+** xInstToken() API.
+**
+** iRowid:
+** Rowid for the current entry.
+**
+** iPos:
+** Position of current entry within row. In the usual ((iCol<<32)+iOff)
+** format (e.g. see macros FTS5_POS2COLUMN() and FTS5_POS2OFFSET()).
+**
+** iIter:
+** If the Fts5TokenDataIter iterator that the entry is part of is
+** actually an iterator (i.e. with nIter>0, not just a container for
+** Fts5TokenDataMap structures), then this variable is an index into
+** the apIter[] array. The corresponding term is that which the iterator
+** at apIter[iIter] currently points to.
+**
+** Or, if the Fts5TokenDataIter iterator is just a container object
+** (nIter==0), then iIter is an index into the term.p[] buffer where
+** the term is stored.
+**
+** nByte:
+** In the case where iIter is an index into term.p[], this variable
+** is the size of the term in bytes. If iIter is an index into apIter[],
+** this variable is unused.
+*/
+struct Fts5TokenDataMap {
+ i64 iRowid; /* Row this token is located in */
+ i64 iPos; /* Position of token */
+ int iIter; /* Iterator token was read from */
+ int nByte; /* Length of token in bytes (or 0) */
+};
+
+/*
+** An object used to supplement Fts5Iter for tokendata=1 iterators.
+**
+** This object serves two purposes. The first is as a container for an array
+** of Fts5TokenDataMap structures, which are used to find the token required
+** when the xInstToken() API is used. This is done by the nMapAlloc, nMap and
+** aMap[] variables.
+*/
+struct Fts5TokenDataIter {
+ int nMapAlloc; /* Allocated size of aMap[] in entries */
+ int nMap; /* Number of valid entries in aMap[] */
+ Fts5TokenDataMap *aMap; /* Array of (rowid+pos -> token) mappings */
+
+ /* The following are used for prefix-queries only. */
+ Fts5Buffer terms;
+
+ /* The following are used for other full-token tokendata queries only. */
+ int nIter;
+ int nIterAlloc;
+ Fts5PoslistReader *aPoslistReader;
+ int *aPoslistToIter;
+ Fts5Iter *apIter[FLEXARRAY];
+};
+
+/* Size in bytes of an Fts5TokenDataIter object holding up to N iterators */
+#define SZ_FTS5TOKENDATAITER(N) \
+ (offsetof(Fts5TokenDataIter,apIter) + (N)*sizeof(Fts5Iter))
+
+/*
+** The two input arrays - a1[] and a2[] - are in sorted order. This function
+** merges the two arrays together and writes the result to output array
+** aOut[]. aOut[] is guaranteed to be large enough to hold the result.
+**
+** Duplicate entries are copied into the output. So the size of the output
+** array is always (n1+n2) entries.
+*/
+static void fts5TokendataMerge(
+ Fts5TokenDataMap *a1, int n1, /* Input array 1 */
+ Fts5TokenDataMap *a2, int n2, /* Input array 2 */
+ Fts5TokenDataMap *aOut /* Output array */
+){
+ int i1 = 0;
+ int i2 = 0;
+
+ assert( n1>=0 && n2>=0 );
+ while( i1<n1 || i2<n2 ){
+ Fts5TokenDataMap *pOut = &aOut[i1+i2];
+ if( i2>=n2 || (i1<n1 && (
+ a1[i1].iRowid<a2[i2].iRowid
+ || (a1[i1].iRowid==a2[i2].iRowid && a1[i1].iPos<=a2[i2].iPos)
+ ))){
+ memcpy(pOut, &a1[i1], sizeof(Fts5TokenDataMap));
+ i1++;
+ }else{
+ memcpy(pOut, &a2[i2], sizeof(Fts5TokenDataMap));
+ i2++;
+ }
+ }
+}
+
+
+/*
+** Append a mapping to the token-map belonging to object pT.
+*/
+static void fts5TokendataIterAppendMap(
+ Fts5Index *p,
+ Fts5TokenDataIter *pT,
+ int iIter,
+ int nByte,
+ i64 iRowid,
+ i64 iPos
+){
+ if( p->rc==SQLITE_OK ){
+ if( pT->nMap==pT->nMapAlloc ){
+ int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
+ int nAlloc = nNew * sizeof(Fts5TokenDataMap);
+ Fts5TokenDataMap *aNew;
+
+ aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nAlloc);
+ if( aNew==0 ){
+ p->rc = SQLITE_NOMEM;
+ return;
+ }
+
+ pT->aMap = aNew;
+ pT->nMapAlloc = nNew;
+ }
+
+ pT->aMap[pT->nMap].iRowid = iRowid;
+ pT->aMap[pT->nMap].iPos = iPos;
+ pT->aMap[pT->nMap].iIter = iIter;
+ pT->aMap[pT->nMap].nByte = nByte;
+ pT->nMap++;
+ }
+}
+
+/*
+** Sort the contents of the pT->aMap[] array.
+**
+** The sorting algorithm requires a malloc(). If this fails, an error code
+** is left in Fts5Index.rc before returning.
+*/
+static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){
+ Fts5TokenDataMap *aTmp = 0;
+ int nByte = pT->nMap * sizeof(Fts5TokenDataMap);
+
+ aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte);
+ if( aTmp ){
+ Fts5TokenDataMap *a1 = pT->aMap;
+ Fts5TokenDataMap *a2 = aTmp;
+ i64 nHalf;
+
+ for(nHalf=1; nHalf<pT->nMap; nHalf=nHalf*2){
+ int i1;
+ for(i1=0; i1<pT->nMap; i1+=(nHalf*2)){
+ int n1 = MIN(nHalf, pT->nMap-i1);
+ int n2 = MIN(nHalf, pT->nMap-i1-n1);
+ fts5TokendataMerge(&a1[i1], n1, &a1[i1+n1], n2, &a2[i1]);
+ }
+ SWAPVAL(Fts5TokenDataMap*, a1, a2);
+ }
+
+ if( a1!=pT->aMap ){
+ memcpy(pT->aMap, a1, pT->nMap*sizeof(Fts5TokenDataMap));
+ }
+ sqlite3_free(aTmp);
+
+#ifdef SQLITE_DEBUG
+ {
+ int ii;
+ for(ii=1; ii<pT->nMap; ii++){
+ Fts5TokenDataMap *p1 = &pT->aMap[ii-1];
+ Fts5TokenDataMap *p2 = &pT->aMap[ii];
+ assert( p1->iRowid<p2->iRowid
+ || (p1->iRowid==p2->iRowid && p1->iPos<=p2->iPos)
+ );
+ }
+ }
+#endif
+ }
+}
+
+/*
+** Delete an Fts5TokenDataIter structure and its contents.
+*/
+static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
+ if( pSet ){
+ int ii;
+ for(ii=0; ii<pSet->nIter; ii++){
+ fts5MultiIterFree(pSet->apIter[ii]);
+ }
+ fts5BufferFree(&pSet->terms);
+ sqlite3_free(pSet->aPoslistReader);
+ sqlite3_free(pSet->aMap);
+ sqlite3_free(pSet);
+ }
+}
+
+
+/*
+** fts5VisitEntries() context object used by fts5SetupPrefixIterTokendata()
+** to pass data to prefixIterSetupTokendataCb().
+*/
+typedef struct TokendataSetupCtx TokendataSetupCtx;
+struct TokendataSetupCtx {
+ Fts5TokenDataIter *pT; /* Object being populated with mappings */
+ int iTermOff; /* Offset of current term in terms.p[] */
+ int nTermByte; /* Size of current term in bytes */
+};
+
+/*
+** fts5VisitEntries() callback used by fts5SetupPrefixIterTokendata(). This
+** callback adds an entry to the Fts5TokenDataIter.aMap[] array for each
+** position in the current position-list. It doesn't matter that some of
+** these may be out of order - they will be sorted later.
+*/
+static void prefixIterSetupTokendataCb(
+ Fts5Index *p,
+ void *pCtx,
+ Fts5Iter *p1,
+ const u8 *pNew,
+ int nNew
+){
+ TokendataSetupCtx *pSetup = (TokendataSetupCtx*)pCtx;
+ int iPosOff = 0;
+ i64 iPos = 0;
+
+ if( pNew ){
+ pSetup->nTermByte = nNew-1;
+ pSetup->iTermOff = pSetup->pT->terms.n;
+ fts5BufferAppendBlob(&p->rc, &pSetup->pT->terms, nNew-1, pNew+1);
+ }
+
+ while( 0==sqlite3Fts5PoslistNext64(
+ p1->base.pData, p1->base.nData, &iPosOff, &iPos
+ ) ){
+ fts5TokendataIterAppendMap(p,
+ pSetup->pT, pSetup->iTermOff, pSetup->nTermByte, p1->base.iRowid, iPos
+ );
+ }
+}
+
+
+/*
+** Context object passed by fts5SetupPrefixIter() to fts5VisitEntries().
+*/
+typedef struct PrefixSetupCtx PrefixSetupCtx;
+struct PrefixSetupCtx {
+ void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
+ void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
+ i64 iLastRowid;
+ int nMerge;
+ Fts5Buffer *aBuf;
+ int nBuf;
+ Fts5Buffer doclist;
+ TokendataSetupCtx *pTokendata;
+};
+
+/*
+** fts5VisitEntries() callback used by fts5SetupPrefixIter()
+*/
+static void prefixIterSetupCb(
+ Fts5Index *p,
+ void *pCtx,
+ Fts5Iter *p1,
+ const u8 *pNew,
+ int nNew
+){
+ PrefixSetupCtx *pSetup = (PrefixSetupCtx*)pCtx;
+ const int nMerge = pSetup->nMerge;
+
+ if( p1->base.nData>0 ){
+ if( p1->base.iRowid<=pSetup->iLastRowid && pSetup->doclist.n>0 ){
+ int i;
+ for(i=0; p->rc==SQLITE_OK && pSetup->doclist.n; i++){
+ int i1 = i*nMerge;
+ int iStore;
+ assert( i1+nMerge<=pSetup->nBuf );
+ for(iStore=i1; iStore<i1+nMerge; iStore++){
+ if( pSetup->aBuf[iStore].n==0 ){
+ fts5BufferSwap(&pSetup->doclist, &pSetup->aBuf[iStore]);
+ fts5BufferZero(&pSetup->doclist);
+ break;
+ }
+ }
+ if( iStore==i1+nMerge ){
+ pSetup->xMerge(p, &pSetup->doclist, nMerge, &pSetup->aBuf[i1]);
+ for(iStore=i1; iStore<i1+nMerge; iStore++){
+ fts5BufferZero(&pSetup->aBuf[iStore]);
+ }
+ }
+ }
+ pSetup->iLastRowid = 0;
+ }
+
+ pSetup->xAppend(
+ p, (u64)p1->base.iRowid-(u64)pSetup->iLastRowid, p1, &pSetup->doclist
+ );
+ pSetup->iLastRowid = p1->base.iRowid;
+ }
+
+ if( pSetup->pTokendata ){
+ prefixIterSetupTokendataCb(p, (void*)pSetup->pTokendata, p1, pNew, nNew);
+ }
+}
+
static void fts5SetupPrefixIter(
Fts5Index *p, /* Index to read from */
int bDesc, /* True for "ORDER BY rowid DESC" */
@@ -246730,38 +250854,41 @@ static void fts5SetupPrefixIter(
Fts5Iter **ppIter /* OUT: New iterator */
){
Fts5Structure *pStruct;
- Fts5Buffer *aBuf;
- int nBuf = 32;
- int nMerge = 1;
+ PrefixSetupCtx s;
+ TokendataSetupCtx s2;
+
+ memset(&s, 0, sizeof(s));
+ memset(&s2, 0, sizeof(s2));
+
+ s.nMerge = 1;
+ s.iLastRowid = 0;
+ s.nBuf = 32;
+ if( iIdx==0
+ && p->pConfig->eDetail==FTS5_DETAIL_FULL
+ && p->pConfig->bPrefixInsttoken
+ ){
+ s.pTokendata = &s2;
+ s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, SZ_FTS5TOKENDATAITER(1));
+ }
- void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
- void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
- xMerge = fts5MergeRowidLists;
- xAppend = fts5AppendRowid;
+ s.xMerge = fts5MergeRowidLists;
+ s.xAppend = fts5AppendRowid;
}else{
- nMerge = FTS5_MERGE_NLIST-1;
- nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
- xMerge = fts5MergePrefixLists;
- xAppend = fts5AppendPoslist;
+ s.nMerge = FTS5_MERGE_NLIST-1;
+ s.nBuf = s.nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
+ s.xMerge = fts5MergePrefixLists;
+ s.xAppend = fts5AppendPoslist;
}
- aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
+ s.aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*s.nBuf);
pStruct = fts5StructureRead(p);
- assert( p->rc!=SQLITE_OK || (aBuf && pStruct) );
+ assert( p->rc!=SQLITE_OK || (s.aBuf && pStruct) );
if( p->rc==SQLITE_OK ){
- const int flags = FTS5INDEX_QUERY_SCAN
- | FTS5INDEX_QUERY_SKIPEMPTY
- | FTS5INDEX_QUERY_NOOUTPUT;
+ void *pCtx = (void*)&s;
int i;
- i64 iLastRowid = 0;
- Fts5Iter *p1 = 0; /* Iterator used to gather data from index */
Fts5Data *pData;
- Fts5Buffer doclist;
- int bNewTerm = 1;
-
- memset(&doclist, 0, sizeof(doclist));
/* If iIdx is non-zero, then it is the number of a prefix-index for
** prefixes 1 character longer than the prefix being queried for. That
@@ -246769,94 +250896,46 @@ static void fts5SetupPrefixIter(
** corresponding to the prefix itself. That one is extracted from the
** main term index here. */
if( iIdx!=0 ){
- int dummy = 0;
- const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
pToken[0] = FTS5_MAIN_PREFIX;
- fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1);
- fts5IterSetOutputCb(&p->rc, p1);
- for(;
- fts5MultiIterEof(p, p1)==0;
- fts5MultiIterNext2(p, p1, &dummy)
- ){
- Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
- p1->xSetOutputs(p1, pSeg);
- if( p1->base.nData ){
- xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
- iLastRowid = p1->base.iRowid;
- }
- }
- fts5MultiIterFree(p1);
+ fts5VisitEntries(p, pColset, pToken, nToken, 0, prefixIterSetupCb, pCtx);
}
pToken[0] = FTS5_MAIN_PREFIX + iIdx;
- fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
- fts5IterSetOutputCb(&p->rc, p1);
-
- for( /* no-op */ ;
- fts5MultiIterEof(p, p1)==0;
- fts5MultiIterNext2(p, p1, &bNewTerm)
- ){
- Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
- int nTerm = pSeg->term.n;
- const u8 *pTerm = pSeg->term.p;
- p1->xSetOutputs(p1, pSeg);
-
- assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
- if( bNewTerm ){
- if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
- }
-
- if( p1->base.nData==0 ) continue;
- if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
- for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
- int i1 = i*nMerge;
- int iStore;
- assert( i1+nMerge<=nBuf );
- for(iStore=i1; iStore<i1+nMerge; iStore++){
- if( aBuf[iStore].n==0 ){
- fts5BufferSwap(&doclist, &aBuf[iStore]);
- fts5BufferZero(&doclist);
- break;
- }
- }
- if( iStore==i1+nMerge ){
- xMerge(p, &doclist, nMerge, &aBuf[i1]);
- for(iStore=i1; iStore<i1+nMerge; iStore++){
- fts5BufferZero(&aBuf[iStore]);
- }
- }
- }
- iLastRowid = 0;
- }
+ fts5VisitEntries(p, pColset, pToken, nToken, 1, prefixIterSetupCb, pCtx);
- xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
- iLastRowid = p1->base.iRowid;
- }
-
- assert( (nBuf%nMerge)==0 );
- for(i=0; i<nBuf; i+=nMerge){
+ assert( (s.nBuf%s.nMerge)==0 );
+ for(i=0; i<s.nBuf; i+=s.nMerge){
int iFree;
if( p->rc==SQLITE_OK ){
- xMerge(p, &doclist, nMerge, &aBuf[i]);
+ s.xMerge(p, &s.doclist, s.nMerge, &s.aBuf[i]);
}
- for(iFree=i; iFree<i+nMerge; iFree++){
- fts5BufferFree(&aBuf[iFree]);
+ for(iFree=i; iFree<i+s.nMerge; iFree++){
+ fts5BufferFree(&s.aBuf[iFree]);
}
}
- fts5MultiIterFree(p1);
- pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING);
+ pData = fts5IdxMalloc(p, sizeof(*pData)
+ + ((i64)s.doclist.n)+FTS5_DATA_ZERO_PADDING);
+ assert( pData!=0 || p->rc!=SQLITE_OK );
if( pData ){
pData->p = (u8*)&pData[1];
- pData->nn = pData->szLeaf = doclist.n;
- if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n);
+ pData->nn = pData->szLeaf = s.doclist.n;
+ if( s.doclist.n ) memcpy(pData->p, s.doclist.p, s.doclist.n);
fts5MultiIterNew2(p, pData, bDesc, ppIter);
}
- fts5BufferFree(&doclist);
+
+ assert( (*ppIter)!=0 || p->rc!=SQLITE_OK );
+ if( p->rc==SQLITE_OK && s.pTokendata ){
+ fts5TokendataIterSortMap(p, s2.pT);
+ (*ppIter)->pTokenDataIter = s2.pT;
+ s2.pT = 0;
+ }
}
+ fts5TokendataIterDelete(s2.pT);
+ fts5BufferFree(&s.doclist);
fts5StructureRelease(pStruct);
- sqlite3_free(aBuf);
+ sqlite3_free(s.aBuf);
}
@@ -246894,7 +250973,7 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
static int sqlite3Fts5IndexSync(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
return fts5IndexReturn(p);
}
@@ -246905,11 +250984,10 @@ static int sqlite3Fts5IndexSync(Fts5Index *p){
** records must be invalidated.
*/
static int sqlite3Fts5IndexRollback(Fts5Index *p){
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
fts5IndexDiscardData(p);
fts5StructureInvalidate(p);
- /* assert( p->rc==SQLITE_OK ); */
- return SQLITE_OK;
+ return fts5IndexReturn(p);
}
/*
@@ -246918,15 +250996,17 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){
** and the initial version of the "averages" record (a zero-byte blob).
*/
static int sqlite3Fts5IndexReinit(Fts5Index *p){
- Fts5Structure s;
+ Fts5Structure *pTmp;
+ u8 tmpSpace[SZ_FTS5STRUCTURE(1)];
fts5StructureInvalidate(p);
fts5IndexDiscardData(p);
- memset(&s, 0, sizeof(Fts5Structure));
+ pTmp = (Fts5Structure*)tmpSpace;
+ memset(pTmp, 0, SZ_FTS5STRUCTURE(1));
if( p->pConfig->bContentlessDelete ){
- s.nOriginCntr = 1;
+ pTmp->nOriginCntr = 1;
}
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
- fts5StructureWrite(p, &s);
+ fts5StructureWrite(p, pTmp);
return fts5IndexReturn(p);
}
@@ -247110,37 +251190,15 @@ static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
pSeg->pLeaf = 0;
}
-/*
-** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
-** array of these for each row it visits. Or, for an iterator used by an
-** "ORDER BY rank" query, it accumulates an array of these for the entire
-** query.
-**
-** Each instance in the array indicates the iterator (and therefore term)
-** associated with position iPos of rowid iRowid. This is used by the
-** xInstToken() API.
-*/
-struct Fts5TokenDataMap {
- i64 iRowid; /* Row this token is located in */
- i64 iPos; /* Position of token */
- int iIter; /* Iterator token was read from */
-};
-
-/*
-** An object used to supplement Fts5Iter for tokendata=1 iterators.
-*/
-struct Fts5TokenDataIter {
- int nIter;
- int nIterAlloc;
-
- int nMap;
- int nMapAlloc;
- Fts5TokenDataMap *aMap;
-
- Fts5PoslistReader *aPoslistReader;
- int *aPoslistToIter;
- Fts5Iter *apIter[1];
-};
+static void fts5IterClose(Fts5IndexIter *pIndexIter){
+ if( pIndexIter ){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5Index *pIndex = pIter->pIndex;
+ fts5TokendataIterDelete(pIter->pTokenDataIter);
+ fts5MultiIterFree(pIter);
+ fts5IndexCloseReader(pIndex);
+ }
+}
/*
** This function appends iterator pAppend to Fts5TokenDataIter pIn and
@@ -247156,7 +251214,7 @@ static Fts5TokenDataIter *fts5AppendTokendataIter(
if( p->rc==SQLITE_OK ){
if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
- int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter);
+ int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1);
Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte);
if( pNew==0 ){
@@ -247169,7 +251227,7 @@ static Fts5TokenDataIter *fts5AppendTokendataIter(
}
}
if( p->rc ){
- sqlite3Fts5IterClose((Fts5IndexIter*)pAppend);
+ fts5IterClose((Fts5IndexIter*)pAppend);
}else{
pRet->apIter[pRet->nIter++] = pAppend;
}
@@ -247179,54 +251237,6 @@ static Fts5TokenDataIter *fts5AppendTokendataIter(
}
/*
-** Delete an Fts5TokenDataIter structure and its contents.
-*/
-static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
- if( pSet ){
- int ii;
- for(ii=0; ii<pSet->nIter; ii++){
- fts5MultiIterFree(pSet->apIter[ii]);
- }
- sqlite3_free(pSet->aPoslistReader);
- sqlite3_free(pSet->aMap);
- sqlite3_free(pSet);
- }
-}
-
-/*
-** Append a mapping to the token-map belonging to object pT.
-*/
-static void fts5TokendataIterAppendMap(
- Fts5Index *p,
- Fts5TokenDataIter *pT,
- int iIter,
- i64 iRowid,
- i64 iPos
-){
- if( p->rc==SQLITE_OK ){
- if( pT->nMap==pT->nMapAlloc ){
- int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
- int nByte = nNew * sizeof(Fts5TokenDataMap);
- Fts5TokenDataMap *aNew;
-
- aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nByte);
- if( aNew==0 ){
- p->rc = SQLITE_NOMEM;
- return;
- }
-
- pT->aMap = aNew;
- pT->nMapAlloc = nNew;
- }
-
- pT->aMap[pT->nMap].iRowid = iRowid;
- pT->aMap[pT->nMap].iPos = iPos;
- pT->aMap[pT->nMap].iIter = iIter;
- pT->nMap++;
- }
-}
-
-/*
** The iterator passed as the only argument must be a tokendata=1 iterator
** (pIter->pTokenDataIter!=0). This function sets the iterator output
** variables (pIter->base.*) according to the contents of the current
@@ -247266,7 +251276,7 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
pIter->base.iRowid = iRowid;
if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){
- fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1);
+ fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, 0, iRowid, -1);
}else
if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){
int nReader = 0;
@@ -247430,7 +251440,7 @@ static Fts5Iter *fts5SetupTokendataIter(
fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
}
if( p->rc ){
- sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ fts5IterClose((Fts5IndexIter*)pNew);
break;
}
@@ -247495,7 +251505,7 @@ static Fts5Iter *fts5SetupTokendataIter(
** not point to any terms that match the query. So delete it and break
** out of the loop - all required iterators have been collected. */
if( pSmall==0 ){
- sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ fts5IterClose((Fts5IndexIter*)pNew);
break;
}
@@ -247519,6 +251529,7 @@ static Fts5Iter *fts5SetupTokendataIter(
pRet = fts5MultiIterAlloc(p, 0);
}
if( pRet ){
+ pRet->nSeg = 0;
pRet->pTokenDataIter = pSet;
if( pSet ){
fts5IterSetOutputsTokendata(pRet);
@@ -247534,7 +251545,6 @@ static Fts5Iter *fts5SetupTokendataIter(
return pRet;
}
-
/*
** Open a new iterator to iterate though all rowid that match the
** specified token or token prefix.
@@ -247557,8 +251567,14 @@ static int sqlite3Fts5IndexQuery(
int iIdx = 0; /* Index to search */
int iPrefixIdx = 0; /* +1 prefix index */
int bTokendata = pConfig->bTokendata;
+ assert( buf.p!=0 );
if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
+ /* The NOTOKENDATA flag is set when each token in a tokendata=1 table
+ ** should be treated individually, instead of merging all those with
+ ** a common prefix into a single entry. This is used, for example, by
+ ** queries performed as part of an integrity-check, or by the fts5vocab
+ ** module. */
if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
bTokendata = 0;
}
@@ -247589,7 +251605,7 @@ static int sqlite3Fts5IndexQuery(
}
if( bTokendata && iIdx==0 ){
- buf.p[0] = '0';
+ buf.p[0] = FTS5_MAIN_PREFIX;
pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
}else if( iIdx<=pConfig->nPrefix ){
/* Straight index lookup */
@@ -247602,7 +251618,7 @@ static int sqlite3Fts5IndexQuery(
fts5StructureRelease(pStruct);
}
}else{
- /* Scan multiple terms in the main index */
+ /* Scan multiple terms in the main index for a prefix query. */
int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
if( pRet==0 ){
@@ -247618,9 +251634,9 @@ static int sqlite3Fts5IndexQuery(
}
if( p->rc ){
- sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
+ fts5IterClose((Fts5IndexIter*)pRet);
pRet = 0;
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
}
*ppIter = (Fts5IndexIter*)pRet;
@@ -247638,7 +251654,8 @@ static int sqlite3Fts5IndexQuery(
static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
assert( pIter->pIndex->rc==SQLITE_OK );
- if( pIter->pTokenDataIter ){
+ if( pIter->nSeg==0 ){
+ assert( pIter->pTokenDataIter );
fts5TokendataIterNext(pIter, 0, 0);
}else{
fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
@@ -247675,7 +251692,8 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){
*/
static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- if( pIter->pTokenDataIter ){
+ if( pIter->nSeg==0 ){
+ assert( pIter->pTokenDataIter );
fts5TokendataIterNext(pIter, 1, iMatch);
}else{
fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
@@ -247695,13 +251713,61 @@ static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
}
/*
+** pIter is a prefix query. This function populates pIter->pTokenDataIter
+** with an Fts5TokenDataIter object containing mappings for all rows
+** matched by the query.
+*/
+static int fts5SetupPrefixIterTokendata(
+ Fts5Iter *pIter,
+ const char *pToken, /* Token prefix to search for */
+ int nToken /* Size of pToken in bytes */
+){
+ Fts5Index *p = pIter->pIndex;
+ Fts5Buffer token = {0, 0, 0};
+ TokendataSetupCtx ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ fts5BufferGrow(&p->rc, &token, nToken+1);
+ assert( token.p!=0 || p->rc!=SQLITE_OK );
+ ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc,
+ SZ_FTS5TOKENDATAITER(1));
+
+ if( p->rc==SQLITE_OK ){
+
+ /* Fill in the token prefix to search for */
+ token.p[0] = FTS5_MAIN_PREFIX;
+ memcpy(&token.p[1], pToken, nToken);
+ token.n = nToken+1;
+
+ fts5VisitEntries(
+ p, 0, token.p, token.n, 1, prefixIterSetupTokendataCb, (void*)&ctx
+ );
+
+ fts5TokendataIterSortMap(p, ctx.pT);
+ }
+
+ if( p->rc==SQLITE_OK ){
+ pIter->pTokenDataIter = ctx.pT;
+ }else{
+ fts5TokendataIterDelete(ctx.pT);
+ }
+ fts5BufferFree(&token);
+
+ return fts5IndexReturn(p);
+}
+
+/*
** This is used by xInstToken() to access the token at offset iOff, column
** iCol of row iRowid. The token is returned via output variables *ppOut
** and *pnOut. The iterator passed as the first argument must be a tokendata=1
** iterator (pIter->pTokenDataIter!=0).
+**
+** pToken/nToken:
*/
static int sqlite3Fts5IterToken(
Fts5IndexIter *pIndexIter,
+ const char *pToken, int nToken,
i64 iRowid,
int iCol,
int iOff,
@@ -247709,13 +251775,22 @@ static int sqlite3Fts5IterToken(
){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
Fts5TokenDataIter *pT = pIter->pTokenDataIter;
- Fts5TokenDataMap *aMap = pT->aMap;
i64 iPos = (((i64)iCol)<<32) + iOff;
-
+ Fts5TokenDataMap *aMap = 0;
int i1 = 0;
- int i2 = pT->nMap;
+ int i2 = 0;
int iTest = 0;
+ assert( pT || (pToken && pIter->nSeg>0) );
+ if( pT==0 ){
+ int rc = fts5SetupPrefixIterTokendata(pIter, pToken, nToken);
+ if( rc!=SQLITE_OK ) return rc;
+ pT = pIter->pTokenDataIter;
+ }
+
+ i2 = pT->nMap;
+ aMap = pT->aMap;
+
while( i2>i1 ){
iTest = (i1 + i2) / 2;
@@ -247738,9 +251813,15 @@ static int sqlite3Fts5IterToken(
}
if( i2>i1 ){
- Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
- *ppOut = (const char*)pMap->aSeg[0].term.p+1;
- *pnOut = pMap->aSeg[0].term.n-1;
+ if( pIter->nSeg==0 ){
+ Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
+ *ppOut = (const char*)pMap->aSeg[0].term.p+1;
+ *pnOut = pMap->aSeg[0].term.n-1;
+ }else{
+ Fts5TokenDataMap *p = &aMap[iTest];
+ *ppOut = (const char*)&pT->terms.p[p->iIter];
+ *pnOut = aMap[iTest].nByte;
+ }
}
return SQLITE_OK;
@@ -247752,7 +251833,9 @@ static int sqlite3Fts5IterToken(
*/
static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- if( pIter && pIter->pTokenDataIter ){
+ if( pIter && pIter->pTokenDataIter
+ && (pIter->nSeg==0 || pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_FULL)
+ ){
pIter->pTokenDataIter->nMap = 0;
}
}
@@ -247772,17 +251855,30 @@ static int sqlite3Fts5IndexIterWriteTokendata(
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
Fts5TokenDataIter *pT = pIter->pTokenDataIter;
Fts5Index *p = pIter->pIndex;
- int ii;
+ i64 iPos = (((i64)iCol)<<32) + iOff;
assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
- assert( pIter->pTokenDataIter );
-
- for(ii=0; ii<pT->nIter; ii++){
- Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
- if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
- }
- if( ii<pT->nIter ){
- fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff);
+ assert( pIter->pTokenDataIter || pIter->nSeg>0 );
+ if( pIter->nSeg>0 ){
+ /* This is a prefix term iterator. */
+ if( pT==0 ){
+ pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc,
+ SZ_FTS5TOKENDATAITER(1));
+ pIter->pTokenDataIter = pT;
+ }
+ if( pT ){
+ fts5TokendataIterAppendMap(p, pT, pT->terms.n, nToken, iRowid, iPos);
+ fts5BufferAppendBlob(&p->rc, &pT->terms, nToken, (const u8*)pToken);
+ }
+ }else{
+ int ii;
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
+ if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
+ }
+ if( ii<pT->nIter ){
+ fts5TokendataIterAppendMap(p, pT, ii, 0, iRowid, iPos);
+ }
}
return fts5IndexReturn(p);
}
@@ -247792,11 +251888,9 @@ static int sqlite3Fts5IndexIterWriteTokendata(
*/
static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
if( pIndexIter ){
- Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- Fts5Index *pIndex = pIter->pIndex;
- fts5TokendataIterDelete(pIter->pTokenDataIter);
- fts5MultiIterFree(pIter);
- sqlite3Fts5IndexCloseReader(pIndex);
+ Fts5Index *pIndex = ((Fts5Iter*)pIndexIter)->pIndex;
+ fts5IterClose(pIndexIter);
+ fts5IndexReturn(pIndex);
}
}
@@ -248326,7 +252420,7 @@ static int fts5QueryCksum(
rc = sqlite3Fts5IterNext(pIter);
}
}
- sqlite3Fts5IterClose(pIter);
+ fts5IterClose(pIter);
*pCksum = cksum;
return rc;
@@ -248803,7 +252897,7 @@ static void fts5DecodeRowid(
#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
- int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid compenents */
+ int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid components */
fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno);
if( iSegid==0 ){
@@ -249049,7 +253143,7 @@ static void fts5DecodeFunction(
** buffer overreads even if the record is corrupt. */
n = sqlite3_value_bytes(apVal[1]);
aBlob = sqlite3_value_blob(apVal[1]);
- nSpace = n + FTS5_DATA_ZERO_PADDING;
+ nSpace = ((i64)n) + FTS5_DATA_ZERO_PADDING;
a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace);
if( a==0 ) goto decode_out;
if( n>0 ) memcpy(a, aBlob, n);
@@ -249335,7 +253429,7 @@ static int fts5structConnectMethod(
/*
** We must have a single struct=? constraint that will be passed through
-** into the xFilter method. If there is no valid stmt=? constraint,
+** into the xFilter method. If there is no valid struct=? constraint,
** then return an SQLITE_CONSTRAINT error.
*/
static int fts5structBestIndexMethod(
@@ -249677,9 +253771,19 @@ struct Fts5Global {
Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
Fts5Cursor *pCsr; /* First in list of all open cursors */
+ u32 aLocaleHdr[4];
};
/*
+** Size of header on fts5_locale() values. And macro to access a buffer
+** containing a copy of the header from an Fts5Config pointer.
+*/
+#define FTS5_LOCALE_HDR_SIZE ((int)sizeof( ((Fts5Global*)0)->aLocaleHdr ))
+#define FTS5_LOCALE_HDR(pConfig) ((const u8*)(pConfig->pGlobal->aLocaleHdr))
+
+#define FTS5_INSTTOKEN_SUBTYPE 73
+
+/*
** Each auxiliary function registered with the FTS5 module is represented
** by an object of the following type. All such objects are stored as part
** of the Fts5Global.pAux list.
@@ -249697,11 +253801,28 @@ struct Fts5Auxiliary {
** Each tokenizer module registered with the FTS5 module is represented
** by an object of the following type. All such objects are stored as part
** of the Fts5Global.pTok list.
+**
+** bV2Native:
+** True if the tokenizer was registered using xCreateTokenizer_v2(), false
+** for xCreateTokenizer(). If this variable is true, then x2 is populated
+** with the routines as supplied by the caller and x1 contains synthesized
+** wrapper routines. In this case the user-data pointer passed to
+** x1.xCreate should be a pointer to the Fts5TokenizerModule structure,
+** not a copy of pUserData.
+**
+** Of course, if bV2Native is false, then x1 contains the real routines and
+** x2 the synthesized ones. In this case a pointer to the Fts5TokenizerModule
+** object should be passed to x2.xCreate.
+**
+** The synthesized wrapper routines are necessary for xFindTokenizer(_v2)
+** calls.
*/
struct Fts5TokenizerModule {
char *zName; /* Name of tokenizer */
void *pUserData; /* User pointer passed to xCreate() */
- fts5_tokenizer x; /* Tokenizer functions */
+ int bV2Native; /* True if v2 native tokenizer */
+ fts5_tokenizer x1; /* Tokenizer functions */
+ fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
void (*xDestroy)(void*); /* Destructor function */
Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
};
@@ -249737,9 +253858,11 @@ struct Fts5Sorter {
i64 iRowid; /* Current rowid */
const u8 *aPoslist; /* Position lists for current row */
int nIdx; /* Number of entries in aIdx[] */
- int aIdx[1]; /* Offsets into aPoslist for current row */
+ int aIdx[FLEXARRAY]; /* Offsets into aPoslist for current row */
};
+/* Size (int bytes) of an Fts5Sorter object with N indexes */
+#define SZ_FTS5SORTER(N) (offsetof(Fts5Sorter,nIdx)+((N+2)/2)*sizeof(i64))
/*
** Virtual-table cursor object.
@@ -249789,7 +253912,7 @@ struct Fts5Cursor {
Fts5Auxiliary *pAux; /* Currently executing extension function */
Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
- /* Cache used by auxiliary functions xInst() and xInstCount() */
+ /* Cache used by auxiliary API functions xInst() and xInstCount() */
Fts5PoslistReader *aInstIter; /* One for each phrase */
int nInstAlloc; /* Size of aInst[] array (entries / 3) */
int nInstCount; /* Number of phrase instances */
@@ -249900,10 +254023,16 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
#endif
/*
-** Return true if pTab is a contentless table.
+** Return true if pTab is a contentless table. If parameter bIncludeUnindexed
+** is true, this includes contentless tables that store UNINDEXED columns
+** only.
*/
-static int fts5IsContentless(Fts5FullTable *pTab){
- return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
+static int fts5IsContentless(Fts5FullTable *pTab, int bIncludeUnindexed){
+ int eContent = pTab->p.pConfig->eContent;
+ return (
+ eContent==FTS5_CONTENT_NONE
+ || (bIncludeUnindexed && eContent==FTS5_CONTENT_UNINDEXED)
+ );
}
/*
@@ -249971,8 +254100,12 @@ static int fts5InitVtab(
assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
}
if( rc==SQLITE_OK ){
+ pConfig->pzErrmsg = pzErr;
pTab->p.pConfig = pConfig;
pTab->pGlobal = pGlobal;
+ if( bCreate || sqlite3Fts5TokenizerPreload(&pConfig->t) ){
+ rc = sqlite3Fts5LoadTokenizer(pConfig);
+ }
}
/* Open the index sub-system */
@@ -249994,11 +254127,7 @@ static int fts5InitVtab(
/* Load the initial configuration */
if( rc==SQLITE_OK ){
- assert( pConfig->pzErrmsg==0 );
- pConfig->pzErrmsg = pzErr;
- rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
- sqlite3Fts5IndexRollback(pTab->p.pIndex);
- pConfig->pzErrmsg = 0;
+ rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie-1);
}
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
@@ -250008,6 +254137,7 @@ static int fts5InitVtab(
rc = sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
}
+ if( pConfig ) pConfig->pzErrmsg = 0;
if( rc!=SQLITE_OK ){
fts5FreeVtab(pTab);
pTab = 0;
@@ -250075,10 +254205,10 @@ static int fts5UsePatternMatch(
){
assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB );
assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE );
- if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
+ if( pConfig->t.ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
return 1;
}
- if( pConfig->ePattern==FTS5_PATTERN_LIKE
+ if( pConfig->t.ePattern==FTS5_PATTERN_LIKE
&& (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB)
){
return 1;
@@ -250125,10 +254255,10 @@ static int fts5UsePatternMatch(
** 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:
+** If an unusable MATCH operator is present in the WHERE clause, then
+** SQLITE_CONSTRAINT is returned.
**
-** a) If an unusable MATCH operator is present in the WHERE clause, the
-** cost is unconditionally set to 1e50 (a really big number).
+** Costs are assigned as follows:
**
** a) If a MATCH operator is present, the cost depends on the other
** constraints also present. As follows:
@@ -250161,7 +254291,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
int bSeenEq = 0;
int bSeenGt = 0;
int bSeenLt = 0;
- int bSeenMatch = 0;
+ int nSeenMatch = 0;
int bSeenRank = 0;
@@ -250192,18 +254322,16 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
/* 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 );
+ ** unusable plan. Return SQLITE_CONSTRAINT. */
idxStr[iIdxStr] = 0;
- return SQLITE_OK;
+ return SQLITE_CONSTRAINT;
}else{
if( iCol==nCol+1 ){
if( bSeenRank ) continue;
idxStr[iIdxStr++] = 'r';
bSeenRank = 1;
- }else if( iCol>=0 ){
- bSeenMatch = 1;
+ }else{
+ nSeenMatch++;
idxStr[iIdxStr++] = 'M';
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]);
@@ -250220,6 +254348,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
idxStr += strlen(&idxStr[iIdxStr]);
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
assert( idxStr[iIdxStr]=='\0' );
+ nSeenMatch++;
}else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){
idxStr[iIdxStr++] = '=';
bSeenEq = 1;
@@ -250256,7 +254385,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
*/
if( pInfo->nOrderBy==1 ){
int iSort = pInfo->aOrderBy[0].iColumn;
- if( iSort==(pConfig->nCol+1) && bSeenMatch ){
+ if( iSort==(pConfig->nCol+1) && nSeenMatch>0 ){
idxFlags |= FTS5_BI_ORDER_RANK;
}else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){
idxFlags |= FTS5_BI_ORDER_ROWID;
@@ -250271,14 +254400,17 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
/* Calculate the estimated cost based on the flags set in idxFlags. */
if( bSeenEq ){
- pInfo->estimatedCost = bSeenMatch ? 100.0 : 10.0;
- if( bSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
+ pInfo->estimatedCost = nSeenMatch ? 1000.0 : 10.0;
+ if( nSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
}else if( bSeenLt && bSeenGt ){
- pInfo->estimatedCost = bSeenMatch ? 500.0 : 250000.0;
+ pInfo->estimatedCost = nSeenMatch ? 5000.0 : 250000.0;
}else if( bSeenLt || bSeenGt ){
- pInfo->estimatedCost = bSeenMatch ? 750.0 : 750000.0;
+ pInfo->estimatedCost = nSeenMatch ? 7500.0 : 750000.0;
}else{
- pInfo->estimatedCost = bSeenMatch ? 1000.0 : 1000000.0;
+ pInfo->estimatedCost = nSeenMatch ? 10000.0 : 1000000.0;
+ }
+ for(i=1; i<nSeenMatch; i++){
+ pInfo->estimatedCost *= 0.4;
}
pInfo->idxNum = idxFlags;
@@ -250554,6 +254686,7 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
}
}else{
rc = SQLITE_OK;
+ CsrFlagSet(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
}
break;
}
@@ -250583,7 +254716,7 @@ static int fts5PrepareStatement(
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));
+ sqlite3Fts5ConfigErrmsg(pConfig, "%s", sqlite3_errmsg(pConfig->db));
}
sqlite3_free(zSql);
}
@@ -250607,7 +254740,7 @@ static int fts5CursorFirstSorted(
const char *zRankArgs = pCsr->zRankArgs;
nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
- nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
+ nByte = SZ_FTS5SORTER(nPhrase);
pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte);
if( pSorter==0 ) return SQLITE_NOMEM;
memset(pSorter, 0, (size_t)nByte);
@@ -250808,6 +254941,145 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
}
/*
+** Set the error message on the virtual table passed as the first argument.
+*/
+static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
+ va_list ap; /* ... printf arguments */
+ va_start(ap, zFormat);
+ sqlite3_free(p->p.base.zErrMsg);
+ p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+}
+
+/*
+** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale
+** specified by pLocale/nLocale. The buffer indicated by pLocale must remain
+** valid until after the final call to sqlite3Fts5Tokenize() that will use
+** the locale.
+*/
+static void sqlite3Fts5SetLocale(
+ Fts5Config *pConfig,
+ const char *zLocale,
+ int nLocale
+){
+ Fts5TokenizerConfig *pT = &pConfig->t;
+ pT->pLocale = zLocale;
+ pT->nLocale = nLocale;
+}
+
+/*
+** Clear any locale configured by an earlier call to sqlite3Fts5SetLocale().
+*/
+static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){
+ sqlite3Fts5SetLocale(pConfig, 0, 0);
+}
+
+/*
+** Return true if the value passed as the only argument is an
+** fts5_locale() value.
+*/
+static int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal){
+ int ret = 0;
+ if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
+ /* Call sqlite3_value_bytes() after sqlite3_value_blob() in this case.
+ ** If the blob was created using zeroblob(), then sqlite3_value_blob()
+ ** may call malloc(). If this malloc() fails, then the values returned
+ ** by both value_blob() and value_bytes() will be 0. If value_bytes() were
+ ** called first, then the NULL pointer returned by value_blob() might
+ ** be dereferenced. */
+ const u8 *pBlob = sqlite3_value_blob(pVal);
+ int nBlob = sqlite3_value_bytes(pVal);
+ if( nBlob>FTS5_LOCALE_HDR_SIZE
+ && 0==memcmp(pBlob, FTS5_LOCALE_HDR(pConfig), FTS5_LOCALE_HDR_SIZE)
+ ){
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+/*
+** Value pVal is guaranteed to be an fts5_locale() value, according to
+** sqlite3Fts5IsLocaleValue(). This function extracts the text and locale
+** from the value and returns them separately.
+**
+** If successful, SQLITE_OK is returned and (*ppText) and (*ppLoc) set
+** to point to buffers containing the text and locale, as utf-8,
+** respectively. In this case output parameters (*pnText) and (*pnLoc) are
+** set to the sizes in bytes of these two buffers.
+**
+** Or, if an error occurs, then an SQLite error code is returned. The final
+** value of the four output parameters is undefined in this case.
+*/
+static int sqlite3Fts5DecodeLocaleValue(
+ sqlite3_value *pVal,
+ const char **ppText,
+ int *pnText,
+ const char **ppLoc,
+ int *pnLoc
+){
+ const char *p = sqlite3_value_blob(pVal);
+ int n = sqlite3_value_bytes(pVal);
+ int nLoc = 0;
+
+ assert( sqlite3_value_type(pVal)==SQLITE_BLOB );
+ assert( n>FTS5_LOCALE_HDR_SIZE );
+
+ for(nLoc=FTS5_LOCALE_HDR_SIZE; p[nLoc]; nLoc++){
+ if( nLoc==(n-1) ){
+ return SQLITE_MISMATCH;
+ }
+ }
+ *ppLoc = &p[FTS5_LOCALE_HDR_SIZE];
+ *pnLoc = nLoc - FTS5_LOCALE_HDR_SIZE;
+
+ *ppText = &p[nLoc+1];
+ *pnText = n - nLoc - 1;
+ return SQLITE_OK;
+}
+
+/*
+** Argument pVal is the text of a full-text search expression. It may or
+** may not have been wrapped by fts5_locale(). This function extracts
+** the text of the expression, and sets output variable (*pzText) to
+** point to a nul-terminated buffer containing the expression.
+**
+** If pVal was an fts5_locale() value, then sqlite3Fts5SetLocale() is called
+** to set the tokenizer to use the specified locale.
+**
+** If output variable (*pbFreeAndReset) is set to true, then the caller
+** is required to (a) call sqlite3Fts5ClearLocale() to reset the tokenizer
+** locale, and (b) call sqlite3_free() to free (*pzText).
+*/
+static int fts5ExtractExprText(
+ Fts5Config *pConfig, /* Fts5 configuration */
+ sqlite3_value *pVal, /* Value to extract expression text from */
+ char **pzText, /* OUT: nul-terminated buffer of text */
+ int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */
+){
+ int rc = SQLITE_OK;
+
+ if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ const char *pText = 0;
+ int nText = 0;
+ const char *pLoc = 0;
+ int nLoc = 0;
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, pText);
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ }
+ *pbFreeAndReset = 1;
+ }else{
+ *pzText = (char*)sqlite3_value_text(pVal);
+ *pbFreeAndReset = 0;
+ }
+
+ return rc;
+}
+
+
+/*
** This is the xFilter interface for the virtual table. See
** the virtual table xFilter method documentation for additional
** information.
@@ -250837,17 +255109,12 @@ static int fts5FilterMethod(
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
int iCol; /* Column on LHS of MATCH operator */
char **pzErrmsg = pConfig->pzErrmsg;
+ int bPrefixInsttoken = pConfig->bPrefixInsttoken;
int i;
int iIdxStr = 0;
Fts5Expr *pExpr = 0;
- if( pConfig->bLock ){
- pTab->p.base.zErrMsg = sqlite3_mprintf(
- "recursively defined fts5 content table"
- );
- return SQLITE_ERROR;
- }
-
+ assert( pConfig->bLock==0 );
if( pCsr->ePlan ){
fts5FreeCursorComponents(pCsr);
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
@@ -250871,8 +255138,17 @@ static int fts5FilterMethod(
pRank = apVal[i];
break;
case 'M': {
- const char *zText = (const char*)sqlite3_value_text(apVal[i]);
+ char *zText = 0;
+ int bFreeAndReset = 0;
+ int bInternal = 0;
+
+ rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset);
+ if( rc!=SQLITE_OK ) goto filter_out;
if( zText==0 ) zText = "";
+ if( sqlite3_value_subtype(apVal[i])==FTS5_INSTTOKEN_SUBTYPE ){
+ pConfig->bPrefixInsttoken = 1;
+ }
+
iCol = 0;
do{
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
@@ -250884,7 +255160,7 @@ static int fts5FilterMethod(
** 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;
+ bInternal = 1;
}else{
char **pzErr = &pTab->p.base.zErrMsg;
rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
@@ -250892,9 +255168,15 @@ static int fts5FilterMethod(
rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
pExpr = 0;
}
- if( rc!=SQLITE_OK ) goto filter_out;
}
+ if( bFreeAndReset ){
+ sqlite3_free(zText);
+ sqlite3Fts5ClearLocale(pConfig);
+ }
+
+ if( bInternal || rc!=SQLITE_OK ) goto filter_out;
+
break;
}
case 'L':
@@ -250982,9 +255264,7 @@ static int fts5FilterMethod(
}
}
}else if( pConfig->zContent==0 ){
- *pConfig->pzErrmsg = sqlite3_mprintf(
- "%s: table does not support scanning", pConfig->zName
- );
+ fts5SetVtabError(pTab,"%s: table does not support scanning",pConfig->zName);
rc = SQLITE_ERROR;
}else{
/* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
@@ -251008,6 +255288,7 @@ static int fts5FilterMethod(
filter_out:
sqlite3Fts5ExprFree(pExpr);
pConfig->pzErrmsg = pzErrmsg;
+ pConfig->bPrefixInsttoken = bPrefixInsttoken;
return rc;
}
@@ -251027,9 +255308,13 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){
assert( pCsr->ePlan==FTS5_PLAN_MATCH
|| pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
|| pCsr->ePlan==FTS5_PLAN_SOURCE
+ || pCsr->ePlan==FTS5_PLAN_SCAN
+ || pCsr->ePlan==FTS5_PLAN_ROWID
);
if( pCsr->pSorter ){
return pCsr->pSorter->iRowid;
+ }else if( pCsr->ePlan>=FTS5_PLAN_SCAN ){
+ return sqlite3_column_int64(pCsr->pStmt, 0);
}else{
return sqlite3Fts5ExprRowid(pCsr->pExpr);
}
@@ -251046,25 +255331,16 @@ static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
int ePlan = pCsr->ePlan;
assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
- switch( ePlan ){
- case FTS5_PLAN_SPECIAL:
- *pRowid = 0;
- break;
-
- case FTS5_PLAN_SOURCE:
- case FTS5_PLAN_MATCH:
- case FTS5_PLAN_SORTED_MATCH:
- *pRowid = fts5CursorRowid(pCsr);
- break;
-
- default:
- *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
- break;
+ if( ePlan==FTS5_PLAN_SPECIAL ){
+ *pRowid = 0;
+ }else{
+ *pRowid = fts5CursorRowid(pCsr);
}
return SQLITE_OK;
}
+
/*
** If the cursor requires seeking (bSeekRequired flag is set), seek it.
** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
@@ -251101,8 +255377,13 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
rc = sqlite3_reset(pCsr->pStmt);
if( rc==SQLITE_OK ){
rc = FTS5_CORRUPT;
+ fts5SetVtabError((Fts5FullTable*)pTab,
+ "fts5: missing row %lld from content table %s",
+ fts5CursorRowid(pCsr),
+ pTab->pConfig->zContent
+ );
}else if( pTab->pConfig->pzErrmsg ){
- *pTab->pConfig->pzErrmsg = sqlite3_mprintf(
+ fts5SetVtabError((Fts5FullTable*)pTab,
"%s", sqlite3_errmsg(pTab->pConfig->db)
);
}
@@ -251111,14 +255392,6 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
return rc;
}
-static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
- va_list ap; /* ... printf arguments */
- va_start(ap, zFormat);
- assert( p->p.base.zErrMsg==0 );
- p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
- va_end(ap);
-}
-
/*
** This function is called to handle an FTS INSERT command. In other words,
** an INSERT statement of the form:
@@ -251156,7 +255429,7 @@ static int fts5SpecialInsert(
}
bLoadConfig = 1;
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
- if( pConfig->eContent==FTS5_CONTENT_NONE ){
+ if( fts5IsContentless(pTab, 1) ){
fts5SetVtabError(pTab,
"'rebuild' may not be used with a contentless fts5 table"
);
@@ -251212,7 +255485,7 @@ static int fts5SpecialDelete(
int eType1 = sqlite3_value_type(apVal[1]);
if( eType1==SQLITE_INTEGER ){
sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2], 0);
}
return rc;
}
@@ -251225,7 +255498,7 @@ static void fts5StorageInsert(
){
int rc = *pRc;
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
+ rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, 0, apVal, piRowid);
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
@@ -251234,6 +255507,67 @@ static void fts5StorageInsert(
}
/*
+**
+** This function is called when the user attempts an UPDATE on a contentless
+** table. Parameter bRowidModified is true if the UPDATE statement modifies
+** the rowid value. Parameter apVal[] contains the new values for each user
+** defined column of the fts5 table. pConfig is the configuration object of the
+** table being updated (guaranteed to be contentless). The contentless_delete=1
+** and contentless_unindexed=1 options may or may not be set.
+**
+** This function returns SQLITE_OK if the UPDATE can go ahead, or an SQLite
+** error code if it cannot. In this case an error message is also loaded into
+** pConfig. Output parameter (*pbContent) is set to true if the caller should
+** update the %_content table only - not the FTS index or any other shadow
+** table. This occurs when an UPDATE modifies only UNINDEXED columns of the
+** table.
+**
+** An UPDATE may proceed if:
+**
+** * The only columns modified are UNINDEXED columns, or
+**
+** * The contentless_delete=1 option was specified and all of the indexed
+** columns (not a subset) have been modified.
+*/
+static int fts5ContentlessUpdate(
+ Fts5Config *pConfig,
+ sqlite3_value **apVal,
+ int bRowidModified,
+ int *pbContent
+){
+ int ii;
+ int bSeenIndex = 0; /* Have seen modified indexed column */
+ int bSeenIndexNC = 0; /* Have seen unmodified indexed column */
+ int rc = SQLITE_OK;
+
+ for(ii=0; ii<pConfig->nCol; ii++){
+ if( pConfig->abUnindexed[ii]==0 ){
+ if( sqlite3_value_nochange(apVal[ii]) ){
+ bSeenIndexNC++;
+ }else{
+ bSeenIndex++;
+ }
+ }
+ }
+
+ if( bSeenIndex==0 && bRowidModified==0 ){
+ *pbContent = 1;
+ }else{
+ if( bSeenIndexNC || pConfig->bContentlessDelete==0 ){
+ rc = SQLITE_ERROR;
+ sqlite3Fts5ConfigErrmsg(pConfig,
+ (pConfig->bContentlessDelete ?
+ "%s a subset of columns on fts5 contentless-delete table: %s" :
+ "%s contentless fts5 table: %s")
+ , "cannot UPDATE", pConfig->zName
+ );
+ }
+ }
+
+ return rc;
+}
+
+/*
** 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.
@@ -251257,7 +255591,6 @@ static int fts5UpdateMethod(
Fts5Config *pConfig = pTab->p.pConfig;
int eType0; /* value_type() of apVal[0] */
int rc = SQLITE_OK; /* Return code */
- int bUpdateOrDelete = 0;
/* A transaction must be open when this is called. */
assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
@@ -251269,7 +255602,7 @@ static int fts5UpdateMethod(
);
assert( pTab->p.pConfig->pzErrmsg==0 );
if( pConfig->pgsz==0 ){
- rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie);
if( rc!=SQLITE_OK ) return rc;
}
@@ -251294,7 +255627,6 @@ static int fts5UpdateMethod(
rc = SQLITE_ERROR;
}else{
rc = fts5SpecialDelete(pTab, apVal);
- bUpdateOrDelete = 1;
}
}else{
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
@@ -251319,88 +255651,104 @@ static int fts5UpdateMethod(
assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
assert( nArg!=1 || eType0==SQLITE_INTEGER );
- /* Filter out attempts to run UPDATE or DELETE on contentless tables.
- ** This is not suported. Except - they are both supported if the CREATE
- ** VIRTUAL TABLE statement contained "contentless_delete=1". */
- if( eType0==SQLITE_INTEGER
- && pConfig->eContent==FTS5_CONTENT_NONE
- && pConfig->bContentlessDelete==0
- ){
- pTab->p.base.zErrMsg = sqlite3_mprintf(
- "cannot %s contentless fts5 table: %s",
- (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
- );
- rc = SQLITE_ERROR;
- }
-
/* DELETE */
- else if( nArg==1 ){
- i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
- bUpdateOrDelete = 1;
+ if( nArg==1 ){
+ /* It is only possible to DELETE from a contentless table if the
+ ** contentless_delete=1 flag is set. */
+ if( fts5IsContentless(pTab, 1) && pConfig->bContentlessDelete==0 ){
+ fts5SetVtabError(pTab,
+ "cannot DELETE from contentless fts5 table: %s", pConfig->zName
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
+ }
}
/* INSERT or UPDATE */
else{
int eType1 = sqlite3_value_numeric_type(apVal[1]);
- if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
- rc = SQLITE_MISMATCH;
+ /* It is an error to write an fts5_locale() value to a table without
+ ** the locale=1 option. */
+ if( pConfig->bLocale==0 ){
+ int ii;
+ for(ii=0; ii<pConfig->nCol; ii++){
+ sqlite3_value *pVal = apVal[ii+2];
+ if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ fts5SetVtabError(pTab, "fts5_locale() requires locale=1");
+ rc = SQLITE_MISMATCH;
+ goto update_out;
+ }
+ }
}
- else if( eType0!=SQLITE_INTEGER ){
+ if( eType0!=SQLITE_INTEGER ){
/* An INSERT statement. If the conflict-mode is 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);
- bUpdateOrDelete = 1;
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
/* UPDATE */
else{
+ Fts5Storage *pStorage = pTab->pStorage;
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
- if( eType1==SQLITE_INTEGER && iOld!=iNew ){
+ int bContent = 0; /* Content only update */
+
+ /* If this is a contentless table (including contentless_unindexed=1
+ ** tables), check if the UPDATE may proceed. */
+ if( fts5IsContentless(pTab, 1) ){
+ rc = fts5ContentlessUpdate(pConfig, &apVal[2], iOld!=iNew, &bContent);
+ if( rc!=SQLITE_OK ) goto update_out;
+ }
+
+ if( eType1!=SQLITE_INTEGER ){
+ rc = SQLITE_MISMATCH;
+ }else if( iOld!=iNew ){
+ assert( bContent==0 );
if( eConflict==SQLITE_REPLACE ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ rc = sqlite3Fts5StorageDelete(pStorage, iNew, 0, 0);
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}else{
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
+ rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5StorageContentInsert(pStorage, 0, apVal, pRowid);
+ }
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 0);
}
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
+ rc = sqlite3Fts5StorageIndexInsert(pStorage, apVal, *pRowid);
}
}
+ }else if( bContent ){
+ /* This occurs when an UPDATE on a contentless table affects *only*
+ ** UNINDEXED columns. This is a no-op for contentless_unindexed=0
+ ** tables, or a write to the %_content table only for =1 tables. */
+ assert( fts5IsContentless(pTab, 1) );
+ rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5StorageContentInsert(pStorage, 1, apVal, pRowid);
+ }
}else{
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
- bUpdateOrDelete = 1;
+ sqlite3Fts5StorageReleaseDeleteRow(pStorage);
}
}
}
- if( rc==SQLITE_OK
- && bUpdateOrDelete
- && pConfig->bSecureDelete
- && pConfig->iVersion==FTS5_CURRENT_VERSION
- ){
- rc = sqlite3Fts5StorageConfigValue(
- pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
- );
- if( rc==SQLITE_OK ){
- pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
- }
- }
-
+ update_out:
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -251422,9 +255770,11 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
** Implementation of xBegin() method.
*/
static int fts5BeginMethod(sqlite3_vtab *pVtab){
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
- fts5NewTransaction((Fts5FullTable*)pVtab);
- return SQLITE_OK;
+ int rc = fts5NewTransaction((Fts5FullTable*)pVtab);
+ if( rc==SQLITE_OK ){
+ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
+ }
+ return rc;
}
/*
@@ -251447,6 +255797,7 @@ static int fts5RollbackMethod(sqlite3_vtab *pVtab){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
rc = sqlite3Fts5StorageRollback(pTab->pStorage);
+ pTab->p.pConfig->pgsz = 0;
return rc;
}
@@ -251478,17 +255829,40 @@ static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
}
-static int fts5ApiTokenize(
+/*
+** Implementation of xTokenize_v2() API.
+*/
+static int fts5ApiTokenize_v2(
Fts5Context *pCtx,
const char *pText, int nText,
+ const char *pLoc, int nLoc,
void *pUserData,
int (*xToken)(void*, int, const char*, int, int, int)
){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- return sqlite3Fts5Tokenize(
- pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
+ int rc = SQLITE_OK;
+
+ sqlite3Fts5SetLocale(pTab->pConfig, pLoc, nLoc);
+ rc = sqlite3Fts5Tokenize(pTab->pConfig,
+ FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
);
+ sqlite3Fts5SetLocale(pTab->pConfig, 0, 0);
+
+ return rc;
+}
+
+/*
+** Implementation of xTokenize() API. This is just xTokenize_v2() with NULL/0
+** passed as the locale.
+*/
+static int fts5ApiTokenize(
+ Fts5Context *pCtx,
+ const char *pText, int nText,
+ void *pUserData,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ return fts5ApiTokenize_v2(pCtx, pText, nText, 0, 0, pUserData, xToken);
}
static int fts5ApiPhraseCount(Fts5Context *pCtx){
@@ -251501,6 +255875,49 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
}
+/*
+** Argument pStmt is an SQL statement of the type used by Fts5Cursor. This
+** function extracts the text value of column iCol of the current row.
+** Additionally, if there is an associated locale, it invokes
+** sqlite3Fts5SetLocale() to configure the tokenizer. In all cases the caller
+** should invoke sqlite3Fts5ClearLocale() to clear the locale at some point
+** after this function returns.
+**
+** If successful, (*ppText) is set to point to a buffer containing the text
+** value as utf-8 and SQLITE_OK returned. (*pnText) is set to the size of that
+** buffer in bytes. It is not guaranteed to be nul-terminated. If an error
+** occurs, an SQLite error code is returned. The final values of the two
+** output parameters are undefined in this case.
+*/
+static int fts5TextFromStmt(
+ Fts5Config *pConfig,
+ sqlite3_stmt *pStmt,
+ int iCol,
+ const char **ppText,
+ int *pnText
+){
+ sqlite3_value *pVal = sqlite3_column_value(pStmt, iCol+1);
+ const char *pLoc = 0;
+ int nLoc = 0;
+ int rc = SQLITE_OK;
+
+ if( pConfig->bLocale
+ && pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, ppText, pnText, &pLoc, &nLoc);
+ }else{
+ *ppText = (const char*)sqlite3_value_text(pVal);
+ *pnText = sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale && pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ pLoc = (const char*)sqlite3_column_text(pStmt, iCol+1+pConfig->nCol);
+ nLoc = sqlite3_column_bytes(pStmt, iCol+1+pConfig->nCol);
+ }
+ }
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ return rc;
+}
+
static int fts5ApiColumnText(
Fts5Context *pCtx,
int iCol,
@@ -251510,28 +255927,35 @@ static int fts5ApiColumnText(
int rc = SQLITE_OK;
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
if( iCol<0 || iCol>=pTab->pConfig->nCol ){
rc = SQLITE_RANGE;
- }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
- || pCsr->ePlan==FTS5_PLAN_SPECIAL
- ){
+ }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab), 0) ){
*pz = 0;
*pn = 0;
}else{
rc = fts5SeekCursor(pCsr, 0);
if( rc==SQLITE_OK ){
- *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
- *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
+ rc = fts5TextFromStmt(pTab->pConfig, pCsr->pStmt, iCol, pz, pn);
+ sqlite3Fts5ClearLocale(pTab->pConfig);
}
}
return rc;
}
+/*
+** This is called by various API functions - xInst, xPhraseFirst,
+** xPhraseFirstColumn etc. - to obtain the position list for phrase iPhrase
+** of the current row. This function works for both detail=full tables (in
+** which case the position-list was read from the fts index) or for other
+** detail= modes if the row content is available.
+*/
static int fts5CsrPoslist(
- Fts5Cursor *pCsr,
- int iPhrase,
- const u8 **pa,
- int *pn
+ Fts5Cursor *pCsr, /* Fts5 cursor object */
+ int iPhrase, /* Phrase to find position list for */
+ const u8 **pa, /* OUT: Pointer to position list buffer */
+ int *pn /* OUT: Size of (*pa) in bytes */
){
Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
int rc = SQLITE_OK;
@@ -251539,20 +255963,32 @@ static int fts5CsrPoslist(
if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
rc = SQLITE_RANGE;
+ }else if( pConfig->eDetail!=FTS5_DETAIL_FULL
+ && fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
+ ){
+ *pa = 0;
+ *pn = 0;
+ return SQLITE_OK;
}else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5PoslistPopulator *aPopulator;
int i;
+
aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
if( aPopulator==0 ) rc = SQLITE_NOMEM;
+ if( rc==SQLITE_OK ){
+ rc = fts5SeekCursor(pCsr, 0);
+ }
for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
- int n; const char *z;
- rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
+ const char *z = 0;
+ int n = 0;
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ExprPopulatePoslists(
pConfig, pCsr->pExpr, aPopulator, i, z, n
);
}
+ sqlite3Fts5ClearLocale(pConfig);
}
sqlite3_free(aPopulator);
@@ -251577,7 +256013,6 @@ static int fts5CsrPoslist(
*pn = 0;
}
-
return rc;
}
@@ -251646,7 +256081,8 @@ 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 ){
+ assert( aInst[1]>=0 );
+ if( aInst[1]>=nCol ){
rc = FTS5_CORRUPT;
break;
}
@@ -251724,7 +256160,7 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
if( pConfig->bColumnsize ){
i64 iRowid = fts5CursorRowid(pCsr);
rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
- }else if( pConfig->zContent==0 ){
+ }else if( !pConfig->zContent || pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
int i;
for(i=0; i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i]==0 ){
@@ -251733,17 +256169,19 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
}
}else{
int i;
+ rc = fts5SeekCursor(pCsr, 0);
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
if( pConfig->abUnindexed[i]==0 ){
- const char *z; int n;
- void *p = (void*)(&pCsr->aColumnSize[i]);
+ const char *z = 0;
+ int n = 0;
pCsr->aColumnSize[i] = 0;
- rc = fts5ApiColumnText(pCtx, i, &z, &n);
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5Tokenize(
- pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
+ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX,
+ z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb
);
}
+ sqlite3Fts5ClearLocale(pConfig);
}
}
}
@@ -251823,11 +256261,10 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
}
static void fts5ApiPhraseNext(
- Fts5Context *pUnused,
+ Fts5Context *pCtx,
Fts5PhraseIter *pIter,
int *piCol, int *piOff
){
- UNUSED_PARAM(pUnused);
if( pIter->a>=pIter->b ){
*piCol = -1;
*piOff = -1;
@@ -251835,8 +256272,12 @@ static void fts5ApiPhraseNext(
int iVal;
pIter->a += fts5GetVarint32(pIter->a, iVal);
if( iVal==1 ){
+ /* Avoid returning a (*piCol) value that is too large for the table,
+ ** even if the position-list is corrupt. The caller might not be
+ ** expecting it. */
+ int nCol = ((Fts5Table*)(((Fts5Cursor*)pCtx)->base.pVtab))->pConfig->nCol;
pIter->a += fts5GetVarint32(pIter->a, iVal);
- *piCol = iVal;
+ *piCol = (iVal>=nCol ? nCol-1 : iVal);
*piOff = 0;
pIter->a += fts5GetVarint32(pIter->a, iVal);
}
@@ -251986,8 +256427,48 @@ static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
);
+/*
+** The xColumnLocale() API.
+*/
+static int fts5ApiColumnLocale(
+ Fts5Context *pCtx,
+ int iCol,
+ const char **pzLocale,
+ int *pnLocale
+){
+ int rc = SQLITE_OK;
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
+
+ *pzLocale = 0;
+ *pnLocale = 0;
+
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
+ if( iCol<0 || iCol>=pConfig->nCol ){
+ rc = SQLITE_RANGE;
+ }else if(
+ pConfig->abUnindexed[iCol]==0
+ && 0==fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
+ && pConfig->bLocale
+ ){
+ rc = fts5SeekCursor(pCsr, 0);
+ if( rc==SQLITE_OK ){
+ const char *zDummy = 0;
+ int nDummy = 0;
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &zDummy, &nDummy);
+ if( rc==SQLITE_OK ){
+ *pzLocale = pConfig->t.pLocale;
+ *pnLocale = pConfig->t.nLocale;
+ }
+ sqlite3Fts5ClearLocale(pConfig);
+ }
+ }
+
+ return rc;
+}
+
static const Fts5ExtensionApi sFts5Api = {
- 3, /* iVersion */
+ 4, /* iVersion */
fts5ApiUserData,
fts5ApiColumnCount,
fts5ApiRowCount,
@@ -252008,7 +256489,9 @@ static const Fts5ExtensionApi sFts5Api = {
fts5ApiPhraseFirstColumn,
fts5ApiPhraseNextColumn,
fts5ApiQueryToken,
- fts5ApiInstToken
+ fts5ApiInstToken,
+ fts5ApiColumnLocale,
+ fts5ApiTokenize_v2
};
/*
@@ -252059,6 +256542,7 @@ static void fts5ApiInvoke(
sqlite3_value **argv
){
assert( pCsr->pAux==0 );
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
pCsr->pAux = pAux;
pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
pCsr->pAux = 0;
@@ -252072,6 +256556,21 @@ static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
return pCsr;
}
+/*
+** Parameter zFmt is a printf() style formatting string. This function
+** formats it using the trailing arguments and returns the result as
+** an error message to the context passed as the first argument.
+*/
+static void fts5ResultError(sqlite3_context *pCtx, const char *zFmt, ...){
+ char *zErr = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zErr = sqlite3_vmprintf(zFmt, ap);
+ sqlite3_result_error(pCtx, zErr, -1);
+ sqlite3_free(zErr);
+ va_end(ap);
+}
+
static void fts5ApiCallback(
sqlite3_context *context,
int argc,
@@ -252087,12 +256586,13 @@ static void fts5ApiCallback(
iCsrId = sqlite3_value_int64(argv[0]);
pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
- if( pCsr==0 || pCsr->ePlan==0 ){
- char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
- sqlite3_result_error(context, zErr, -1);
- sqlite3_free(zErr);
+ if( pCsr==0 || (pCsr->ePlan==0 || pCsr->ePlan==FTS5_PLAN_SPECIAL) ){
+ fts5ResultError(context, "no such cursor: %lld", iCsrId);
}else{
+ sqlite3_vtab *pTab = pCsr->base.pVtab;
fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
+ sqlite3_free(pTab->zErrMsg);
+ pTab->zErrMsg = 0;
}
}
@@ -252210,8 +256710,8 @@ static int fts5ColumnMethod(
** auxiliary function. */
sqlite3_result_int64(pCtx, pCsr->iCsrId);
}else if( iCol==pConfig->nCol+1 ){
-
/* The value of the "rank" column. */
+
if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
fts5PoslistBlob(pCtx, pCsr);
}else if(
@@ -252222,20 +256722,32 @@ static int fts5ColumnMethod(
fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
}
}
- }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));
+ }else{
+ if( !sqlite3_vtab_nochange(pCtx) && pConfig->eContent!=FTS5_CONTENT_NONE ){
+ pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
+ rc = fts5SeekCursor(pCsr, 1);
+ if( rc==SQLITE_OK ){
+ sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
+ if( pConfig->bLocale
+ && pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ const char *z = 0;
+ int n = 0;
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &z, &n);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_text(pCtx, z, n, SQLITE_TRANSIENT);
+ }
+ sqlite3Fts5ClearLocale(pConfig);
+ }else{
+ sqlite3_result_value(pCtx, pVal);
+ }
+ }
+
+ pConfig->pzErrmsg = 0;
}
- pConfig->pzErrmsg = 0;
- }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){
- char *zErr = sqlite3_mprintf("cannot UPDATE a subset of "
- "columns on fts5 contentless-delete table: %s", pConfig->zName
- );
- sqlite3_result_error(pCtx, zErr, -1);
- sqlite3_free(zErr);
}
+
return rc;
}
@@ -252375,47 +256887,210 @@ static int fts5CreateAux(
}
/*
-** Register a new tokenizer. This is the implementation of the
-** fts5_api.xCreateTokenizer() method.
+** This function is used by xCreateTokenizer_v2() and xCreateTokenizer().
+** It allocates and partially populates a new Fts5TokenizerModule object.
+** The new object is already linked into the Fts5Global context before
+** returning.
+**
+** If successful, SQLITE_OK is returned and a pointer to the new
+** Fts5TokenizerModule object returned via output parameter (*ppNew). All
+** that is required is for the caller to fill in the methods in
+** Fts5TokenizerModule.x1 and x2, and to set Fts5TokenizerModule.bV2Native
+** as appropriate.
+**
+** If an error occurs, an SQLite error code is returned and the final value
+** of (*ppNew) undefined.
*/
-static int fts5CreateTokenizer(
- fts5_api *pApi, /* Global context (one per db handle) */
+static int fts5NewTokenizerModule(
+ Fts5Global *pGlobal, /* Global context (one per db handle) */
const char *zName, /* Name of new function */
void *pUserData, /* User data for aux. function */
- fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
- void(*xDestroy)(void*) /* Destructor for pUserData */
+ void(*xDestroy)(void*), /* Destructor for pUserData */
+ Fts5TokenizerModule **ppNew
){
- Fts5Global *pGlobal = (Fts5Global*)pApi;
- Fts5TokenizerModule *pNew;
- sqlite3_int64 nName; /* Size of zName and its \0 terminator */
- sqlite3_int64 nByte; /* Bytes of space to allocate */
int rc = SQLITE_OK;
+ Fts5TokenizerModule *pNew;
+ sqlite3_int64 nName; /* Size of zName and its \0 terminator */
+ sqlite3_int64 nByte; /* Bytes of space to allocate */
nName = strlen(zName) + 1;
nByte = sizeof(Fts5TokenizerModule) + nName;
- pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte);
+ *ppNew = pNew = (Fts5TokenizerModule*)sqlite3Fts5MallocZero(&rc, nByte);
if( pNew ){
- memset(pNew, 0, (size_t)nByte);
pNew->zName = (char*)&pNew[1];
memcpy(pNew->zName, zName, nName);
pNew->pUserData = pUserData;
- pNew->x = *pTokenizer;
pNew->xDestroy = xDestroy;
pNew->pNext = pGlobal->pTok;
pGlobal->pTok = pNew;
if( pNew->pNext==0 ){
pGlobal->pDfltTok = pNew;
}
+ }
+
+ return rc;
+}
+
+/*
+** An instance of this type is used as the Fts5Tokenizer object for
+** wrapper tokenizers - those that provide access to a v1 tokenizer via
+** the fts5_tokenizer_v2 API, and those that provide access to a v2 tokenizer
+** via the fts5_tokenizer API.
+*/
+typedef struct Fts5VtoVTokenizer Fts5VtoVTokenizer;
+struct Fts5VtoVTokenizer {
+ int bV2Native; /* True if v2 native tokenizer */
+ fts5_tokenizer x1; /* Tokenizer functions */
+ fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
+ Fts5Tokenizer *pReal;
+};
+
+/*
+** Create a wrapper tokenizer. The context argument pCtx points to the
+** Fts5TokenizerModule object.
+*/
+static int fts5VtoVCreate(
+ void *pCtx,
+ const char **azArg,
+ int nArg,
+ Fts5Tokenizer **ppOut
+){
+ Fts5TokenizerModule *pMod = (Fts5TokenizerModule*)pCtx;
+ Fts5VtoVTokenizer *pNew = 0;
+ int rc = SQLITE_OK;
+
+ pNew = (Fts5VtoVTokenizer*)sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
+ if( rc==SQLITE_OK ){
+ pNew->x1 = pMod->x1;
+ pNew->x2 = pMod->x2;
+ pNew->bV2Native = pMod->bV2Native;
+ if( pMod->bV2Native ){
+ rc = pMod->x2.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
+ }else{
+ rc = pMod->x1.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pNew);
+ pNew = 0;
+ }
+ }
+
+ *ppOut = (Fts5Tokenizer*)pNew;
+ return rc;
+}
+
+/*
+** Delete an Fts5VtoVTokenizer wrapper tokenizer.
+*/
+static void fts5VtoVDelete(Fts5Tokenizer *pTok){
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
+ if( p ){
+ if( p->bV2Native ){
+ p->x2.xDelete(p->pReal);
+ }else{
+ p->x1.xDelete(p->pReal);
+ }
+ sqlite3_free(p);
+ }
+}
+
+
+/*
+** xTokenizer method for a wrapper tokenizer that offers the v1 interface
+** (no support for locales).
+*/
+static int fts5V1toV2Tokenize(
+ Fts5Tokenizer *pTok,
+ void *pCtx, int flags,
+ const char *pText, int nText,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
+ assert( p->bV2Native );
+ return p->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken);
+}
+
+/*
+** xTokenizer method for a wrapper tokenizer that offers the v2 interface
+** (with locale support).
+*/
+static int fts5V2toV1Tokenize(
+ Fts5Tokenizer *pTok,
+ void *pCtx, int flags,
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
+ assert( p->bV2Native==0 );
+ UNUSED_PARAM2(pLocale,nLocale);
+ return p->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken);
+}
+
+/*
+** Register a new tokenizer. This is the implementation of the
+** fts5_api.xCreateTokenizer_v2() method.
+*/
+static int fts5CreateTokenizer_v2(
+ fts5_api *pApi, /* Global context (one per db handle) */
+ const char *zName, /* Name of new function */
+ void *pUserData, /* User data for aux. function */
+ fts5_tokenizer_v2 *pTokenizer, /* Tokenizer implementation */
+ void(*xDestroy)(void*) /* Destructor for pUserData */
+){
+ Fts5Global *pGlobal = (Fts5Global*)pApi;
+ int rc = SQLITE_OK;
+
+ if( pTokenizer->iVersion>2 ){
+ rc = SQLITE_ERROR;
}else{
- rc = SQLITE_NOMEM;
+ Fts5TokenizerModule *pNew = 0;
+ rc = fts5NewTokenizerModule(pGlobal, zName, pUserData, xDestroy, &pNew);
+ if( pNew ){
+ pNew->x2 = *pTokenizer;
+ pNew->bV2Native = 1;
+ pNew->x1.xCreate = fts5VtoVCreate;
+ pNew->x1.xTokenize = fts5V1toV2Tokenize;
+ pNew->x1.xDelete = fts5VtoVDelete;
+ }
}
return rc;
}
+/*
+** The fts5_api.xCreateTokenizer() method.
+*/
+static int fts5CreateTokenizer(
+ fts5_api *pApi, /* Global context (one per db handle) */
+ const char *zName, /* Name of new function */
+ void *pUserData, /* User data for aux. function */
+ fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
+ void(*xDestroy)(void*) /* Destructor for pUserData */
+){
+ Fts5TokenizerModule *pNew = 0;
+ int rc = SQLITE_OK;
+
+ rc = fts5NewTokenizerModule(
+ (Fts5Global*)pApi, zName, pUserData, xDestroy, &pNew
+ );
+ if( pNew ){
+ pNew->x1 = *pTokenizer;
+ pNew->x2.xCreate = fts5VtoVCreate;
+ pNew->x2.xTokenize = fts5V2toV1Tokenize;
+ pNew->x2.xDelete = fts5VtoVDelete;
+ }
+ return rc;
+}
+
+/*
+** Search the global context passed as the first argument for a tokenizer
+** module named zName. If found, return a pointer to the Fts5TokenizerModule
+** object. Otherwise, return NULL.
+*/
static Fts5TokenizerModule *fts5LocateTokenizer(
- Fts5Global *pGlobal,
- const char *zName
+ Fts5Global *pGlobal, /* Global (one per db handle) object */
+ const char *zName /* Name of tokenizer module to find */
){
Fts5TokenizerModule *pMod = 0;
@@ -252432,6 +257107,36 @@ static Fts5TokenizerModule *fts5LocateTokenizer(
/*
** Find a tokenizer. This is the implementation of the
+** fts5_api.xFindTokenizer_v2() method.
+*/
+static int fts5FindTokenizer_v2(
+ fts5_api *pApi, /* Global context (one per db handle) */
+ const char *zName, /* Name of tokenizer */
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer /* Populate this object */
+){
+ int rc = SQLITE_OK;
+ Fts5TokenizerModule *pMod;
+
+ pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
+ if( pMod ){
+ if( pMod->bV2Native ){
+ *ppUserData = pMod->pUserData;
+ }else{
+ *ppUserData = (void*)pMod;
+ }
+ *ppTokenizer = &pMod->x2;
+ }else{
+ *ppTokenizer = 0;
+ *ppUserData = 0;
+ rc = SQLITE_ERROR;
+ }
+
+ return rc;
+}
+
+/*
+** Find a tokenizer. This is the implementation of the
** fts5_api.xFindTokenizer() method.
*/
static int fts5FindTokenizer(
@@ -252445,55 +257150,75 @@ static int fts5FindTokenizer(
pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
if( pMod ){
- *pTokenizer = pMod->x;
- *ppUserData = pMod->pUserData;
+ if( pMod->bV2Native==0 ){
+ *ppUserData = pMod->pUserData;
+ }else{
+ *ppUserData = (void*)pMod;
+ }
+ *pTokenizer = pMod->x1;
}else{
- memset(pTokenizer, 0, sizeof(fts5_tokenizer));
+ memset(pTokenizer, 0, sizeof(*pTokenizer));
+ *ppUserData = 0;
rc = SQLITE_ERROR;
}
return rc;
}
-static int sqlite3Fts5GetTokenizer(
- Fts5Global *pGlobal,
- const char **azArg,
- int nArg,
- Fts5Config *pConfig,
- char **pzErr
-){
- Fts5TokenizerModule *pMod;
+/*
+** Attempt to instantiate the tokenizer.
+*/
+static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){
+ const char **azArg = pConfig->t.azArg;
+ const int nArg = pConfig->t.nArg;
+ Fts5TokenizerModule *pMod = 0;
int rc = SQLITE_OK;
- pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
+ pMod = fts5LocateTokenizer(pConfig->pGlobal, nArg==0 ? 0 : azArg[0]);
if( pMod==0 ){
assert( nArg>0 );
rc = SQLITE_ERROR;
- if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
+ sqlite3Fts5ConfigErrmsg(pConfig, "no such tokenizer: %s", azArg[0]);
}else{
- rc = pMod->x.xCreate(
- pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
+ int (*xCreate)(void*, const char**, int, Fts5Tokenizer**) = 0;
+ if( pMod->bV2Native ){
+ xCreate = pMod->x2.xCreate;
+ pConfig->t.pApi2 = &pMod->x2;
+ }else{
+ pConfig->t.pApi1 = &pMod->x1;
+ xCreate = pMod->x1.xCreate;
+ }
+
+ rc = xCreate(pMod->pUserData,
+ (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok
);
- pConfig->pTokApi = &pMod->x;
+
if( rc!=SQLITE_OK ){
- if( pzErr && rc!=SQLITE_NOMEM ){
- *pzErr = sqlite3_mprintf("error in tokenizer constructor");
+ if( rc!=SQLITE_NOMEM ){
+ sqlite3Fts5ConfigErrmsg(pConfig, "error in tokenizer constructor");
}
- }else{
- pConfig->ePattern = sqlite3Fts5TokenizerPattern(
- pMod->x.xCreate, pConfig->pTok
+ }else if( pMod->bV2Native==0 ){
+ pConfig->t.ePattern = sqlite3Fts5TokenizerPattern(
+ pMod->x1.xCreate, pConfig->t.pTok
);
}
}
if( rc!=SQLITE_OK ){
- pConfig->pTokApi = 0;
- pConfig->pTok = 0;
+ pConfig->t.pApi1 = 0;
+ pConfig->t.pApi2 = 0;
+ pConfig->t.pTok = 0;
}
return rc;
}
+
+/*
+** xDestroy callback passed to sqlite3_create_module(). This is invoked
+** when the db handle is being closed. Free memory associated with
+** tokenizers and aux functions registered with this db handle.
+*/
static void fts5ModuleDestroy(void *pCtx){
Fts5TokenizerModule *pTok, *pNextTok;
Fts5Auxiliary *pAux, *pNextAux;
@@ -252514,6 +257239,10 @@ static void fts5ModuleDestroy(void *pCtx){
sqlite3_free(pGlobal);
}
+/*
+** Implementation of the fts5() function used by clients to obtain the
+** API pointer.
+*/
static void fts5Fts5Func(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
@@ -252537,7 +257266,82 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2025-06-28 14:00:48 2af157d77fb1304a74176eaee7fbc7c7e932d946bf25325e9c26c91db19e3079", -1, SQLITE_TRANSIENT);
+}
+
+/*
+** Implementation of fts5_locale(LOCALE, TEXT) function.
+**
+** If parameter LOCALE is NULL, or a zero-length string, then a copy of
+** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as
+** text, and the value returned is a blob consisting of:
+**
+** * The 4 bytes 0x00, 0xE0, 0xB2, 0xEb (FTS5_LOCALE_HEADER).
+** * The LOCALE, as utf-8 text, followed by
+** * 0x00, followed by
+** * The TEXT, as utf-8 text.
+**
+** There is no final nul-terminator following the TEXT value.
+*/
+static void fts5LocaleFunc(
+ sqlite3_context *pCtx, /* Function call context */
+ int nArg, /* Number of args */
+ sqlite3_value **apArg /* Function arguments */
+){
+ const char *zLocale = 0;
+ int nLocale = 0;
+ const char *zText = 0;
+ int nText = 0;
+
+ assert( nArg==2 );
+ UNUSED_PARAM(nArg);
+
+ zLocale = (const char*)sqlite3_value_text(apArg[0]);
+ nLocale = sqlite3_value_bytes(apArg[0]);
+
+ zText = (const char*)sqlite3_value_text(apArg[1]);
+ nText = sqlite3_value_bytes(apArg[1]);
+
+ if( zLocale==0 || zLocale[0]=='\0' ){
+ sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT);
+ }else{
+ Fts5Global *p = (Fts5Global*)sqlite3_user_data(pCtx);
+ u8 *pBlob = 0;
+ u8 *pCsr = 0;
+ int nBlob = 0;
+
+ nBlob = FTS5_LOCALE_HDR_SIZE + nLocale + 1 + nText;
+ pBlob = (u8*)sqlite3_malloc(nBlob);
+ if( pBlob==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+
+ pCsr = pBlob;
+ memcpy(pCsr, (const u8*)p->aLocaleHdr, FTS5_LOCALE_HDR_SIZE);
+ pCsr += FTS5_LOCALE_HDR_SIZE;
+ memcpy(pCsr, zLocale, nLocale);
+ pCsr += nLocale;
+ (*pCsr++) = 0x00;
+ if( zText ) memcpy(pCsr, zText, nText);
+ assert( &pCsr[nText]==&pBlob[nBlob] );
+
+ sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free);
+ }
+}
+
+/*
+** Implementation of fts5_insttoken() function.
+*/
+static void fts5InsttokenFunc(
+ sqlite3_context *pCtx, /* Function call context */
+ int nArg, /* Number of args */
+ sqlite3_value **apArg /* Function arguments */
+){
+ assert( nArg==1 );
+ (void)nArg;
+ sqlite3_result_value(pCtx, apArg[0]);
+ sqlite3_result_subtype(pCtx, FTS5_INSTTOKEN_SUBTYPE);
}
/*
@@ -252632,10 +257436,22 @@ static int fts5Init(sqlite3 *db){
void *p = (void*)pGlobal;
memset(pGlobal, 0, sizeof(Fts5Global));
pGlobal->db = db;
- pGlobal->api.iVersion = 2;
+ pGlobal->api.iVersion = 3;
pGlobal->api.xCreateFunction = fts5CreateAux;
pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
pGlobal->api.xFindTokenizer = fts5FindTokenizer;
+ pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2;
+ pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2;
+
+ /* Initialize pGlobal->aLocaleHdr[] to a 128-bit pseudo-random vector.
+ ** The constants below were generated randomly. */
+ sqlite3_randomness(sizeof(pGlobal->aLocaleHdr), pGlobal->aLocaleHdr);
+ pGlobal->aLocaleHdr[0] ^= 0xF924976D;
+ pGlobal->aLocaleHdr[1] ^= 0x16596E13;
+ pGlobal->aLocaleHdr[2] ^= 0x7C80BEAA;
+ pGlobal->aLocaleHdr[3] ^= 0x9B03A67F;
+ assert( sizeof(pGlobal->aLocaleHdr)==16 );
+
rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
@@ -252654,6 +257470,20 @@ static int fts5Init(sqlite3 *db){
p, fts5SourceIdFunc, 0, 0
);
}
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(
+ db, "fts5_locale", 2,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE|SQLITE_SUBTYPE,
+ p, fts5LocaleFunc, 0, 0
+ );
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(
+ db, "fts5_insttoken", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
+ p, fts5InsttokenFunc, 0, 0
+ );
+ }
}
/* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
@@ -252661,8 +257491,8 @@ static int fts5Init(sqlite3 *db){
** its entry point to enable the matchinfo() demo. */
#ifdef SQLITE_FTS5_ENABLE_TEST_MI
if( rc==SQLITE_OK ){
- extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
- rc = sqlite3Fts5TestRegisterMatchinfo(db);
+ extern int sqlite3Fts5TestRegisterMatchinfoAPI(fts5_api*);
+ rc = sqlite3Fts5TestRegisterMatchinfoAPI(&pGlobal->api);
}
#endif
@@ -252728,13 +257558,40 @@ SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3 *db){
/* #include "fts5Int.h" */
+/*
+** pSavedRow:
+** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it
+** does a by-rowid lookup to retrieve a single row from the %_content
+** table or equivalent external-content table/view.
+**
+** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original
+** values for a row being UPDATEd. In that case, the SQL statement is
+** not reset and pSavedRow is set to point at it. This is so that the
+** insert operation that follows the delete may access the original
+** row values for any new values for which sqlite3_value_nochange() returns
+** true. i.e. if the user executes:
+**
+** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1);
+** ...
+** UPDATE fts SET a=?, b=? WHERE rowid=?;
+**
+** then the value passed to the xUpdate() method of this table as the
+** new.c value is an sqlite3_value_nochange() value. So in this case it
+** must be read from the saved row stored in Fts5Storage.pSavedRow.
+**
+** This is necessary - using sqlite3_value_nochange() instead of just having
+** SQLite pass the original value back via xUpdate() - so as not to discard
+** any locale information associated with such values.
+**
+*/
struct Fts5Storage {
Fts5Config *pConfig;
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 */
- sqlite3_stmt *aStmt[11];
+ sqlite3_stmt *pSavedRow;
+ sqlite3_stmt *aStmt[12];
};
@@ -252748,14 +257605,15 @@ struct Fts5Storage {
# error "FTS5_STMT_LOOKUP mismatch"
#endif
-#define FTS5_STMT_INSERT_CONTENT 3
-#define FTS5_STMT_REPLACE_CONTENT 4
-#define FTS5_STMT_DELETE_CONTENT 5
-#define FTS5_STMT_REPLACE_DOCSIZE 6
-#define FTS5_STMT_DELETE_DOCSIZE 7
-#define FTS5_STMT_LOOKUP_DOCSIZE 8
-#define FTS5_STMT_REPLACE_CONFIG 9
-#define FTS5_STMT_SCAN 10
+#define FTS5_STMT_LOOKUP2 3
+#define FTS5_STMT_INSERT_CONTENT 4
+#define FTS5_STMT_REPLACE_CONTENT 5
+#define FTS5_STMT_DELETE_CONTENT 6
+#define FTS5_STMT_REPLACE_DOCSIZE 7
+#define FTS5_STMT_DELETE_DOCSIZE 8
+#define FTS5_STMT_LOOKUP_DOCSIZE 9
+#define FTS5_STMT_REPLACE_CONFIG 10
+#define FTS5_STMT_SCAN 11
/*
** Prepare the two insert statements - Fts5Storage.pInsertContent and
@@ -252785,6 +257643,7 @@ static int fts5StorageGetStmt(
"SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
"SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
"SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
+ "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */
"INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
"REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
@@ -252800,6 +257659,8 @@ static int fts5StorageGetStmt(
Fts5Config *pC = p->pConfig;
char *zSql = 0;
+ assert( ArraySize(azStmt)==ArraySize(p->aStmt) );
+
switch( eStmt ){
case FTS5_STMT_SCAN:
zSql = sqlite3_mprintf(azStmt[eStmt],
@@ -252816,6 +257677,7 @@ static int fts5StorageGetStmt(
break;
case FTS5_STMT_LOOKUP:
+ case FTS5_STMT_LOOKUP2:
zSql = sqlite3_mprintf(azStmt[eStmt],
pC->zContentExprlist, pC->zContent, pC->zContentRowid
);
@@ -252823,20 +257685,35 @@ static int fts5StorageGetStmt(
case FTS5_STMT_INSERT_CONTENT:
case FTS5_STMT_REPLACE_CONTENT: {
- int nCol = pC->nCol + 1;
- char *zBind;
+ char *zBind = 0;
int i;
- zBind = sqlite3_malloc64(1 + nCol*2);
- if( zBind ){
- for(i=0; i<nCol; i++){
- zBind[i*2] = '?';
- zBind[i*2 + 1] = ',';
+ assert( pC->eContent==FTS5_CONTENT_NORMAL
+ || pC->eContent==FTS5_CONTENT_UNINDEXED
+ );
+
+ /* Add bindings for the "c*" columns - those that store the actual
+ ** table content. If eContent==NORMAL, then there is one binding
+ ** for each column. Or, if eContent==UNINDEXED, then there are only
+ ** bindings for the UNINDEXED columns. */
+ for(i=0; rc==SQLITE_OK && i<(pC->nCol+1); i++){
+ if( !i || pC->eContent==FTS5_CONTENT_NORMAL || pC->abUnindexed[i-1] ){
+ zBind = sqlite3Fts5Mprintf(&rc, "%z%s?%d", zBind, zBind?",":"",i+1);
+ }
+ }
+
+ /* Add bindings for any "l*" columns. Only non-UNINDEXED columns
+ ** require these. */
+ if( pC->bLocale && pC->eContent==FTS5_CONTENT_NORMAL ){
+ for(i=0; rc==SQLITE_OK && i<pC->nCol; i++){
+ if( pC->abUnindexed[i]==0 ){
+ zBind = sqlite3Fts5Mprintf(&rc, "%z,?%d", zBind, pC->nCol+i+2);
+ }
}
- zBind[i*2-1] = '\0';
- zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
- sqlite3_free(zBind);
}
+
+ zSql = sqlite3Fts5Mprintf(&rc, azStmt[eStmt], pC->zDb, pC->zName,zBind);
+ sqlite3_free(zBind);
break;
}
@@ -252862,7 +257739,7 @@ static int fts5StorageGetStmt(
rc = SQLITE_NOMEM;
}else{
int f = SQLITE_PREPARE_PERSISTENT;
- if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
+ if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB;
p->pConfig->bLock++;
rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
p->pConfig->bLock--;
@@ -252870,6 +257747,11 @@ static int fts5StorageGetStmt(
if( rc!=SQLITE_OK && pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
}
+ if( rc==SQLITE_ERROR && eStmt>FTS5_STMT_LOOKUP2 && eStmt<FTS5_STMT_SCAN ){
+ /* One of the internal tables - not the %_content table - is missing.
+ ** This counts as a corrupted table. */
+ rc = SQLITE_CORRUPT;
+ }
}
}
@@ -253022,9 +257904,11 @@ static int sqlite3Fts5StorageOpen(
p->pIndex = pIndex;
if( bCreate ){
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
int nDefn = 32 + pConfig->nCol*10;
- char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
+ char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20);
if( zDefn==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -253033,8 +257917,20 @@ static int sqlite3Fts5StorageOpen(
sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
iOff = (int)strlen(zDefn);
for(i=0; i<pConfig->nCol; i++){
- sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
- iOff += (int)strlen(&zDefn[iOff]);
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->abUnindexed[i]
+ ){
+ sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
+ iOff += (int)strlen(&zDefn[iOff]);
+ }
+ }
+ if( pConfig->bLocale ){
+ for(i=0; i<pConfig->nCol; i++){
+ if( pConfig->abUnindexed[i]==0 ){
+ sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i);
+ iOff += (int)strlen(&zDefn[iOff]);
+ }
+ }
}
rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
}
@@ -253112,14 +258008,48 @@ static int fts5StorageInsertCallback(
}
/*
+** This function is used as part of an UPDATE statement that modifies the
+** rowid of a row. In that case, this function is called first to set
+** Fts5Storage.pSavedRow to point to a statement that may be used to
+** access the original values of the row being deleted - iDel.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+** It is not considered an error if row iDel does not exist. In this case
+** pSavedRow is not set and SQLITE_OK returned.
+*/
+static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){
+ int rc = SQLITE_OK;
+ sqlite3_stmt *pSeek = 0;
+
+ assert( p->pSavedRow==0 );
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pSeek, 1, iDel);
+ if( sqlite3_step(pSeek)!=SQLITE_ROW ){
+ rc = sqlite3_reset(pSeek);
+ }else{
+ p->pSavedRow = pSeek;
+ }
+ }
+
+ return rc;
+}
+
+/*
** If a row with rowid iDel is present in the %_content table, add the
** delete-markers to the FTS index necessary to delete it. Do not actually
** remove the %_content row at this time though.
+**
+** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left
+** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access
+** the original values of the row being deleted. This is used by UPDATE
+** statements.
*/
static int fts5StorageDeleteFromIndex(
Fts5Storage *p,
i64 iDel,
- sqlite3_value **apVal
+ sqlite3_value **apVal,
+ int bSaveRow /* True to set pSavedRow */
){
Fts5Config *pConfig = p->pConfig;
sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
@@ -253128,12 +258058,21 @@ static int fts5StorageDeleteFromIndex(
int iCol;
Fts5InsertCtx ctx;
+ assert( bSaveRow==0 || apVal==0 );
+ assert( bSaveRow==0 || bSaveRow==1 );
+ assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 );
+
if( apVal==0 ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
- if( rc!=SQLITE_OK ) return rc;
- sqlite3_bind_int64(pSeek, 1, iDel);
- if( sqlite3_step(pSeek)!=SQLITE_ROW ){
- return sqlite3_reset(pSeek);
+ if( p->pSavedRow && bSaveRow ){
+ pSeek = p->pSavedRow;
+ p->pSavedRow = 0;
+ }else{
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0);
+ if( rc!=SQLITE_OK ) return rc;
+ sqlite3_bind_int64(pSeek, 1, iDel);
+ if( sqlite3_step(pSeek)!=SQLITE_ROW ){
+ return sqlite3_reset(pSeek);
+ }
}
}
@@ -253141,27 +258080,56 @@ static int fts5StorageDeleteFromIndex(
ctx.iCol = -1;
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
if( pConfig->abUnindexed[iCol-1]==0 ){
- const char *zText;
- int nText;
+ sqlite3_value *pVal = 0;
+ sqlite3_value *pFree = 0;
+ const char *pText = 0;
+ int nText = 0;
+ const char *pLoc = 0;
+ int nLoc = 0;
+
assert( pSeek==0 || apVal==0 );
assert( pSeek!=0 || apVal!=0 );
if( pSeek ){
- zText = (const char*)sqlite3_column_text(pSeek, iCol);
- nText = sqlite3_column_bytes(pSeek, iCol);
- }else if( ALWAYS(apVal) ){
- zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
- nText = sqlite3_value_bytes(apVal[iCol-1]);
+ pVal = sqlite3_column_value(pSeek, iCol);
}else{
- continue;
+ pVal = apVal[iCol-1];
}
- ctx.szCol = 0;
- rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
- zText, nText, (void*)&ctx, fts5StorageInsertCallback
- );
- p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
- if( p->aTotalSize[iCol-1]<0 ){
- rc = FTS5_CORRUPT;
+
+ if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ }else{
+ if( sqlite3_value_type(pVal)!=SQLITE_TEXT ){
+ /* Make a copy of the value to work with. This is because the call
+ ** to sqlite3_value_text() below forces the type of the value to
+ ** SQLITE_TEXT, and we may need to use it again later. */
+ pFree = pVal = sqlite3_value_dup(pVal);
+ if( pVal==0 ){
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pText = (const char*)sqlite3_value_text(pVal);
+ nText = sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale && pSeek ){
+ pLoc = (const char*)sqlite3_column_text(pSeek, iCol+pConfig->nCol);
+ nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
+ }
+ }
}
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ ctx.szCol = 0;
+ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
+ pText, nText, (void*)&ctx, fts5StorageInsertCallback
+ );
+ p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
+ if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){
+ rc = FTS5_CORRUPT;
+ }
+ sqlite3Fts5ClearLocale(pConfig);
+ }
+ sqlite3_value_free(pFree);
}
}
if( rc==SQLITE_OK && p->nTotalRow<1 ){
@@ -253170,12 +258138,30 @@ static int fts5StorageDeleteFromIndex(
p->nTotalRow--;
}
- rc2 = sqlite3_reset(pSeek);
- if( rc==SQLITE_OK ) rc = rc2;
+ if( rc==SQLITE_OK && bSaveRow ){
+ assert( p->pSavedRow==0 );
+ p->pSavedRow = pSeek;
+ }else{
+ rc2 = sqlite3_reset(pSeek);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
return rc;
}
/*
+** Reset any saved statement pSavedRow. Zero pSavedRow as well. This
+** should be called by the xUpdate() method of the fts5 table before
+** returning from any operation that may have set Fts5Storage.pSavedRow.
+*/
+static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){
+ assert( pStorage->pSavedRow==0
+ || pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2]
+ );
+ sqlite3_reset(pStorage->pSavedRow);
+ pStorage->pSavedRow = 0;
+}
+
+/*
** This function is called to process a DELETE on a contentless_delete=1
** table. It adds the tombstone required to delete the entry with rowid
** iDel. If successful, SQLITE_OK is returned. Or, if an error occurs,
@@ -253187,7 +258173,9 @@ static int fts5StorageContentlessDelete(Fts5Storage *p, i64 iDel){
int rc = SQLITE_OK;
assert( p->pConfig->bContentlessDelete );
- assert( p->pConfig->eContent==FTS5_CONTENT_NONE );
+ assert( p->pConfig->eContent==FTS5_CONTENT_NONE
+ || p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ );
/* Look up the origin of the document in the %_docsize table. Store
** this in stack variable iOrigin. */
@@ -253231,12 +258219,12 @@ static int fts5StorageInsertDocsize(
rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
sqlite3_bind_int64(pReplace, 3, iOrigin);
}
- if( rc==SQLITE_OK ){
- sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
- sqlite3_step(pReplace);
- rc = sqlite3_reset(pReplace);
- sqlite3_bind_null(pReplace, 2);
- }
+ }
+ if( rc==SQLITE_OK ){
+ 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;
@@ -253290,7 +258278,12 @@ static int fts5StorageSaveTotals(Fts5Storage *p){
/*
** Remove a row from the FTS table.
*/
-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
+static int sqlite3Fts5StorageDelete(
+ Fts5Storage *p, /* Storage object */
+ i64 iDel, /* Rowid to delete from table */
+ sqlite3_value **apVal, /* Optional - values to remove from index */
+ int bSaveRow /* If true, set pSavedRow for deleted row */
+){
Fts5Config *pConfig = p->pConfig;
int rc;
sqlite3_stmt *pDel = 0;
@@ -253306,8 +258299,14 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **ap
if( rc==SQLITE_OK ){
if( p->pConfig->bContentlessDelete ){
rc = fts5StorageContentlessDelete(p, iDel);
+ if( rc==SQLITE_OK
+ && bSaveRow
+ && p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
+ rc = sqlite3Fts5StorageFindDeleteRow(p, iDel);
+ }
}else{
- rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
+ rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
}
}
@@ -253322,7 +258321,9 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **ap
}
/* Delete the %_content record */
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
}
@@ -253354,8 +258355,13 @@ static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
);
if( rc==SQLITE_OK && pConfig->bColumnsize ){
rc = fts5ExecPrintf(pConfig->db, 0,
- "DELETE FROM %Q.'%q_docsize';",
- pConfig->zDb, pConfig->zName
+ "DELETE FROM %Q.'%q_docsize';", pConfig->zDb, pConfig->zName
+ );
+ }
+
+ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
+ rc = fts5ExecPrintf(pConfig->db, 0,
+ "DELETE FROM %Q.'%q_content';", pConfig->zDb, pConfig->zName
);
}
@@ -253396,14 +258402,36 @@ 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 ){
- 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,
- zText, nText,
- (void*)&ctx,
- fts5StorageInsertCallback
- );
+ int nText = 0; /* Size of pText in bytes */
+ const char *pText = 0; /* Pointer to buffer containing text value */
+ int nLoc = 0; /* Size of pLoc in bytes */
+ const char *pLoc = 0; /* Pointer to buffer containing text value */
+
+ sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1);
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ }else{
+ pText = (const char*)sqlite3_value_text(pVal);
+ nText = sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale ){
+ int iCol = ctx.iCol + 1 + pConfig->nCol;
+ pLoc = (const char*)sqlite3_column_text(pScan, iCol);
+ nLoc = sqlite3_column_bytes(pScan, iCol);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ rc = sqlite3Fts5Tokenize(pConfig,
+ FTS5_TOKENIZE_DOCUMENT,
+ pText, nText,
+ (void*)&ctx,
+ fts5StorageInsertCallback
+ );
+ sqlite3Fts5ClearLocale(pConfig);
+ }
}
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
@@ -253469,6 +258497,7 @@ static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
*/
static int sqlite3Fts5StorageContentInsert(
Fts5Storage *p,
+ int bReplace, /* True to use REPLACE instead of INSERT */
sqlite3_value **apVal,
i64 *piRowid
){
@@ -253476,7 +258505,9 @@ static int sqlite3Fts5StorageContentInsert(
int rc = SQLITE_OK;
/* Insert the new row into the %_content table. */
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent!=FTS5_CONTENT_NORMAL
+ && pConfig->eContent!=FTS5_CONTENT_UNINDEXED
+ ){
if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
*piRowid = sqlite3_value_int64(apVal[1]);
}else{
@@ -253485,9 +258516,52 @@ static int sqlite3Fts5StorageContentInsert(
}else{
sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
int i; /* Counter variable */
- rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
- for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
- rc = sqlite3_bind_value(pInsert, i, apVal[i]);
+
+ assert( FTS5_STMT_INSERT_CONTENT+1==FTS5_STMT_REPLACE_CONTENT );
+ assert( bReplace==0 || bReplace==1 );
+ rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT+bReplace, &pInsert, 0);
+ if( pInsert ) sqlite3_clear_bindings(pInsert);
+
+ /* Bind the rowid value */
+ sqlite3_bind_value(pInsert, 1, apVal[1]);
+
+ /* Loop through values for user-defined columns. i=2 is the leftmost
+ ** user-defined column. As is column 1 of pSavedRow. */
+ for(i=2; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
+ int bUnindexed = pConfig->abUnindexed[i-2];
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL || bUnindexed ){
+ sqlite3_value *pVal = apVal[i];
+
+ if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
+ /* This is an UPDATE statement, and user-defined column (i-2) was not
+ ** modified. Retrieve the value from Fts5Storage.pSavedRow. */
+ pVal = sqlite3_column_value(p->pSavedRow, i-1);
+ if( pConfig->bLocale && bUnindexed==0 ){
+ sqlite3_bind_value(pInsert, pConfig->nCol + i,
+ sqlite3_column_value(p->pSavedRow, pConfig->nCol + i - 1)
+ );
+ }
+ }else if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ const char *pText = 0;
+ const char *pLoc = 0;
+ int nText = 0;
+ int nLoc = 0;
+ assert( pConfig->bLocale );
+
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
+ if( bUnindexed==0 ){
+ int iLoc = pConfig->nCol + i;
+ sqlite3_bind_text(pInsert, iLoc, pLoc, nLoc, SQLITE_TRANSIENT);
+ }
+ }
+
+ continue;
+ }
+
+ rc = sqlite3_bind_value(pInsert, i, pVal);
+ }
}
if( rc==SQLITE_OK ){
sqlite3_step(pInsert);
@@ -253522,14 +258596,38 @@ 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 ){
- 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,
- zText, nText,
- (void*)&ctx,
- fts5StorageInsertCallback
- );
+ int nText = 0; /* Size of pText in bytes */
+ const char *pText = 0; /* Pointer to buffer containing text value */
+ int nLoc = 0; /* Size of pText in bytes */
+ const char *pLoc = 0; /* Pointer to buffer containing text value */
+
+ sqlite3_value *pVal = apVal[ctx.iCol+2];
+ if( p->pSavedRow && sqlite3_value_nochange(pVal) ){
+ pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
+ int iCol = ctx.iCol + 1 + pConfig->nCol;
+ pLoc = (const char*)sqlite3_column_text(p->pSavedRow, iCol);
+ nLoc = sqlite3_column_bytes(p->pSavedRow, iCol);
+ }
+ }else{
+ pVal = apVal[ctx.iCol+2];
+ }
+
+ if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ }else{
+ pText = (const char*)sqlite3_value_text(pVal);
+ nText = sqlite3_value_bytes(pVal);
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ rc = sqlite3Fts5Tokenize(pConfig,
+ FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx,
+ fts5StorageInsertCallback
+ );
+ sqlite3Fts5ClearLocale(pConfig);
+ }
}
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
@@ -253693,29 +258791,61 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
- if( pConfig->abUnindexed[i] ) continue;
- ctx.iCol = i;
- ctx.szCol = 0;
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
- }
- if( rc==SQLITE_OK ){
- 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,
- zText, nText,
- (void*)&ctx,
- fts5StorageIntegrityCallback
- );
- }
- if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
- rc = FTS5_CORRUPT;
- }
- aTotalSize[i] += ctx.szCol;
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- sqlite3Fts5TermsetFree(ctx.pTermset);
- ctx.pTermset = 0;
+ if( pConfig->abUnindexed[i]==0 ){
+ const char *pText = 0;
+ int nText = 0;
+ const char *pLoc = 0;
+ int nLoc = 0;
+ sqlite3_value *pVal = sqlite3_column_value(pScan, i+1);
+
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ rc = sqlite3Fts5DecodeLocaleValue(
+ pVal, &pText, &nText, &pLoc, &nLoc
+ );
+ }else{
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
+ int iCol = i + 1 + pConfig->nCol;
+ pLoc = (const char*)sqlite3_column_text(pScan, iCol);
+ nLoc = sqlite3_column_bytes(pScan, iCol);
+ }
+ pText = (const char*)sqlite3_value_text(pVal);
+ nText = sqlite3_value_bytes(pVal);
+ }
+
+ ctx.iCol = i;
+ ctx.szCol = 0;
+
+ if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
+ rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ rc = sqlite3Fts5Tokenize(pConfig,
+ FTS5_TOKENIZE_DOCUMENT,
+ pText, nText,
+ (void*)&ctx,
+ fts5StorageIntegrityCallback
+ );
+ sqlite3Fts5ClearLocale(pConfig);
+ }
+
+ /* If this is not a columnsize=0 database, check that the number
+ ** of tokens in the value matches the aColSize[] value read from
+ ** the %_docsize table. */
+ if( rc==SQLITE_OK
+ && pConfig->bColumnsize
+ && ctx.szCol!=aColSize[i]
+ ){
+ rc = FTS5_CORRUPT;
+ }
+ aTotalSize[i] += ctx.szCol;
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
+ sqlite3Fts5TermsetFree(ctx.pTermset);
+ ctx.pTermset = 0;
+ }
}
}
sqlite3Fts5TermsetFree(ctx.pTermset);
@@ -254022,7 +259152,7 @@ static int fts5AsciiCreate(
int i;
memset(p, 0, sizeof(AsciiTokenizer));
memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
- for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
fts5AsciiAddExceptions(p, zArg, 1);
@@ -254033,7 +259163,6 @@ static int fts5AsciiCreate(
rc = SQLITE_ERROR;
}
}
- if( rc==SQLITE_OK && i<nArg ) rc = SQLITE_ERROR;
if( rc!=SQLITE_OK ){
fts5AsciiDelete((Fts5Tokenizer*)p);
p = 0;
@@ -254142,7 +259271,7 @@ static const unsigned char sqlite3Utf8Trans1[] = {
c = *(zIn++); \
if( c>=0xc0 ){ \
c = sqlite3Utf8Trans1[c-0xc0]; \
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
+ while( zIn<zTerm && (*zIn & 0xc0)==0x80 ){ \
c = (c<<6) + (0x3f & *(zIn++)); \
} \
if( c<0x80 \
@@ -254325,7 +259454,7 @@ static int fts5UnicodeCreate(
}
/* Search for a "categories" argument */
- for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
if( 0==sqlite3_stricmp(azArg[i], "categories") ){
zCat = azArg[i+1];
}
@@ -254334,7 +259463,7 @@ static int fts5UnicodeCreate(
rc = unicodeSetCategories(p, zCat);
}
- for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
+ 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[0]!='2') || zArg[1] ){
@@ -254359,8 +259488,6 @@ static int fts5UnicodeCreate(
rc = SQLITE_ERROR;
}
}
- if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
-
}else{
rc = SQLITE_NOMEM;
}
@@ -254499,7 +259626,7 @@ static int fts5UnicodeTokenize(
typedef struct PorterTokenizer PorterTokenizer;
struct PorterTokenizer {
- fts5_tokenizer tokenizer; /* Parent tokenizer module */
+ fts5_tokenizer_v2 tokenizer_v2; /* Parent tokenizer module */
Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */
char aBuf[FTS5_PORTER_MAX_TOKEN + 64];
};
@@ -254511,7 +259638,7 @@ static void fts5PorterDelete(Fts5Tokenizer *pTok){
if( pTok ){
PorterTokenizer *p = (PorterTokenizer*)pTok;
if( p->pTokenizer ){
- p->tokenizer.xDelete(p->pTokenizer);
+ p->tokenizer_v2.xDelete(p->pTokenizer);
}
sqlite3_free(p);
}
@@ -254530,6 +259657,7 @@ static int fts5PorterCreate(
PorterTokenizer *pRet;
void *pUserdata = 0;
const char *zBase = "unicode61";
+ fts5_tokenizer_v2 *pV2 = 0;
if( nArg>0 ){
zBase = azArg[0];
@@ -254538,14 +259666,15 @@ static int fts5PorterCreate(
pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
if( pRet ){
memset(pRet, 0, sizeof(PorterTokenizer));
- rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer);
+ rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2);
}else{
rc = SQLITE_NOMEM;
}
if( rc==SQLITE_OK ){
int nArg2 = (nArg>0 ? nArg-1 : 0);
- const char **azArg2 = (nArg2 ? &azArg[1] : 0);
- rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer);
+ const char **az2 = (nArg2 ? &azArg[1] : 0);
+ memcpy(&pRet->tokenizer_v2, pV2, sizeof(fts5_tokenizer_v2));
+ rc = pRet->tokenizer_v2.xCreate(pUserdata, az2, nArg2, &pRet->pTokenizer);
}
if( rc!=SQLITE_OK ){
@@ -255196,6 +260325,7 @@ static int fts5PorterTokenize(
void *pCtx,
int flags,
const char *pText, int nText,
+ const char *pLoc, int nLoc,
int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
){
PorterTokenizer *p = (PorterTokenizer*)pTokenizer;
@@ -255203,8 +260333,8 @@ static int fts5PorterTokenize(
sCtx.xToken = xToken;
sCtx.pCtx = pCtx;
sCtx.aBuf = p->aBuf;
- return p->tokenizer.xTokenize(
- p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb
+ return p->tokenizer_v2.xTokenize(
+ p->pTokenizer, (void*)&sCtx, flags, pText, nText, pLoc, nLoc, fts5PorterCb
);
}
@@ -255234,41 +260364,46 @@ static int fts5TriCreate(
Fts5Tokenizer **ppOut
){
int rc = SQLITE_OK;
- TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
+ TrigramTokenizer *pNew = 0;
UNUSED_PARAM(pUnused);
- if( pNew==0 ){
- rc = SQLITE_NOMEM;
+ if( nArg%2 ){
+ rc = SQLITE_ERROR;
}else{
int i;
- pNew->bFold = 1;
- pNew->iFoldParam = 0;
- for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
- const char *zArg = azArg[i+1];
- if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
- if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
- rc = SQLITE_ERROR;
+ pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pNew->bFold = 1;
+ pNew->iFoldParam = 0;
+
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+ const char *zArg = azArg[i+1];
+ if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
+ rc = SQLITE_ERROR;
+ }else{
+ pNew->bFold = (zArg[0]=='0');
+ }
+ }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
+ if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
+ rc = SQLITE_ERROR;
+ }else{
+ pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
+ }
}else{
- pNew->bFold = (zArg[0]=='0');
- }
- }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
- if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
rc = SQLITE_ERROR;
- }else{
- pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
}
- }else{
- rc = SQLITE_ERROR;
}
- }
- if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
- if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
- rc = SQLITE_ERROR;
- }
+ if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
+ rc = SQLITE_ERROR;
+ }
- if( rc!=SQLITE_OK ){
- fts5TriDelete((Fts5Tokenizer*)pNew);
- pNew = 0;
+ if( rc!=SQLITE_OK ){
+ fts5TriDelete((Fts5Tokenizer*)pNew);
+ pNew = 0;
+ }
}
}
*ppOut = (Fts5Tokenizer*)pNew;
@@ -255291,8 +260426,8 @@ static int fts5TriTokenize(
char *zOut = aBuf;
int ii;
const unsigned char *zIn = (const unsigned char*)pText;
- const unsigned char *zEof = &zIn[nText];
- u32 iCode;
+ const unsigned char *zEof = (zIn ? &zIn[nText] : 0);
+ u32 iCode = 0;
int aStart[3]; /* Input offset of each character in aBuf[] */
UNUSED_PARAM(unusedFlags);
@@ -255301,8 +260436,8 @@ static int fts5TriTokenize(
for(ii=0; ii<3; ii++){
do {
aStart[ii] = zIn - (const unsigned char*)pText;
+ if( zIn>=zEof ) return SQLITE_OK;
READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) return SQLITE_OK;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
}while( iCode==0 );
WRITE_UTF8(zOut, iCode);
@@ -255323,8 +260458,11 @@ static int fts5TriTokenize(
/* Read characters from the input up until the first non-diacritic */
do {
iNext = zIn - (const unsigned char*)pText;
+ if( zIn>=zEof ){
+ iCode = 0;
+ break;
+ }
READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
}while( iCode==0 );
@@ -255374,6 +260512,16 @@ static int sqlite3Fts5TokenizerPattern(
}
/*
+** Return true if the tokenizer described by p->azArg[] is the trigram
+** tokenizer. This tokenizer needs to be loaded before xBestIndex is
+** called for the first time in order to correctly handle LIKE/GLOB.
+*/
+static int sqlite3Fts5TokenizerPreload(Fts5TokenizerConfig *p){
+ return (p->nArg>=1 && 0==sqlite3_stricmp(p->azArg[0], "trigram"));
+}
+
+
+/*
** Register all built-in tokenizers with FTS5.
*/
static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
@@ -255383,7 +260531,6 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
} aBuiltin[] = {
{ "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
- { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
{ "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
};
@@ -255398,7 +260545,20 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
0
);
}
-
+ if( rc==SQLITE_OK ){
+ fts5_tokenizer_v2 sPorter = {
+ 2,
+ fts5PorterCreate,
+ fts5PorterDelete,
+ fts5PorterTokenize
+ };
+ rc = pApi->xCreateTokenizer_v2(pApi,
+ "porter",
+ (void*)pApi,
+ &sPorter,
+ 0
+ );
+ }
return rc;
}
@@ -255768,6 +260928,9 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
default: return 1; }
break;
+
+ default:
+ return 1;
}
return 0;
}
@@ -256180,7 +261343,6 @@ static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
aAscii[0] = 0; /* 0x00 is never a token character */
}
-
/*
** 2015 May 30
**
@@ -256592,6 +261754,7 @@ struct Fts5VocabCursor {
int nLeTerm; /* Size of zLeTerm in bytes */
char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
+ int colUsed; /* Copy of sqlite3_index_info.colUsed */
/* These are used by 'col' tables only */
int iCol;
@@ -256618,9 +261781,11 @@ struct Fts5VocabCursor {
/*
** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
*/
-#define FTS5_VOCAB_TERM_EQ 0x01
-#define FTS5_VOCAB_TERM_GE 0x02
-#define FTS5_VOCAB_TERM_LE 0x04
+#define FTS5_VOCAB_TERM_EQ 0x0100
+#define FTS5_VOCAB_TERM_GE 0x0200
+#define FTS5_VOCAB_TERM_LE 0x0400
+
+#define FTS5_VOCAB_COLUSED_MASK 0xFF
/*
@@ -256718,12 +261883,12 @@ static int fts5VocabInitVtab(
*pzErr = sqlite3_mprintf("wrong number of vtable arguments");
rc = SQLITE_ERROR;
}else{
- int nByte; /* Bytes of space to allocate */
+ i64 nByte; /* Bytes of space to allocate */
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 nTab = (int)strlen(zTab)+1;
+ i64 nDb = strlen(zDb)+1;
+ i64 nTab = strlen(zTab)+1;
int eType = 0;
rc = fts5VocabTableType(zType, pzErr, &eType);
@@ -256797,11 +261962,13 @@ static int fts5VocabBestIndexMethod(
int iTermEq = -1;
int iTermGe = -1;
int iTermLe = -1;
- int idxNum = 0;
+ int idxNum = (int)pInfo->colUsed;
int nArg = 0;
UNUSED_PARAM(pUnused);
+ assert( (pInfo->colUsed & FTS5_VOCAB_COLUSED_MASK)==pInfo->colUsed );
+
for(i=0; i<pInfo->nConstraint; i++){
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
if( p->usable==0 ) continue;
@@ -256893,7 +262060,7 @@ static int fts5VocabOpenMethod(
if( rc==SQLITE_OK ){
pVTab->zErrMsg = sqlite3_mprintf(
"no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
- );
+ );
rc = SQLITE_ERROR;
}
}else{
@@ -257053,9 +262220,19 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
switch( pTab->eType ){
case FTS5_VOCAB_ROW:
- if( eDetail==FTS5_DETAIL_FULL ){
- while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
- pCsr->aCnt[0]++;
+ /* Do not bother counting the number of instances if the "cnt"
+ ** column is not being read (according to colUsed). */
+ if( eDetail==FTS5_DETAIL_FULL && (pCsr->colUsed & 0x04) ){
+ while( iPos<nPos ){
+ u32 ii;
+ fts5FastGetVarint32(pPos, iPos, ii);
+ if( ii==1 ){
+ /* New column in the position list */
+ fts5FastGetVarint32(pPos, iPos, ii);
+ }else{
+ /* An instance - increment pCsr->aCnt[] */
+ pCsr->aCnt[0]++;
+ }
}
}
pCsr->aDoc[0]++;
@@ -257153,6 +262330,7 @@ static int fts5VocabFilterMethod(
if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];
+ pCsr->colUsed = (idxNum & FTS5_VOCAB_COLUSED_MASK);
if( pEq ){
zTerm = (const char *)sqlite3_value_text(pEq);
@@ -257320,7 +262498,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
}
-
+/* Here ends the fts5.c composite file. */
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
/************** End of fts5.c ************************************************/
@@ -257676,4 +262854,5 @@ SQLITE_API int sqlite3_stmt_init(
/************** End of stmt.c ************************************************/
/* Return the source-id for this library */
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+#endif /* SQLITE_AMALGAMATION */
/************************** End of sqlite3.c ******************************/
diff --git a/contrib/sqlite3/sqlite3.h b/contrib/sqlite3/sqlite3.h
index f64ca0172782..f56dd8d86a2d 100644
--- a/contrib/sqlite3/sqlite3.h
+++ b/contrib/sqlite3/sqlite3.h
@@ -133,7 +133,7 @@ extern "C" {
**
** 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
+** <a href="http://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
@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.46.1"
-#define SQLITE_VERSION_NUMBER 3046001
-#define SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33"
+#define SQLITE_VERSION "3.50.2"
+#define SQLITE_VERSION_NUMBER 3050002
+#define SQLITE_SOURCE_ID "2025-06-28 14:00:48 2af157d77fb1304a74176eaee7fbc7c7e932d946bf25325e9c26c91db19e3079"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -652,6 +652,13 @@ SQLITE_API int sqlite3_exec(
** 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].
+**
+** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read
+** from the database file in amounts that are not a multiple of the
+** page size and that do not begin at a page boundary. Without this
+** property, SQLite is careful to only do full-page reads and write
+** on aligned pages, with the one exception that it will do a sub-page
+** read of the first page to access the database header.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -668,6 +675,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
+#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000
/*
** CAPI3REF: File Locking Levels
@@ -772,8 +780,8 @@ struct sqlite3_file {
** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
-** PENDING, or EXCLUSIVE lock on the file. It returns true
-** if such a lock exists and false otherwise.
+** PENDING, or EXCLUSIVE lock on the file. It returns, via its output
+** pointer parameter, true if such a lock exists and false otherwise.
**
** The xFileControl() method is a generic interface that allows custom
** VFS implementations to directly control an open file using the
@@ -814,6 +822,7 @@ struct sqlite3_file {
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE]
** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
+** <li> [SQLITE_IOCAP_SUBPAGE_READ]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -1091,6 +1100,11 @@ struct sqlite3_io_methods {
** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
+** <li>[[SQLITE_FCNTL_NULL_IO]]
+** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor
+** or file handle for the [sqlite3_file] object such that it will no longer
+** read or write to the database file.
+**
** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
** be advantageous to block on the next WAL lock if the lock is not immediately
@@ -1149,6 +1163,12 @@ struct sqlite3_io_methods {
** 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_BLOCK_ON_CONNECT]]
+** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the
+** VFS to block when taking a SHARED lock to connect to a wal mode database.
+** This is used to implement the functionality associated with
+** SQLITE_SETLK_BLOCK_ON_CONNECT.
+**
** <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.
@@ -1244,6 +1264,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_EXTERNAL_READER 40
#define SQLITE_FCNTL_CKSM_FILE 41
#define SQLITE_FCNTL_RESET_CACHE 42
+#define SQLITE_FCNTL_NULL_IO 43
+#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1974,13 +1996,16 @@ struct sqlite3_mem_methods {
**
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
-** the default size of lookaside memory on each [database connection].
+** the default size of [lookaside memory] on each [database connection].
** The first argument is the
-** size of each lookaside buffer slot and the second is the number of
-** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
-** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
-** option to [sqlite3_db_config()] can be used to change the lookaside
-** configuration on individual connections.)^ </dd>
+** size of each lookaside buffer slot ("sz") and the second is the number of
+** slots allocated to each database connection ("cnt").)^
+** ^(SQLITE_CONFIG_LOOKASIDE sets the <i>default</i> lookaside size.
+** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can
+** be used to change the lookaside configuration on individual connections.)^
+** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the
+** default lookaside configuration at compile-time.
+** </dd>
**
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
@@ -2196,7 +2221,15 @@ struct sqlite3_mem_methods {
** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
-** can be passed as the second argument to the [sqlite3_db_config()] interface.
+** can be passed as the second parameter to the [sqlite3_db_config()] interface.
+**
+** The [sqlite3_db_config()] interface is a var-args functions. It takes a
+** variable number of parameters, though always at least two. The number of
+** parameters passed into sqlite3_db_config() depends on which of these
+** constants is given as the second parameter. This documentation page
+** refers to parameters beyond the second as "arguments". Thus, when this
+** page says "the N-th argument" it means "the N-th parameter past the
+** configuration option" or "the (N+2)-th parameter to sqlite3_db_config()".
**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
@@ -2208,31 +2241,57 @@ struct sqlite3_mem_methods {
** <dl>
** [[SQLITE_DBCONFIG_LOOKASIDE]]
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
-** <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
+** <dd> The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the
+** configuration of the [lookaside memory allocator] within a database
+** connection.
+** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are <i>not</i>
+** in the [DBCONFIG arguments|usual format].
+** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two,
+** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE
+** should have a total of five parameters.
+** <ol>
+** <li><p>The first argument ("buf") is a
** pointer to a memory buffer to use for lookaside memory.
-** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
-** may be NULL in which case SQLite will allocate the
-** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the
-** size of each lookaside buffer slot. ^The third argument is the number of
-** slots. The size of the buffer in the first argument must be greater than
-** or equal to the product of the second and third arguments. The buffer
-** must be aligned to an 8-byte boundary. ^If the second argument to
-** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
-** rounded down to the next smaller multiple of 8. ^(The lookaside memory
+** The first argument may be NULL in which case SQLite will allocate the
+** lookaside buffer itself using [sqlite3_malloc()].
+** <li><P>The second argument ("sz") is the
+** size of each lookaside buffer slot. Lookaside is disabled if "sz"
+** is less than 8. The "sz" argument should be a multiple of 8 less than
+** 65536. If "sz" does not meet this constraint, it is reduced in size until
+** it does.
+** <li><p>The third argument ("cnt") is the number of slots. Lookaside is disabled
+** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so
+** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt"
+** parameter is usually chosen so that the product of "sz" and "cnt" is less
+** than 1,000,000.
+** </ol>
+** <p>If the "buf" argument is not NULL, then it must
+** point to a memory buffer with a size that is greater than
+** or equal to the product of "sz" and "cnt".
+** The buffer must be aligned to an 8-byte boundary.
+** The lookaside memory
** configuration for a database connection can only be changed when that
** connection is not currently using lookaside memory, or in other words
-** when the "current value" returned by
-** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
+** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero.
** Any attempt to change the lookaside memory configuration when lookaside
** memory is in use leaves the configuration unchanged and returns
-** [SQLITE_BUSY].)^</dd>
+** [SQLITE_BUSY].
+** If the "buf" argument is NULL and an attempt
+** to allocate memory based on "sz" and "cnt" fails, then
+** lookaside is silently disabled.
+** <p>
+** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the
+** default lookaside configuration at initialization. The
+** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside
+** configuration at compile-time. Typical values for lookaside are 1200 for
+** "sz" and 40 to 100 for "cnt".
+** </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.
+** [foreign key constraints]. This is the same setting that is
+** enabled or disabled by the [PRAGMA foreign_keys] statement.
** The first argument is an integer which is 0 to disable FK enforcement,
** positive to enable FK enforcement or negative to leave FK enforcement
** unchanged. The second parameter is a pointer to an integer into which
@@ -2254,13 +2313,13 @@ struct sqlite3_mem_methods {
** <p>Originally this option disabled all triggers. ^(However, since
** SQLite version 3.35.0, TEMP triggers are still allowed even if
** this option is off. So, in other words, this option now only disables
-** triggers in the main database schema or in the schemas of ATTACH-ed
+** triggers in the main database schema or in the schemas of [ATTACH]-ed
** databases.)^ </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.
+** There must 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
@@ -2279,7 +2338,7 @@ struct sqlite3_mem_methods {
** <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.
+** There must be two additional arguments.
** The first argument is an integer which is 0 to disable fts3_tokenizer() or
** positive to enable fts3_tokenizer() or negative to leave the setting
** unchanged.
@@ -2294,7 +2353,7 @@ struct sqlite3_mem_methods {
** interface independently of the [load_extension()] SQL function.
** The [sqlite3_enable_load_extension()] API enables or disables both the
** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
-** There should be two additional arguments.
+** There must be two additional arguments.
** When the first argument to this interface is 1, then only the C-API is
** enabled and the SQL function remains disabled. If the first argument to
** this interface is 0, then both the C-API and the SQL function are disabled.
@@ -2308,23 +2367,30 @@ struct sqlite3_mem_methods {
**
** [[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
-** does not make a copy of the new main schema name string, so the application
-** must ensure that the argument passed into this DBCONFIG option is unchanged
-** until after the database connection closes.
+** schema. This option does not follow the
+** [DBCONFIG arguments|usual SQLITE_DBCONFIG argument format].
+** This option takes exactly one additional argument so that the
+** [sqlite3_db_config()] call has a total of three parameters. The
+** extra argument must be a pointer to a constant UTF8 string which
+** will become the new schema name in place of "main". ^SQLite does
+** not make a copy of the new main schema name string, so the application
+** must ensure that the argument passed into SQLITE_DBCONFIG MAINDBNAME
+** is unchanged 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 behavior. 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
+** <dd> Usually, when a database in [WAL mode] is closed or detached from a
+** database handle, SQLite checks if if there are other connections to the
+** same database, and if there are no other database connection (if the
+** connection being closed is the last open connection to the database),
+** then SQLite performs a [checkpoint] before closing the connection and
+** deletes the WAL file. The SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE option can
+** be used to override that behavior. The first argument passed to this
+** operation (the third parameter to [sqlite3_db_config()]) is an integer
+** which is positive to disable checkpoints-on-close, or zero (the default)
+** to enable them, and negative to leave the setting unchanged.
+** The second argument (the fourth 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>
@@ -2485,7 +2551,7 @@ struct sqlite3_mem_methods {
** statistics. For statistics to be collected, the flag must be set on
** the database handle both when the SQL statement is prepared and when it
** is stepped. The flag is set (collection of statistics is enabled)
-** by default. This option takes two arguments: an integer and a pointer to
+** by default. <p>This option takes two arguments: an integer and a pointer to
** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
** leave unchanged the statement scanstatus option. If the second argument
** is not NULL, then the value of the statement scanstatus setting after
@@ -2499,7 +2565,7 @@ struct sqlite3_mem_methods {
** in which tables and indexes are scanned so that the scans start at the end
** and work toward the beginning rather than starting at the beginning and
** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
-** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** same as setting [PRAGMA reverse_unordered_selects]. <p>This option takes
** two arguments which are an integer and a pointer to an integer. The first
** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
** reverse scan order flag, respectively. If the second argument is not NULL,
@@ -2508,7 +2574,76 @@ struct sqlite3_mem_methods {
** first argument.
** </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]]
+** <dt>SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE option enables or disables
+** the ability of the [ATTACH DATABASE] SQL command to create a new database
+** file if the database filed named in the ATTACH command does not already
+** exist. This ability of ATTACH to create a new database is enabled by
+** default. Applications can disable or reenable the ability for ATTACH to
+** create new database files using this DBCONFIG option.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the attach-create flag, respectively. If the second
+** argument is not NULL, then 0 or 1 is written into the integer that the
+** second argument points to depending on if the attach-create flag is set
+** after processing the first argument.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE]]
+** <dt>SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE option enables or disables the
+** ability of the [ATTACH DATABASE] SQL command to open a database for writing.
+** This capability is enabled by default. Applications can disable or
+** reenable this capability using the current DBCONFIG option. If the
+** the this capability is disabled, the [ATTACH] command will still work,
+** but the database will be opened read-only. If this option is disabled,
+** then the ability to create a new database using [ATTACH] is also disabled,
+** regardless of the value of the [SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]
+** option.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the ability to ATTACH another database for writing,
+** respectively. If the second argument is not NULL, then 0 or 1 is written
+** into the integer to which the second argument points, depending on whether
+** the ability to ATTACH a read/write database is enabled or disabled
+** after processing the first argument.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_COMMENTS]]
+** <dt>SQLITE_DBCONFIG_ENABLE_COMMENTS</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_COMMENTS option enables or disables the
+** ability to include comments in SQL text. Comments are enabled by default.
+** An application can disable or reenable comments in SQL text using this
+** DBCONFIG option.<p>
+** This option takes two arguments which are an integer and a pointer
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the ability to use comments in SQL text,
+** respectively. If the second argument is not NULL, then 0 or 1 is written
+** into the integer that the second argument points to depending on if
+** comments are allowed in SQL text after processing the first argument.
+** </dd>
+**
** </dl>
+**
+** [[DBCONFIG arguments]] <h3>Arguments To SQLITE_DBCONFIG Options</h3>
+**
+** <p>Most of the SQLITE_DBCONFIG options take two arguments, so that the
+** overall call to [sqlite3_db_config()] has a total of four parameters.
+** The first argument (the third parameter to sqlite3_db_config()) is a integer.
+** The second argument is a pointer to an integer. If the first argument is 1,
+** then the option becomes enabled. If the first integer argument is 0, then the
+** option is disabled. If the first argument is -1, then the option setting
+** is unchanged. The second argument, the pointer to an integer, may be NULL.
+** If the second argument is not NULL, then a value of 0 or 1 is written into
+** the integer to which the second argument points, depending on whether the
+** setting is disabled or enabled after applying any changes specified by
+** the first argument.
+**
+** <p>While most SQLITE_DBCONFIG options use the argument format
+** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME]
+** and [SQLITE_DBCONFIG_LOOKASIDE] options are different. See the
+** documentation of those exceptional options for details.
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
@@ -2530,7 +2665,10 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1022 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2622,10 +2760,14 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
** deleted by the most recently completed INSERT, UPDATE or DELETE
** statement on the database connection specified by the only parameter.
** The two functions are identical except for the type of the return value
-** and that if the number of rows modified by the most recent INSERT, UPDATE
+** and that if the number of rows modified by the most recent INSERT, UPDATE,
** or DELETE is greater than the maximum value supported by type "int", then
** the return value of sqlite3_changes() is undefined. ^Executing any other
** type of SQL statement does not modify the value returned by these functions.
+** For the purposes of this interface, a CREATE TABLE AS SELECT statement
+** does not count as an INSERT, UPDATE or DELETE statement and hence the rows
+** added to the new table by the CREATE TABLE AS SELECT statement are not
+** counted.
**
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
@@ -2881,6 +3023,44 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
/*
+** CAPI3REF: Set the Setlk Timeout
+** METHOD: sqlite3
+**
+** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If
+** the VFS supports blocking locks, it sets the timeout in ms used by
+** eligible locks taken on wal mode databases by the specified database
+** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does
+** not support blocking locks, this function is a no-op.
+**
+** Passing 0 to this function disables blocking locks altogether. Passing
+** -1 to this function requests that the VFS blocks for a long time -
+** indefinitely if possible. The results of passing any other negative value
+** are undefined.
+**
+** Internally, each SQLite database handle store two timeout values - the
+** busy-timeout (used for rollback mode databases, or if the VFS does not
+** support blocking locks) and the setlk-timeout (used for blocking locks
+** on wal-mode databases). The sqlite3_busy_timeout() method sets both
+** values, this function sets only the setlk-timeout value. Therefore,
+** to configure separate busy-timeout and setlk-timeout values for a single
+** database handle, call sqlite3_busy_timeout() followed by this function.
+**
+** Whenever the number of connections to a wal mode database falls from
+** 1 to 0, the last connection takes an exclusive lock on the database,
+** then checkpoints and deletes the wal file. While it is doing this, any
+** new connection that tries to read from the database fails with an
+** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is
+** passed to this API, the new connection blocks until the exclusive lock
+** has been released.
+*/
+SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags);
+
+/*
+** CAPI3REF: Flags for sqlite3_setlk_timeout()
+*/
+#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01
+
+/*
** CAPI3REF: Convenience Routines For Running Queries
** METHOD: sqlite3
**
@@ -3570,8 +3750,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
** <dd>The database connection comes up in "extended result code mode".
-** In other words, the database behaves has if
-** [sqlite3_extended_result_codes(db,1)] where called on the database
+** In other words, the database behaves as if
+** [sqlite3_extended_result_codes(db,1)] were called on the database
** connection as soon as the connection is created. In addition to setting
** the extended result code mode, this flag also causes [sqlite3_open_v2()]
** to return an extended result code.</dd>
@@ -3899,7 +4079,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
**
** 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
+** an array P of N URI Key/Value pairs. 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>
@@ -4185,11 +4365,22 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <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.
+**
+** [[SQLITE_PREPARE_DONT_LOG]] <dt>SQLITE_PREPARE_DONT_LOG</dt>
+** <dd>The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler
+** errors from being sent to the error log defined by
+** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test
+** compiles to see if some SQL syntax is well-formed, without generating
+** messages on the global error log when it is not. If the test compile
+** fails, the sqlite3_prepare_v3() call returns the same error indications
+** with or without this flag; it just omits the call to [sqlite3_log()] that
+** logs the error.
** </dl>
*/
#define SQLITE_PREPARE_PERSISTENT 0x01
#define SQLITE_PREPARE_NORMALIZE 0x02
#define SQLITE_PREPARE_NO_VTAB 0x04
+#define SQLITE_PREPARE_DONT_LOG 0x10
/*
** CAPI3REF: Compiling An SQL Statement
@@ -4222,13 +4413,17 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** 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
-** number of bytes read from zSql. ^If nByte is zero, then no prepared
+** first zero terminator. ^If nByte is positive, then it is the maximum
+** number of bytes read from zSql. When nByte is positive, zSql is read
+** up to the first zero terminator or until the nByte bytes have been read,
+** whichever comes first. ^If nByte is zero, then no prepared
** statement is generated.
** If the caller knows that the supplied string is nul-terminated, then
** there is a small performance advantage to passing an nByte parameter that
** is the number of bytes in the input string <i>including</i>
** the nul-terminator.
+** Note that nByte measure the length of the input in bytes, not
+** characters, even for the UTF-16 interfaces.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql. These routines only
@@ -4565,7 +4760,7 @@ typedef struct sqlite3_context sqlite3_context;
** METHOD: sqlite3_stmt
**
** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
-** literals may be replaced by a [parameter] that matches one of following
+** literals may be replaced by a [parameter] that matches one of the following
** templates:
**
** <ul>
@@ -4610,7 +4805,7 @@ typedef struct sqlite3_context sqlite3_context;
**
** [[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
+** found in the 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().)^
@@ -4630,7 +4825,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 occurs at byte offsets less than
+** terminated. If any NUL characters occur 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.
@@ -4842,7 +5037,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** METHOD: sqlite3_stmt
**
** ^These routines provide a means to determine the database, table, and
-** table column that is the origin of a particular result column in
+** table column that is the origin of a particular result column in a
** [SELECT] statement.
** ^The name of the database or table or column can be returned as
** either a UTF-8 or UTF-16 string. ^The _database_ routines return
@@ -4980,7 +5175,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** other than [SQLITE_ROW] before any subsequent invocation of
** 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(). But after [version 3.6.23.1] ([dateof:3.6.23.1]),
** sqlite3_step() began
** calling [sqlite3_reset()] automatically in this circumstance rather
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
@@ -5411,8 +5606,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
**
** 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
+** used inside of triggers, views, CHECK constraints, or other elements of
+** the database schema. This flag 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
@@ -5443,7 +5638,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** [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
+** sqlite3_create_window_function() is not NULL, then it is the 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
@@ -5599,7 +5794,7 @@ SQLITE_API int sqlite3_create_window_function(
** This flag instructs SQLite to omit some corner-case optimizations that
** might disrupt the operation of the [sqlite3_value_subtype()] function,
** causing it to return zero rather than the correct subtype().
-** SQL functions that invokes [sqlite3_value_subtype()] should have this
+** All SQL functions that invoke [sqlite3_value_subtype()] should have this
** property. If the SQLITE_SUBTYPE property is omitted, then the return
** value from [sqlite3_value_subtype()] might sometimes be zero even though
** a non-zero subtype was specified by the function argument expression.
@@ -5615,6 +5810,15 @@ SQLITE_API int sqlite3_create_window_function(
** [sqlite3_result_subtype()] should avoid setting this property, as the
** purpose of this property is to disable certain optimizations that are
** incompatible with subtypes.
+**
+** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
+** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
+** that internally orders the values provided to the first argument. The
+** ordered-set aggregate SQL notation with a single ORDER BY term can be
+** used to invoke this function. If the ordered-set aggregate notation is
+** used on a function that lacks this flag, then an error is raised. Note
+** that the ordered-set aggregate syntax is only available if SQLite is
+** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
** </dd>
** </dl>
*/
@@ -5623,6 +5827,7 @@ SQLITE_API int sqlite3_create_window_function(
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
#define SQLITE_RESULT_SUBTYPE 0x001000000
+#define SQLITE_SELFORDER1 0x002000000
/*
** CAPI3REF: Deprecated Functions
@@ -5820,7 +6025,7 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
** one SQL function to another. Use the [sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
**
-** Every [application-defined SQL function] that invoke this interface
+** Every [application-defined SQL function] that invokes this interface
** should include the [SQLITE_SUBTYPE] property in the text
** encoding argument when the function is [sqlite3_create_function|registered].
** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype()
@@ -5833,7 +6038,7 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
** METHOD: sqlite3_value
**
** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value]
-** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
+** object V and returns a pointer to that copy. ^The [sqlite3_value] returned
** is a [protected sqlite3_value] object even if the input is not.
** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
** memory allocation fails. ^If V is a [pointer value], then the result
@@ -5871,7 +6076,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
** allocation 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
+** determined by the N parameter on the first successful call. Changing the
** 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
@@ -6033,7 +6238,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi
**
** Security Warning: These interfaces should not be exposed in scripting
** languages or in other circumstances where it might be possible for an
-** an attacker to invoke them. Any agent that can invoke these interfaces
+** attacker to invoke them. Any agent that can invoke these interfaces
** can probably also take control of the process.
**
** Database connection client data is only available for SQLite
@@ -6147,7 +6352,7 @@ typedef void (*sqlite3_destructor_type)(void*);
** pointed to by the 2nd parameter are taken as the application-defined
** function result. If the 3rd parameter is non-negative, then it
** must be the byte offset into the string where the NUL terminator would
-** appear if the string where NUL terminated. If any NUL characters occur
+** appear if the string were NUL terminated. If any NUL characters occur
** in the string at a byte offset that is less than the value of the 3rd
** parameter, then the resulting string will contain embedded NULs and the
** result of expressions operating on strings with embedded NULs is undefined.
@@ -6205,7 +6410,7 @@ typedef void (*sqlite3_destructor_type)(void*);
** 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
+** If these routines are called from within a different thread
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
@@ -6611,7 +6816,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
** METHOD: sqlite3
**
** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
-** for the N-th database on database connection D, or a NULL pointer of N is
+** for the N-th database on database connection D, or a NULL pointer if N is
** out of range. An N value of 0 means the main database file. An N of 1 is
** the "temp" schema. Larger values of N correspond to various ATTACH-ed
** databases.
@@ -6706,7 +6911,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
** <dd>The SQLITE_TXN_READ state means that the database is currently
** in a read transaction. Content has been read from the database file
** but nothing in the database file has changed. The transaction state
-** will advanced to SQLITE_TXN_WRITE if any changes occur and there are
+** will be advanced to SQLITE_TXN_WRITE if any changes occur and there are
** no other conflicting concurrent write transactions. The transaction
** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or
** [COMMIT].</dd>
@@ -6715,7 +6920,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
** <dd>The SQLITE_TXN_WRITE state means that the database is currently
** in a write transaction. Content has been written to the database file
** but has not yet committed. The transaction state will change to
-** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
+** SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
*/
#define SQLITE_TXN_NONE 0
#define SQLITE_TXN_READ 1
@@ -6866,6 +7071,8 @@ SQLITE_API int sqlite3_autovacuum_pages(
**
** ^The second argument is a pointer to the function to invoke when a
** row is updated, inserted or deleted in a rowid table.
+** ^The update hook is disabled by invoking sqlite3_update_hook()
+** with a NULL pointer as the second parameter.
** ^The first argument to the callback is a copy of the third argument
** to sqlite3_update_hook().
** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE],
@@ -6994,7 +7201,7 @@ 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.
+** used 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.
@@ -7052,7 +7259,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** </ul>)^
**
** The circumstances under which SQLite will enforce the heap limits may
-** changes in future releases of SQLite.
+** change 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);
@@ -7167,8 +7374,8 @@ SQLITE_API int sqlite3_table_column_metadata(
** ^The entry point is zProc.
** ^(zProc may be 0, in which case SQLite will try to come up with an
** entry point name on its own. It first tries "sqlite3_extension_init".
-** If that does not work, it constructs a name "sqlite3_X_init" where the
-** X is consists of the lower-case equivalent of all ASCII alphabetic
+** If that does not work, it constructs a name "sqlite3_X_init" where
+** X consists of the lower-case equivalent of all ASCII alphabetic
** characters in the filename from the last "/" to the first following
** "." and omitting any initial "lib".)^
** ^The sqlite3_load_extension() interface returns
@@ -7239,7 +7446,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
** ^(Even though the function prototype shows that xEntryPoint() takes
** no arguments and returns void, SQLite invokes xEntryPoint() with three
** arguments and expects an integer result as if the signature of the
-** entry point where as follows:
+** entry point were as follows:
**
** <blockquote><pre>
** &nbsp; int xEntryPoint(
@@ -7403,7 +7610,7 @@ struct sqlite3_module {
** 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
+** checked separately in byte code. If the omit flag is changed 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.)^
@@ -7427,9 +7634,11 @@ struct sqlite3_module {
** will be returned by the strategy.
**
** 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.
+** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
+** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
+** output to show the idxNum as hex instead of as decimal. Another flag is
+** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
+** return 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
@@ -7493,7 +7702,9 @@ struct sqlite3_index_info {
** [sqlite3_index_info].idxFlags field to some combination of
** these bits.
*/
-#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
+#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
+ /* in EXPLAIN QUERY PLAN */
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
@@ -7566,7 +7777,7 @@ struct sqlite3_index_info {
** the implementation of the [virtual table module]. ^The fourth
** parameter is an arbitrary client data pointer that is passed through
** into the [xCreate] and [xConnect] methods of the virtual table module
-** when a new virtual table is be being created or reinitialized.
+** when a new virtual table is being created or reinitialized.
**
** ^The sqlite3_create_module_v2() interface has a fifth parameter which
** is a pointer to a destructor for the pClientData. ^SQLite will
@@ -7731,7 +7942,7 @@ typedef struct sqlite3_blob sqlite3_blob;
** 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()]
-** on *ppBlob after this function it returns.
+** on *ppBlob after this function returns.
**
** This function fails with SQLITE_ERROR if any of the following are true:
** <ul>
@@ -7851,7 +8062,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
**
** ^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
+** incremental blob I/O routines can only read or overwrite existing
** blob content; they cannot change the size of a blob.
**
** This routine only works on a [BLOB handle] which has been created
@@ -8001,7 +8212,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** ^The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
** routine returns NULL if it is unable to allocate the requested
-** mutex. The argument to sqlite3_mutex_alloc() must one of these
+** mutex. The argument to sqlite3_mutex_alloc() must be one of these
** integer constants:
**
** <ul>
@@ -8234,7 +8445,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
** 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 to 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
@@ -8330,6 +8541,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
+#define SQLITE_TESTCTRL_GETOPT 16
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
@@ -8349,14 +8561,14 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_USELONGDOUBLE 34
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
#define SQLITE_TESTCTRL_LAST 34 /* 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
+** recognized by SQLite. Applications can use 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.
**
@@ -8524,7 +8736,7 @@ SQLITE_API void sqlite3_str_reset(sqlite3_str*);
** 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] object. Applications must not use the pointer returned by
** [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
@@ -8610,7 +8822,7 @@ SQLITE_API int sqlite3_status64(
** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
** buffer and where forced to overflow to [sqlite3_malloc()]. The
** returned value includes allocations that overflowed because they
-** where too large (they were larger than the "sz" parameter to
+** were too large (they were larger than the "sz" parameter to
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
** no space was left in the page cache.</dd>)^
**
@@ -8694,28 +8906,29 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
** <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.)^
+** the current value is always zero.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
-** <dd>This parameter returns the number malloc attempts that might have
+** <dd>This parameter returns the number of malloc attempts that might have
** been satisfied using lookaside memory but failed due to the amount of
** memory requested being larger than the lookaside slot size.
** Only the high-water value is meaningful;
-** the current value is always zero.)^
+** the current value is always zero.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]]
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
-** <dd>This parameter returns the number malloc attempts that might have
+** <dd>This parameter returns the number of malloc attempts that might have
** been satisfied using lookaside memory but failed due to all lookaside
** memory already being in use.
** Only the high-water value is meaningful;
-** the current value is always zero.)^
+** the current value is always zero.</dd>)^
**
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
+** </dd>
**
** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
@@ -8724,10 +8937,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** memory used by that pager cache is divided evenly between the attached
** connections.)^ In other words, if none of the pager caches associated
** with the database connection are shared, this request returns the same
-** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
+** value as DBSTATUS_CACHE_USED. Or, if one or more of the pager caches are
** shared, the value returned by this call will be smaller than that returned
** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
-** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
+** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.</dd>
**
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
@@ -8737,6 +8950,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** schema memory is shared with other database connections due to
** [shared cache mode] being enabled.
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
+** </dd>
**
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
@@ -8773,7 +8987,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** 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
+** additional overhead. This parameter can be used to help identify
** inefficiencies that can be resolved by increasing the cache size.
** </dd>
**
@@ -9253,7 +9467,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** 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
-** database is modified by the using the same database connection as is used
+** database is modified by using the same database connection as is used
** by the backup operation, then the backup database is automatically
** updated at the same time.
**
@@ -9270,7 +9484,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** and may not be used following a call to sqlite3_backup_finish().
**
** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no
-** sqlite3_backup_step() errors occurred, regardless or whether or not
+** sqlite3_backup_step() errors occurred, regardless of whether or not
** sqlite3_backup_step() completed.
** ^If an out-of-memory condition or IO error occurred during any prior
** sqlite3_backup_step() call on the same [sqlite3_backup] object, then
@@ -9325,6 +9539,16 @@ typedef struct sqlite3_backup sqlite3_backup;
** APIs are not strictly speaking threadsafe. If they are invoked at the
** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values.
+**
+** <b>Alternatives To Using The Backup API</b>
+**
+** Other techniques for safely creating a consistent backup of an SQLite
+** database include:
+**
+** <ul>
+** <li> The [VACUUM INTO] command.
+** <li> The [sqlite3_rsync] utility program.
+** </ul>
*/
SQLITE_API sqlite3_backup *sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */
@@ -10330,7 +10554,7 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
** METHOD: sqlite3
**
** ^If a write-transaction is open on [database connection] D when the
-** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
+** [sqlite3_db_cacheflush(D)] interface is invoked, any dirty
** 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
@@ -10524,6 +10748,14 @@ typedef struct sqlite3_snapshot {
** If there is not already a read-transaction open on schema S when
** this function is called, one is opened automatically.
**
+** If a read-transaction is opened by this function, then it is guaranteed
+** that the returned snapshot object may not be invalidated by a database
+** writer or checkpointer until after the read-transaction is closed. This
+** is not guaranteed if a read-transaction is already open when this
+** function is called. In that case, any subsequent write or checkpoint
+** operation on the database may invalidate the returned snapshot handle,
+** even while the read-transaction remains open.
+**
** 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
@@ -10681,8 +10913,9 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
/*
** 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.
+** 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 S is a NULL pointer, the main database is used.
** If P is not a NULL pointer, then the size of the database in bytes
** is written into *P.
**
@@ -10832,8 +11065,6 @@ SQLITE_API int sqlite3_deserialize(
#if defined(__wasi__)
# undef SQLITE_WASI
# define SQLITE_WASI 1
-# undef SQLITE_OMIT_WAL
-# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
# ifndef SQLITE_OMIT_LOAD_EXTENSION
# define SQLITE_OMIT_LOAD_EXTENSION
# endif
@@ -10845,7 +11076,7 @@ SQLITE_API int sqlite3_deserialize(
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif
-#endif /* SQLITE3_H */
+/* #endif for SQLITE3_H will be added by mksqlite3.tcl */
/******** Begin file sqlite3rtree.h *********/
/*
@@ -11326,9 +11557,10 @@ SQLITE_API void sqlite3session_table_filter(
** 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
-** 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.
+** Or, if one field of a row is updated while a session is enabled, and
+** then another field of the same row is updated while the session is disabled,
+** the resulting changeset will contain an UPDATE change that updates both
+** fields.
*/
SQLITE_API int sqlite3session_changeset(
sqlite3_session *pSession, /* Session object */
@@ -11400,8 +11632,9 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession
** 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.
+** Unless the call to this function is a no-op as described above, it is an
+** error if database zFrom does not exist or does not contain the required
+** compatible table.
**
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
@@ -11536,7 +11769,7 @@ SQLITE_API int 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>
+** <dt>SQLITE_CHANGESETSTART_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.
@@ -11851,19 +12084,6 @@ SQLITE_API int sqlite3changeset_concat(
void **ppOut /* OUT: Buffer containing output changeset */
);
-
-/*
-** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
-*/
-SQLITE_API int sqlite3changeset_upgrade(
- sqlite3 *db,
- const char *zDb,
- int nIn, const void *pIn, /* Input changeset */
- int *pnOut, void **ppOut /* OUT: Inverse of input */
-);
-
-
-
/*
** CAPI3REF: Changegroup Handle
**
@@ -13036,6 +13256,10 @@ struct Fts5PhraseIter {
** (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).
**
+** In all cases, matches are visited in (column ASC, offset ASC) order.
+** i.e. all those in column 0, sorted by offset, followed by those in
+** column 1, etc.
+**
** xPhraseNext()
** See xPhraseFirst above.
**
@@ -13092,19 +13316,57 @@ struct Fts5PhraseIter {
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
** output variable (*ppToken) is set to point to a buffer containing the
** matching document token, and (*pnToken) to the size of that buffer in
-** bytes. This API is not available if the specified token matches a
-** prefix query term. In that case both output variables are always set
-** to 0.
+** bytes.
**
** The output text is not a copy of the document text that was tokenized.
** It is the output of the tokenizer module. For tokendata=1 tables, this
** includes any embedded 0x00 and trailing data.
**
+** This API may be slow in some cases if the token identified by parameters
+** iIdx and iToken matched a prefix token in the query. In most cases, the
+** first call to this API for each prefix token in the query is forced
+** to scan the portion of the full-text index that matches the prefix
+** token to collect the extra data required by this API. If the prefix
+** token matches a large number of token instances in the document set,
+** this may be a performance problem.
+**
+** If the user knows in advance that a query may use this API for a
+** prefix token, FTS5 may be configured to collect all required data as part
+** of the initial querying of the full-text index, avoiding the second scan
+** entirely. This also causes prefix queries that do not use this API to
+** run more slowly and use more memory. FTS5 may be configured in this way
+** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
+** option, or on a per-query basis using the
+** [fts5_insttoken | fts5_insttoken()] user function.
+**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
+**
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the locale associated
+** with column iCol of the current row. Usually, there is no associated
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
+** to NULL and 0, respectively. However, if the fts5_locale() function
+** was used to associate a locale with the value when it was inserted
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
+** is set to the size in bytes of the buffer, not including the
+** nul-terminator.
+**
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
+** SQLite error code is returned. The final value of the output parameters
+** is undefined in this case.
+**
+** xTokenize_v2:
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
+** API is the same as the xTokenize() API, except that it allows a tokenizer
+** locale to be specified.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
+ int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*);
@@ -13146,6 +13408,15 @@ struct Fts5ExtensionApi {
const char **ppToken, int *pnToken
);
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
+
+ /* Below this point are iVersion>=4 only */
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
+ int (*xTokenize_v2)(Fts5Context*,
+ const char *pText, int nText, /* Text to tokenize */
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
+ void *pCtx, /* Context passed to xToken() */
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
+ );
};
/*
@@ -13166,7 +13437,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
+** pointer provided by the application when the fts5_tokenizer_v2 object
** 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
@@ -13190,7 +13461,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
-** The second argument indicates the reason that FTS5 is requesting
+** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
@@ -13214,6 +13485,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database.
** </ul>
**
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
+** nLocale - are a pointer to a buffer containing the locale to use for
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
+** which case nLocale is always 0) to indicate that the tokenizer should
+** use its default locale.
+**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
@@ -13237,6 +13515,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
+** then the xTokenize() method has two additional arguments - pLocale
+** and nLocale. These specify the locale that the tokenizer should use
+** for the current request. If pLocale and nLocale are both 0, then the
+** tokenizer should use its default locale. Otherwise, pLocale points to
+** an nLocale byte buffer containing the name of the locale to use as utf-8
+** text. pLocale is not nul-terminated.
+**
+** FTS5_TOKENIZER
+**
+** There is also an fts5_tokenizer object. This is an older, deprecated,
+** version of fts5_tokenizer_v2. It is similar except that:
+**
+** <ul>
+** <li> There is no "iVersion" field, and
+** <li> The xTokenize() method does not take a locale argument.
+** </ul>
+**
+** Legacy fts5_tokenizer tokenizers must be registered using the
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
+**
+** Tokenizer implementations registered using either API may be retrieved
+** using both xFindTokenizer() and xFindTokenizer_v2().
+**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -13345,6 +13647,33 @@ struct Fts5ExtensionApi {
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
+struct fts5_tokenizer_v2 {
+ int iVersion; /* Currently always 2 */
+
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+ void (*xDelete)(Fts5Tokenizer*);
+ int (*xTokenize)(Fts5Tokenizer*,
+ void *pCtx,
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Pointer to buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStart, /* Byte offset of token within input text */
+ int iEnd /* Byte offset of end of token within input text */
+ )
+ );
+};
+
+/*
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
+** implementations. The following type is included for legacy applications
+** that still use it.
+*/
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -13364,6 +13693,7 @@ struct fts5_tokenizer {
);
};
+
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
@@ -13383,7 +13713,7 @@ struct fts5_tokenizer {
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
@@ -13410,6 +13740,25 @@ struct fts5_api {
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
+
+ /* APIs below this point are only available if iVersion>=3 */
+
+ /* Create a new tokenizer */
+ int (*xCreateTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void *pUserData,
+ fts5_tokenizer_v2 *pTokenizer,
+ void (*xDestroy)(void*)
+ );
+
+ /* Find an existing tokenizer */
+ int (*xFindTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer
+ );
};
/*
@@ -13423,3 +13772,4 @@ struct fts5_api {
#endif /* _FTS5_H */
/******** End of fts5.h *********/
+#endif /* SQLITE3_H */
diff --git a/contrib/sqlite3/sqlite3.pc.in b/contrib/sqlite3/sqlite3.pc.in
index 3799671e613b..a9f941b1e40d 100644
--- a/contrib/sqlite3/sqlite3.pc.in
+++ b/contrib/sqlite3/sqlite3.pc.in
@@ -9,5 +9,5 @@ Name: SQLite
Description: SQL database engine
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lsqlite3
-Libs.private: @LIBS@
+Libs.private: @LDFLAGS_MATH@ @LDFLAGS_ZLIB@ @LDFLAGS_ICU@
Cflags: -I${includedir}
diff --git a/contrib/sqlite3/sqlite3.rc b/contrib/sqlite3/sqlite3.rc
index 5a856490d64a..aad468d34941 100644
--- a/contrib/sqlite3/sqlite3.rc
+++ b/contrib/sqlite3/sqlite3.rc
@@ -70,7 +70,7 @@ BEGIN
VALUE "FileDescription", "SQLite is a software library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine."
VALUE "FileVersion", SQLITE_VERSION
VALUE "InternalName", "sqlite3"
- VALUE "LegalCopyright", "http://www.sqlite.org/copyright.html"
+ VALUE "LegalCopyright", "http://sqlite.org/copyright.html"
VALUE "ProductName", "SQLite"
VALUE "ProductVersion", SQLITE_VERSION
VALUE "SourceId", SQLITE_SOURCE_ID
diff --git a/contrib/sqlite3/sqlite3ext.h b/contrib/sqlite3/sqlite3ext.h
index ae0949baf75a..cf775dfbde0f 100644
--- a/contrib/sqlite3/sqlite3ext.h
+++ b/contrib/sqlite3/sqlite3ext.h
@@ -366,6 +366,8 @@ struct sqlite3_api_routines {
/* Version 3.44.0 and later */
void *(*get_clientdata)(sqlite3*,const char*);
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
+ /* Version 3.50.0 and later */
+ int (*setlk_timeout)(sqlite3*,int,int);
};
/*
@@ -699,6 +701,8 @@ typedef int (*sqlite3_loadext_entry)(
/* Version 3.44.0 and later */
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
+/* Version 3.50.0 and later */
+#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/contrib/sqlite3/sqlite3rc.h b/contrib/sqlite3/sqlite3rc.h
index 07facc833868..d412190d370b 100644
--- a/contrib/sqlite3/sqlite3rc.h
+++ b/contrib/sqlite3/sqlite3rc.h
@@ -1,3 +1,3 @@
#ifndef SQLITE_RESOURCE_VERSION
-#define SQLITE_RESOURCE_VERSION 3,46,1
+#define SQLITE_RESOURCE_VERSION 3,50,2
#endif
diff --git a/contrib/sqlite3/tea/Makefile.in b/contrib/sqlite3/tea/Makefile.in
index 5264f89f3c55..5b2ad4c69992 100644
--- a/contrib/sqlite3/tea/Makefile.in
+++ b/contrib/sqlite3/tea/Makefile.in
@@ -1,475 +1,535 @@
-# Makefile.in --
-#
-# This file is a Makefile for Sample TEA Extension. If it has the name
-# "Makefile.in" then it is a template for a Makefile; to generate the
-# actual Makefile, run "./configure", which is a configuration script
-# generated by the "autoconf" program (constructs like "@foo@" will get
-# replaced in the actual Makefile.
-#
-# Copyright (c) 1999 Scriptics Corporation.
-# Copyright (c) 2002-2005 ActiveState Corporation.
-#
-# See the file "license.terms" for information on usage and redistribution
-# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
-
-#========================================================================
-# Add additional lines to handle any additional AC_SUBST cases that
-# have been added in a customized configure script.
-#========================================================================
-
-#SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@
-
-#========================================================================
-# Nothing of the variables below this line should need to be changed.
-# Please check the TARGETS section below to make sure the make targets
-# are correct.
-#========================================================================
-
-#========================================================================
-# The names of the source files is defined in the configure script.
-# The object files are used for linking into the final library.
-# This will be used when a dist target is added to the Makefile.
-# It is not important to specify the directory, as long as it is the
-# $(srcdir) or in the generic, win or unix subdirectory.
-#========================================================================
-
-PKG_SOURCES = @PKG_SOURCES@
-PKG_OBJECTS = @PKG_OBJECTS@
-
-PKG_STUB_SOURCES = @PKG_STUB_SOURCES@
-PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@
-
-#========================================================================
-# PKG_TCL_SOURCES identifies Tcl runtime files that are associated with
-# this package that need to be installed, if any.
-#========================================================================
-
-PKG_TCL_SOURCES = @PKG_TCL_SOURCES@
-
-#========================================================================
-# This is a list of public header files to be installed, if any.
-#========================================================================
-
-PKG_HEADERS = @PKG_HEADERS@
-
-#========================================================================
-# "PKG_LIB_FILE" refers to the library (dynamic or static as per
-# configuration options) composed of the named objects.
-#========================================================================
-
-PKG_LIB_FILE = @PKG_LIB_FILE@
-PKG_LIB_FILE8 = @PKG_LIB_FILE8@
-PKG_LIB_FILE9 = @PKG_LIB_FILE9@
-PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@
-
-lib_BINARIES = $(PKG_LIB_FILE)
-BINARIES = $(lib_BINARIES)
-
-SHELL = @SHELL@
-
-srcdir = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-libdir = @libdir@
-includedir = @includedir@
-datarootdir = @datarootdir@
-runstatedir = @runstatedir@
-datadir = @datadir@
-mandir = @mandir@
-
-DESTDIR =
-
-PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION)
-pkgdatadir = $(datadir)/$(PKG_DIR)
-pkglibdir = $(libdir)/$(PKG_DIR)
-pkgincludedir = $(includedir)/$(PKG_DIR)
-
-top_builddir = @abs_top_builddir@
-
-INSTALL_OPTIONS =
-INSTALL = @INSTALL@ $(INSTALL_OPTIONS)
-INSTALL_DATA_DIR = @INSTALL_DATA_DIR@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_LIBRARY = @INSTALL_LIBRARY@
-
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-CC = @CC@
-CCLD = @CCLD@
-CFLAGS_DEFAULT = @CFLAGS_DEFAULT@
-CFLAGS_WARNING = @CFLAGS_WARNING@
-EXEEXT = @EXEEXT@
-LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@
-MAKE_LIB = @MAKE_LIB@
-MAKE_STUB_LIB = @MAKE_STUB_LIB@
-OBJEXT = @OBJEXT@
-RANLIB = @RANLIB@
-RANLIB_STUB = @RANLIB_STUB@
-SHLIB_CFLAGS = @SHLIB_CFLAGS@
-SHLIB_LD = @SHLIB_LD@
-SHLIB_LD_LIBS = @SHLIB_LD_LIBS@
-STLIB_LD = @STLIB_LD@
-#TCL_DEFS = @TCL_DEFS@
-TCL_BIN_DIR = @TCL_BIN_DIR@
-TCL_SRC_DIR = @TCL_SRC_DIR@
-#TK_BIN_DIR = @TK_BIN_DIR@
-#TK_SRC_DIR = @TK_SRC_DIR@
-
-# Not used, but retained for reference of what libs Tcl required
-#TCL_LIBS = @TCL_LIBS@
-
-#========================================================================
-# TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our
-# package without installing. The other environment variables allow us
-# to test against an uninstalled Tcl. Add special env vars that you
-# require for testing here (like TCLX_LIBRARY).
-#========================================================================
-
-EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR)
-#EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR)
-TCLLIBPATH = $(top_builddir)
-TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library`
-PKG_ENV = @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \
- PATH="$(EXTRA_PATH):$(PATH)" \
- TCLLIBPATH="$(TCLLIBPATH)"
-
-TCLSH_PROG = @TCLSH_PROG@
-TCLSH = $(TCLSH_ENV) $(PKG_ENV) $(TCLSH_PROG)
-
-#WISH_ENV = TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library`
-#WISH_PROG = @WISH_PROG@
-#WISH = $(TCLSH_ENV) $(WISH_ENV) $(PKG_ENV) $(WISH_PROG)
-
-SHARED_BUILD = @SHARED_BUILD@
-
-INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ -I. -I$(srcdir)/..
-#INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@
-
-PKG_CFLAGS = @PKG_CFLAGS@
-
-# TCL_DEFS is not strictly need here, but if you remove it, then you
-# must make sure that configure.ac checks for the necessary components
-# that your library may use. TCL_DEFS can actually be a problem if
-# you do not compile with a similar machine setup as the Tcl core was
-# compiled with.
-#DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS)
-DEFS = @DEFS@ $(PKG_CFLAGS)
-
-# Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile
-CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl
-CLEANFILES = @CLEANFILES@
-
-CPPFLAGS = @CPPFLAGS@
-LIBS = @PKG_LIBS@ @LIBS@
-AR = @AR@
-CFLAGS = @CFLAGS@
-LDFLAGS = @LDFLAGS@
-LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@
-COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) \
- $(CFLAGS_DEFAULT) $(CFLAGS_WARNING) $(SHLIB_CFLAGS) $(CFLAGS)
-
-GDB = gdb
-VALGRIND = valgrind
-VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \
- --leak-check=yes --show-reachable=yes -v
-
-.SUFFIXES: .c .$(OBJEXT)
-
-#========================================================================
-# Start of user-definable TARGETS section
-#========================================================================
-
-#========================================================================
-# TEA TARGETS. Please note that the "libraries:" target refers to platform
-# independent files, and the "binaries:" target includes executable programs and
-# platform-dependent libraries. Modify these targets so that they install
-# the various pieces of your package. The make and install rules
-# for the BINARIES that you specified above have already been done.
-#========================================================================
-
-all: binaries libraries doc
-
-#========================================================================
-# The binaries target builds executable programs, Windows .dll's, unix
-# shared/static libraries, and any other platform-dependent files.
-# The list of targets to build for "binaries:" is specified at the top
-# of the Makefile, in the "BINARIES" variable.
-#========================================================================
-
-binaries: $(BINARIES)
-
-libraries:
-
-#========================================================================
-# Your doc target should differentiate from doc builds (by the developer)
-# and doc installs (see install-doc), which just install the docs on the
-# end user machine when building from source.
-#========================================================================
-
-doc:
- @echo "If you have documentation to create, place the commands to"
- @echo "build the docs in the 'doc:' target. For example:"
- @echo " xml2nroff sample.xml > sample.n"
- @echo " xml2html sample.xml > sample.html"
-
-install: all install-binaries install-libraries install-doc
-
-install-binaries: binaries install-lib-binaries install-bin-binaries
-
-#========================================================================
-# This rule installs platform-independent files, such as header files.
-# The list=...; for p in $$list handles the empty list case x-platform.
-#========================================================================
-
-install-libraries: libraries
- @$(INSTALL_DATA_DIR) "$(DESTDIR)$(includedir)"
- @echo "Installing header files in $(DESTDIR)$(includedir)"
- @list='$(PKG_HEADERS)'; for i in $$list; do \
- echo "Installing $(srcdir)/$$i" ; \
- $(INSTALL_DATA) $(srcdir)/$$i "$(DESTDIR)$(includedir)" ; \
- done;
-
-#========================================================================
-# Install documentation. Unix manpages should go in the $(mandir)
-# directory.
-#========================================================================
-
-install-doc: doc
- @$(INSTALL_DATA_DIR) "$(DESTDIR)$(mandir)/mann"
- @echo "Installing documentation in $(DESTDIR)$(mandir)"
- @list='$(srcdir)/doc/*.n'; for i in $$list; do \
- echo "Installing $$i"; \
- $(INSTALL_DATA) $$i "$(DESTDIR)$(mandir)/mann" ; \
- done
-
-test: binaries libraries
- @echo "SQLite TEA distribution does not include tests"
-
-shell: binaries libraries
- @$(TCLSH) $(SCRIPT)
-
-gdb:
- $(TCLSH_ENV) $(PKG_ENV) $(GDB) $(TCLSH_PROG) $(SCRIPT)
-
-gdb-test: binaries libraries
- $(TCLSH_ENV) $(PKG_ENV) $(GDB) \
- --args $(TCLSH_PROG) `@CYGPATH@ $(srcdir)/tests/all.tcl` \
- $(TESTFLAGS) -singleproc 1 \
- -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \
- [list load `@CYGPATH@ $(PKG_LIB_FILE)` [string totitle $(PACKAGE_NAME)]]"
-
-valgrind: binaries libraries
- $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) \
- `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS)
-
-valgrindshell: binaries libraries
- $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) $(SCRIPT)
-
-depend:
-
-#========================================================================
-# $(PKG_LIB_FILE) should be listed as part of the BINARIES variable
-# mentioned above. That will ensure that this target is built when you
-# run "make binaries".
-#
-# The $(PKG_OBJECTS) objects are created and linked into the final
-# library. In most cases these object files will correspond to the
-# source files above.
-#========================================================================
-
-$(PKG_LIB_FILE): $(PKG_OBJECTS)
- -rm -f $(PKG_LIB_FILE)
- ${MAKE_LIB}
- $(RANLIB) $(PKG_LIB_FILE)
-
-$(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS)
- -rm -f $(PKG_STUB_LIB_FILE)
- ${MAKE_STUB_LIB}
- $(RANLIB_STUB) $(PKG_STUB_LIB_FILE)
-
-#========================================================================
-# We need to enumerate the list of .c to .o lines here.
-#
-# In the following lines, $(srcdir) refers to the toplevel directory
-# containing your extension. If your sources are in a subdirectory,
-# you will have to modify the paths to reflect this:
-#
-# sample.$(OBJEXT): $(srcdir)/generic/sample.c
-# $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@
-#
-# Setting the VPATH variable to a list of paths will cause the makefile
-# to look into these paths when resolving .c to .obj dependencies.
-# As necessary, add $(srcdir):$(srcdir)/compat:....
-#========================================================================
-
-VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win:$(srcdir)/macosx
-
-.c.@OBJEXT@:
- $(COMPILE) -c `@CYGPATH@ $<` -o $@
-
-tclsample.@OBJEXT@: sampleUuid.h
-
-$(srcdir)/manifest.uuid:
- printf "git-" >$(srcdir)/manifest.uuid
- (cd $(srcdir); git rev-parse HEAD >>$(srcdir)/manifest.uuid || \
- (printf "svn-r" >$(srcdir)/manifest.uuid ; \
- svn info --show-item last-changed-revision >>$(srcdir)/manifest.uuid) || \
- printf "unknown" >$(srcdir)/manifest.uuid)
-
-sampleUuid.h: $(srcdir)/manifest.uuid
- echo "#define SAMPLE_VERSION_UUID \\" >$@
- cat $(srcdir)/manifest.uuid >>$@
- echo "" >>$@
-
-#========================================================================
-# Distribution creation
-# You may need to tweak this target to make it work correctly.
-#========================================================================
-
-#COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar
-COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR)
-DIST_ROOT = /tmp/dist
-DIST_DIR = $(DIST_ROOT)/$(PKG_DIR)
-
-DIST_INSTALL_DATA = CPPROG='cp -p' $(INSTALL) -m 644
-DIST_INSTALL_SCRIPT = CPPROG='cp -p' $(INSTALL) -m 755
-
-dist-clean:
- rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.*
-
-dist: dist-clean $(srcdir)/manifest.uuid
- $(INSTALL_DATA_DIR) $(DIST_DIR)
-
- # TEA files
- $(DIST_INSTALL_DATA) $(srcdir)/Makefile.in \
- $(srcdir)/aclocal.m4 $(srcdir)/configure.ac \
- $(DIST_DIR)/
- $(DIST_INSTALL_SCRIPT) $(srcdir)/configure $(DIST_DIR)/
-
- $(INSTALL_DATA_DIR) $(DIST_DIR)/tclconfig
- $(DIST_INSTALL_DATA) $(srcdir)/tclconfig/README.txt \
- $(srcdir)/manifest.uuid \
- $(srcdir)/tclconfig/tcl.m4 $(srcdir)/tclconfig/install-sh \
- $(DIST_DIR)/tclconfig/
-
- # Extension files
- $(DIST_INSTALL_DATA) \
- $(srcdir)/ChangeLog \
- $(srcdir)/README.sha \
- $(srcdir)/license.terms \
- $(srcdir)/README \
- $(srcdir)/pkgIndex.tcl.in \
- $(DIST_DIR)/
-
- list='demos doc generic library macosx tests unix win'; \
- for p in $$list; do \
- if test -d $(srcdir)/$$p ; then \
- $(INSTALL_DATA_DIR) $(DIST_DIR)/$$p; \
- $(DIST_INSTALL_DATA) $(srcdir)/$$p/* $(DIST_DIR)/$$p/; \
- fi; \
- done
-
- (cd $(DIST_ROOT); $(COMPRESS);)
-
-#========================================================================
-# End of user-definable section
-#========================================================================
-
-#========================================================================
-# Don't modify the file to clean here. Instead, set the "CLEANFILES"
-# variable in configure.ac
-#========================================================================
-
-clean:
- -test -z "$(BINARIES)" || rm -f $(BINARIES)
- -rm -f *.$(OBJEXT) core *.core
- -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
-
-distclean: clean
- -rm -f *.tab.c
- -rm -f $(CONFIG_CLEAN_FILES)
- -rm -f config.cache config.log config.status
-
-#========================================================================
-# Install binary object libraries. On Windows this includes both .dll and
-# .lib files. Because the .lib files are not explicitly listed anywhere,
-# we need to deduce their existence from the .dll file of the same name.
-# Library files go into the lib directory.
-# In addition, this will generate the pkgIndex.tcl
-# file in the install location (assuming it can find a usable tclsh shell)
-#
-# You should not have to modify this target.
-#========================================================================
-
-install-lib-binaries: binaries
- @$(INSTALL_DATA_DIR) "$(DESTDIR)$(pkglibdir)"
- @list='$(lib_BINARIES)'; for p in $$list; do \
- if test -f $$p; then \
- echo " $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p"; \
- $(INSTALL_LIBRARY) $$p "$(DESTDIR)$(pkglibdir)/$$p"; \
- ext=`echo $$p|sed -e "s/.*\.//"`; \
- if test "x$$ext" = "xdll"; then \
- lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \
- if test -f $$lib; then \
- echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \
- $(INSTALL_DATA) $$lib "$(DESTDIR)$(pkglibdir)/$$lib"; \
- fi; \
- fi; \
- fi; \
- done
- @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \
- if test -f $(srcdir)/$$p; then \
- destp=`basename $$p`; \
- echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \
- $(INSTALL_DATA) $(srcdir)/$$p "$(DESTDIR)$(pkglibdir)/$$destp"; \
- fi; \
- done
- @if test "x$(SHARED_BUILD)" = "x1"; then \
- echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \
- $(INSTALL_DATA) pkgIndex.tcl "$(DESTDIR)$(pkglibdir)"; \
+all:
+#
+# Unless this file is named Makefile.in, you are probably looking
+# at an automatically generated/filtered copy and should probably not
+# edit it.
+#
+# This makefile is part of the teaish framework, a tool for building
+# Tcl extensions, conceptually related to TEA/tclconfig but using the
+# Autosetup configuration system instead of the GNU Autotools.
+#
+# A copy of this makefile gets processed for each extension separately
+# and populated with info about how to build, test, and install the
+# extension.
+#
+# Maintenance reminder: this file needs to stay portable with POSIX
+# Make, not just GNU Make. Yes, that's unfortunate because it makes
+# some things impossible (like skipping over swathes of rules when
+# 'make distclean' is invoked).
+#
+
+CC = @CC@
+INSTALL = @BIN_INSTALL@
+INSTALL.noexec = $(INSTALL) -m 0644
+
+#
+# Var name prefixes:
+#
+# teaish. => teaish core
+# tx. => teaish extension
+#
+# Vars with a "tx." or "teaish." prefix are all "public" for purposes
+# of the extension makefile, but the extension must not any "teaish."
+# vars and must only modify "tx." vars where that allowance is
+# specifically noted.
+#
+# Vars with a "teaish__" prefix are "private" and must not be used by
+# the extension makefile. They may change semantics or be removed in
+# any given teaish build.
+#
+tx.name = @TEAISH_NAME@
+tx.version = @TEAISH_VERSION@
+tx.name.pkg = @TEAISH_PKGNAME@
+tx.libdir = @TEAISH_LIBDIR_NAME@
+tx.loadPrefix = @TEAISH_LOAD_PREFIX@
+tx.tcl = @TEAISH_TCL@
+tx.makefile = @TEAISH_MAKEFILE@
+tx.makefile.in = @TEAISH_MAKEFILE_IN@
+tx.dll8.basename = @TEAISH_DLL8_BASENAME@
+tx.dll9.basename = @TEAISH_DLL9_BASENAME@
+tx.dll8 = @TEAISH_DLL8@
+tx.dll9 = @TEAISH_DLL9@
+tx.dll = $(tx.dll$(TCL_MAJOR_VERSION))
+tx.dir = @TEAISH_EXT_DIR@
+@if TEAISH_TM_TCL
+# Input filename for tcl::tm-style module
+tx.tm = @TEAISH_TM_TCL@
+# Target filename for tcl::tm-style installation
+tx.tm.tgt = $(tx.name.pkg)-$(tx.version).tm
+@endif
+
+@if TEAISH_DIST_NAME
+tx.name.dist = @TEAISH_DIST_NAME@
+@else
+tx.name.dist = $(teaish.name)
+@endif
+
+teaish.dir = @abs_top_srcdir@
+#teaish.dir.autosetup = @TEAISH_AUTOSETUP_DIR@
+teaish.makefile = Makefile
+teaish.makefile.in = $(teaish.dir)/Makefile.in
+teaish__auto.def = $(teaish.dir)/auto.def
+
+#
+# Autotools-conventional vars. We don't actually use these in this
+# makefile but some may be referenced by vars imported via
+# tclConfig.sh. They are part of the public API and may be reliably
+# depended on from teaish.make.in.
+#
+bindir = @bindir@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+includedir = @includedir@
+infodir = @infodir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+prefix = @prefix@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+
+
+#
+# Vars derived (mostly) from tclConfig.sh. These may be reliably
+# used from the extension makefile.
+#
+TCLSH = @TCLSH_CMD@
+TCL_CONFIG_SH = @TCL_CONFIG_SH@
+TCL_EXEC_PREFIX = @TCL_EXEC_PREFIX@
+TCL_INCLUDE_SPEC = @TCL_INCLUDE_SPEC@
+TCL_LIBS = @TCL_LIBS@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_MAJOR_VERSION = @TCL_MAJOR_VERSION@
+TCL_MINOR_VERSION = @TCL_MINOR_VERSION@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_PREFIX = @TCL_PREFIX@
+TCL_SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TCLLIBDIR = @TCLLIBDIR@
+
+#
+# CFLAGS.configure = CFLAGS as known at configure-time.
+#
+# This ordering is deliberate: flags populated via tcl's
+# [teaish-cflags-add] should preceed CFLAGS and CPPFLAGS (which
+# typically come from the ./configure command-line invocation).
+#
+CFLAGS.configure = @SH_CFLAGS@ @TEAISH_CFLAGS@ @CFLAGS@ @CPPFLAGS@ $(TCL_INCLUDE_SPEC)
+#CFLAGS.configure += -DUSE_TCL_STUBS=1
+
+#
+# LDFLAGS.configure = LDFLAGS as known at configure-time.
+#
+# This ordering is deliberate: flags populated via tcl's
+# [teaish-ldflags-add] should precede LDFLAGS (which typically
+# comes from the ./configure command-line invocation).
+#
+LDFLAGS.configure = @TEAISH_LDFLAGS@ @LDFLAGS@
+
+#
+# Linker flags for linkhing a shared library.
+#
+LDFLAGS.shlib = @SH_LDFLAGS@
+
+#
+# The following tx.XYZ vars may be populated/modified by teaish.tcl
+# and/or teaish.make.
+#
+
+#
+# tx.src is the list of source or object files to include in the
+# (single) compiler/linker invocation. This will initially contain any
+# sources passed to [teaish-src-add], but may also be appended to by
+# teaish.make.
+#
+tx.src =@TEAISH_EXT_SRC@
+
+#
+# tx.CFLAGS is typically set by teaish.make, whereas TEAISH_CFLAGS
+# gets set up via the configure script.
+#
+tx.CFLAGS =
+
+#
+# tx.LDFLAGS is typically set by teaish.make, whereas TEAISH_LDFLAGS
+# gets set up via the configure script.
+#
+tx.LDFLAGS =
+
+#
+# The list of 'dist' files may be appended to from teaish.make.in.
+# It can also be set up from teaish.tcl using [teaish-dist-add]
+# and/or [teaish-src-add -dist ...].
+#
+tx.dist.files = @TEAISH_DIST_FILES@
+
+# List of deps which may trigger an auto-reconfigure.
+#
+teaish__autogen.deps = \
+ $(tx.makefile.in) $(teaish.makefile.in) \
+ $(tx.tcl) \
+ @TEAISH_PKGINDEX_TCL_IN@ @TEAISH_TM_TCL_IN@ \
+ @AUTODEPS@
+
+@if TEAISH_MAKEFILE_IN
+$(tx.makefile): $(tx.makefile.in)
+@endif
+
+teaish.autoreconfig = \
+ @TEAISH_AUTORECONFIG@
+
+#
+# Problem: when more than one target can invoke TEAISH_AUTORECONFIG,
+# we can get parallel reconfigures running. Thus, targets which
+# may require reconfigure should depend on...
+#
+config.log: $(teaish__autogen.deps)
+ $(teaish.autoreconfig)
+# ^^^ We would love to skip this when running [dist]clean, but there's
+# no POSIX Make-portable way to do that. GNU Make can.
+.PHONY: reconfigure
+reconfigure:
+ $(teaish.autoreconfig)
+
+$(teaish.makefile): $(teaish__auto.def) $(teaish.makefile.in) \
+ @AUTODEPS@
+
+@if TEAISH_TESTER_TCL_IN
+@TEAISH_TESTER_TCL_IN@:
+@TEAISH_TESTER_TCL@: @TEAISH_TESTER_TCL_IN@
+config.log: @TEAISH_TESTER_TCL@
+@endif
+
+#
+# CC variant for compiling Tcl-using sources.
+#
+CC.tcl = \
+ $(CC) -o $@ $(CFLAGS.configure) $(CFLAGS) $(tx.CFLAGS)
+
+#
+# CC variant for linking $(tx.src) into an extension DLL. Note that
+# $(tx.src) must come before $(LDFLAGS...) for linking to third-party
+# libs to work.
+#
+CC.dll = \
+ $(CC.tcl) $(tx.src) $(LDFLAGS.shlib) \
+ $(LDFLAGS.configure) $(LDFLAGS) $(tx.LDFLAGS) $(TCL_STUB_LIB_SPEC)
+
+@if TEAISH_ENABLE_DLL
+#
+# The rest of this makefile exists solely to support this brief
+# target: the extension shared lib.
+#
+$(tx.dll): $(tx.src) config.log
+ @if [ "x" = "x$(tx.src)" ]; then \
+ echo "Makefile var tx.src (source/object files) is empty" 1>&2; \
+ exit 1; \
fi
+ $(CC.dll)
+
+all: $(tx.dll)
+@endif # TEAISH_ENABLE_DLL
+
+tclsh: $(teaish.makefile) config.log
+ @{ echo "#!/bin/sh"; echo 'exec $(TCLSH) "$$@"'; } > $@
+ @chmod +x $@
+ @echo "Created $@"
+
+#
+# Run the generated test script.
+#
+.PHONY: test-pre test-prepre test-core test test-post test-extension
+test-extension: # this name is reserved for use by teaish.make[.in]
+@if TEAISH_ENABLE_DLL
+test-prepre: $(tx.dll)
+@endif
+@if TEAISH_TESTER_TCL
+test-core.args = @TEAISH_TESTER_TCL@
+@if TEAISH_ENABLE_DLL
+test-core.args += '$(tx.dll)' '$(tx.loadPrefix)'
+@else
+test-core.args += '' ''
+@endif
+test-core.args += @TEAISH_TESTUTIL_TCL@
+test-core: test-pre
+ $(TCLSH) $(test-core.args)
+test-prepre: @TEAISH_TESTER_TCL@
+@else # !TEAISH_TESTER_TCL
+test-prepre:
+@endif # TEAISH_TESTER_TCL
+test-pre: test-prepre
+test-core: test-pre
+test-post: test-core
+test: test-post
-#========================================================================
-# Install binary executables (e.g. .exe files and dependent .dll files)
-# This is for files that must go in the bin directory (located next to
-# wish and tclsh), like dependent .dll files on Windows.
-#
-# You should not have to modify this target, except to define bin_BINARIES
-# above if necessary.
-#========================================================================
-
-install-bin-binaries: binaries
- @$(INSTALL_DATA_DIR) "$(DESTDIR)$(bindir)"
- @list='$(bin_BINARIES)'; for p in $$list; do \
- if test -f $$p; then \
- echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \
- $(INSTALL_PROGRAM) $$p "$(DESTDIR)$(bindir)/$$p"; \
- fi; \
- done
-
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- cd $(top_builddir) \
- && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
-
-uninstall-binaries:
- list='$(lib_BINARIES)'; for p in $$list; do \
- rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \
- done
- list='$(PKG_TCL_SOURCES)'; for p in $$list; do \
- p=`basename $$p`; \
- rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \
- done
- list='$(bin_BINARIES)'; for p in $$list; do \
- rm -f "$(DESTDIR)$(bindir)/$$p"; \
- done
-
-.PHONY: all binaries clean depend distclean doc install libraries test
-.PHONY: gdb gdb-test valgrind valgrindshell
-
-# 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:
+#
+# Cleanup rules...
+#
+#.PHONY: clean-pre clean-core clean-post clean-extension
+#
+clean-pre:
+clean-core: clean-pre
+ rm -f $(tx.dll8) $(tx.dll9) tclsh
+clean-post: clean-core
+clean: clean-post
+
+.PHONY: distclean-pre distclean-core distclean-post clean-extension
+distclean-pre: clean
+distclean-core: distclean-pre
+ rm -f Makefile
+ rm -f config.log config.defines.txt
+@if TEAISH_MAKEFILE_IN
+@if TEAISH_MAKEFILE
+ rm -f @TEAISH_MAKEFILE@
+@endif
+@endif
+@if TEAISH_TESTER_TCL_IN
+ rm -f @TEAISH_TESTER_TCL@
+@endif
+@if TEAISH_PKGINDEX_TCL_IN
+ rm -f @TEAISH_PKGINDEX_TCL@
+@endif
+@if TEAISH_PKGINIT_TCL_IN
+ rm -f @TEAISH_PKGINIT_TCL@
+@endif
+@if TEAISH_TEST_TCL_IN
+ rm -f @TEAISH_TEST_TCL@
+@endif
+distclean-post: distclean-core
+distclean: distclean-post
+#
+# The (dist)clean-extension targets are reserved for use by
+# client-side teaish.make.
+#
+# Client code which wants to clean up extra stuff should do so by
+# adding their cleanup target (e.g. clean-extension) as a dependency
+# to the 'clean' target, like so:
+#
+# clean: distclean-extension
+# distclean: distclean-extension
+#
+distclean-extension:
+clean-extension:
+
+#
+# Installation rules...
+#
+@if TEAISH_ENABLE_INSTALL
+.PHONY: install-pre install-core install-post install-test install-prepre install-extension
+install-extension: # this name is reserved for use by teaish.make
+
+@if TEAISH_ENABLE_DLL
+install-prepre: $(tx.dll)
+@else
+install-prepre:
+@endif
+
+@if TEAISH_TM_TCL
+install-core.tmdir = $(DESTDIR)@TEAISH_TCL_TM_DIR@
+@endif
+
+install-pre: install-prepre
+install-core: install-pre
+ @if [ ! -d "$(DESTDIR)$(TCLLIBDIR)" ]; then \
+ set -x; $(INSTALL) -d "$(DESTDIR)$(TCLLIBDIR)"; \
+ fi
+# ^^^^ on some platforms, install -d fails if the target already exists.
+@if TEAISH_ENABLE_DLL
+ $(INSTALL) $(tx.dll) "$(DESTDIR)$(TCLLIBDIR)"
+@endif
+@if TEAISH_PKGINDEX_TCL
+ $(INSTALL.noexec) "@TEAISH_PKGINDEX_TCL@" "$(DESTDIR)$(TCLLIBDIR)"
+@endif
+@if TEAISH_PKGINIT_TCL
+ $(INSTALL.noexec) "@TEAISH_PKGINIT_TCL@" "$(DESTDIR)$(TCLLIBDIR)"
+@endif
+@if TEAISH_TM_TCL
+ @if [ ! -d "$(install-core.tmdir)" ]; then \
+ set -x; $(INSTALL) -d "$(install-core.tmdir)"; \
+ fi
+ $(INSTALL.noexec) "@TEAISH_TM_TCL@" "$(install-core.tmdir)/$(tx.tm.tgt)"
+@endif
+install-test: install-core
+ @echo "Post-install test of [package require $(tx.name.pkg) $(tx.version)]..."; \
+ if echo \
+ 'set c 0; ' \
+ '@TEAISH_POSTINST_PREREQUIRE@' \
+ 'if {[catch {package require $(tx.name.pkg) $(tx.version)}]} {incr c};' \
+ 'exit $$c' \
+ | $(TCLSH) ; then \
+ echo "passed"; \
+ else \
+ echo "FAILED"; \
+ exit 1; \
+ fi
+install-post: install-test
+install: install-post
+
+#
+# Uninstall rules...
+#
+.PHONY: uninstall uninstall-pre uninstall-core uninstall-post uninstall-extension
+uninstall-extension: # this name is reserved for use by teaish.make
+uninstall-pre:
+uninstall-core: uninstall-pre
+@if TEAISH_ENABLE_DLL
+ rm -fr "$(DESTDIR)$(TCLLIBDIR)"
+@endif
+@if TEAISH_TM_TCL
+ rm -f "$(DESTDIR)$(install-core.tmdir)/$(tx.tm.tgt)"
+@endif
+
+uninstall-post: uninstall-core
+ @echo "Uninstalled Tcl extension $(tx.name) $(tx.version)"
+uninstall: uninstall-post
+@endif # TEAISH_ENABLE_INSTALL
+
+@if TEAISH_MAKEFILE_IN
+Makefile: $(tx.makefile.in)
+config.log: $(teaish.makefile.in)
+@endif
+
+#
+# Package archive generation ("dist") rules...
+#
+@if TEAISH_ENABLE_DIST
+@if BIN_TAR
+@if BIN_ZIP
+
+# When installing teaish as part of "make dist", we need to run
+# configure with similar flags to what we last configured with but we
+# must not pass on any extension-specific flags, as those won't be
+# recognized when running in --teaish-install mode, causing
+# the sub-configure to fail.
+dist.flags = --with-tclsh=$(TCLSH)
+dist.reconfig = $(teaish.dir)/configure $(dist.flags)
+
+# Temp dir for dist.zip. Must be different than dist.tgz or else
+# parallel builds may hose the dist.
+teaish__dist.tmp.zip = teaish__dist_zip
+#
+# Make a distribution zip file...
+#
+dist.basename = $(tx.name.dist)-$(tx.version)
+dist.zip = $(dist.basename).zip
+.PHONY: dist.zip dist.zip-core dist.zip-post
+#dist.zip-pre:
+# We apparently can't add a pre-hook here, else "make dist" rebuilds
+# the archive each time it's run.
+$(dist.zip): $(tx.dist.files)
+ @rm -fr $(teaish__dist.tmp.zip)
+ @mkdir -p $(teaish__dist.tmp.zip)/$(dist.basename)
+ @tar cf $(teaish__dist.tmp.zip)/tmp.tar $(tx.dist.files)
+ @tar xf $(teaish__dist.tmp.zip)/tmp.tar -C $(teaish__dist.tmp.zip)/$(dist.basename)
+@if TEAISH_DIST_FULL
+ @$(dist.reconfig) \
+ --teaish-install=$(teaish__dist.tmp.zip)/$(dist.basename) \
+ --t-e-d=$(teaish__dist.tmp.zip)/$(dist.basename) >/dev/null
+@endif
+ @rm -f $(dist.basename)/tmp.tar $(dist.zip)
+ @cd $(teaish__dist.tmp.zip) && zip -q -r ../$(dist.zip) $(dist.basename)
+ @rm -fr $(teaish__dist.tmp.zip)
+ @ls -la $(dist.zip)
+dist.zip-core: $(dist.zip)
+dist.zip-post: dist.zip-core
+dist.zip: dist.zip-post
+dist: dist.zip
+undist-zip:
+ rm -f $(dist.zip)
+undist: undist-zip
+@endif #BIN_ZIP
+
+#
+# Make a distribution tarball...
+#
+teaish__dist.tmp.tgz = teaish__dist_tgz
+dist.tgz = $(dist.basename).tar.gz
+.PHONY: dist.tgz dist.tgz-core dist.tgz-post
+# dist.tgz-pre:
+# see notes in dist.zip
+$(dist.tgz): $(tx.dist.files)
+ @rm -fr $(teaish__dist.tmp.tgz)
+ @mkdir -p $(teaish__dist.tmp.tgz)/$(dist.basename)
+ @tar cf $(teaish__dist.tmp.tgz)/tmp.tar $(tx.dist.files)
+ @tar xf $(teaish__dist.tmp.tgz)/tmp.tar -C $(teaish__dist.tmp.tgz)/$(dist.basename)
+@if TEAISH_DIST_FULL
+ @rm -f $(teaish__dist.tmp.tgz)/$(dist.basename)/pkgIndex.tcl.in; # kludge
+ @$(dist.reconfig) \
+ --teaish-install=$(teaish__dist.tmp.tgz)/$(dist.basename) \
+ --t-e-d=$(teaish__dist.tmp.zip)/$(dist.basename) >/dev/null
+@endif
+ @rm -f $(dist.basename)/tmp.tar $(dist.tgz)
+ @cd $(teaish__dist.tmp.tgz) && tar czf ../$(dist.tgz) $(dist.basename)
+ @rm -fr $(teaish__dist.tmp.tgz)
+ @ls -la $(dist.tgz)
+dist.tgz-core: $(dist.tgz)
+dist.tgz-post: dist.tgz-core
+dist.tgz: dist.tgz-post
+dist: dist.tgz
+undist-tgz:
+ rm -f $(dist.tgz)
+undist: undist-tgz
+@else #!BIN_TAR
+dist:
+ @echo "The dist rules require tar, which configure did not find." 1>&2; exit 1
+@endif #BIN_TAR
+@else #!TEAISH_ENABLE_DIST
+undist:
+dist:
+@if TEAISH_OUT_OF_EXT_TREE
+ @echo "'dist' can only be used from an extension's home dir" 1>&2; \
+ echo "In this case: @TEAISH_EXT_DIR@" 1>&2; exit 1
+@endif
+@endif #TEAISH_ENABLE_DIST
+
+Makefile: @TEAISH_TCL@
+
+@if TEAISH_MAKEFILE_CODE
+#
+# TEAISH_MAKEFILE_CODE may contain literal makefile code, which
+# gets pasted verbatim here. Either [define TEAISH_MAKEFILE_CODE
+# ...] or use [teaish-make-add] to incrementally build up this
+# content.
+#
+# <TEAISH_MAKEFILE_CODE>
+@TEAISH_MAKEFILE_CODE@
+# </TEAISH_MAKEFILE_CODE>
+@endif
+
+@if TEAISH_MAKEFILE
+#
+# TEAISH_MAKEFILE[_IN] defines any extension-specific state this file
+# needs.
+#
+# It must set the following vars if they're not already accounted for
+# via teaish.tcl.
+#
+# - tx.src = list of the extension's source files, being sure to
+# prefix each with $(tx.dir) (if it's in the same dir as the
+# extension) so that out-of-tree builds can find them. Optionally,
+# [define] TEAISH_EXT_SRC or pass them to [teaish-src-add].
+#
+# It may optionally set the following vars:
+#
+# - tx.CFLAGS = CFLAGS/CPPFLAGS. Optionally, [define] TEAISH_CFLAGS
+# or pass them to [teaish-cflags-add].
+#
+# - tx.LDFLAGS = LDFLAGS. Optionally, [define] TEAISH_LDFLAGS or
+# pass them to [teaish-ldflags-add].
+#
+# It may optionally hook into various targets as documented in
+# /doc/extensions.md in the canonical teaish source tree.
+#
+# Interestingly, we don't have to pre-filter teaish.makefile.in - we
+# can just @include it here. That skips its teaish-specific validation
+# though. Hmm.
+#
+# <TEAISH_MAKEFILE>
+Makefile: @TEAISH_MAKEFILE@
+@include @TEAISH_MAKEFILE@
+# </TEAISH_MAKEFILE>
+@endif
diff --git a/contrib/sqlite3/tea/README b/contrib/sqlite3/tea/README
deleted file mode 100644
index 99dc8b8f03cd..000000000000
--- a/contrib/sqlite3/tea/README
+++ /dev/null
@@ -1,36 +0,0 @@
-This is the SQLite extension for Tcl using the Tcl Extension
-Architecture (TEA). For additional information on SQLite see
-
- http://www.sqlite.org/
-
-
-UNIX BUILD
-==========
-
-Building under most UNIX systems is easy, just run the configure script
-and then run make. For more information about the build process, see
-the tcl/unix/README file in the Tcl src dist. The following minimal
-example will install the extension in the /opt/tcl directory.
-
- $ cd sqlite-*-tea
- $ ./configure --prefix=/opt/tcl
- $ make
- $ make install
-
-WINDOWS BUILD
-=============
-
-The recommended method to build extensions under windows is to use the
-Msys + Mingw build process. This provides a Unix-style build while
-generating native Windows binaries. Using the Msys + Mingw build tools
-means that you can use the same configure script as per the Unix build
-to create a Makefile. See the tcl/win/README file for the URL of
-the Msys + Mingw download.
-
-If you have VC++ then you may wish to use the files in the win
-subdirectory and build the extension using just VC++. These files have
-been designed to be as generic as possible but will require some
-additional maintenance by the project developer to synchronise with
-the TEA configure.in and Makefile.in files. Instructions for using the
-VC++ makefile are written in the first part of the Makefile.vc
-file.
diff --git a/contrib/sqlite3/tea/README.txt b/contrib/sqlite3/tea/README.txt
new file mode 100644
index 000000000000..fb7cb1924854
--- /dev/null
+++ b/contrib/sqlite3/tea/README.txt
@@ -0,0 +1,104 @@
+This is the SQLite extension for Tcl using something akin to
+the Tcl Extension Architecture (TEA). To build it:
+
+ ./configure ...flags...
+
+e.g.:
+
+ ./configure --with-tcl=/path/to/tcl/install/root
+
+or:
+
+ ./configure --with-tclsh=/path/to/tcl/install/root
+
+Run ./configure --help for the full list of flags.
+
+The configuration process will fail if tclConfig.sh cannot be found.
+
+The makefile will only honor CFLAGS and CPPFLAGS passed to the
+configure script, not those directly passed to the makefile.
+
+Then:
+
+ make test install
+
+----------------------- THE PREFERRED WAY ---------------------------
+
+The preferred way to build the TCL extension for SQLite is to use the
+canonical source code tarball. For Unix:
+
+ ./configure --with-tclsh=$(TCLSH)
+ make tclextension-install
+
+For Windows:
+
+ nmake /f Makefile.msc tclextension-install TCLSH_CMD=$(TCLSH)
+
+In both of the above, replace $(TCLSH) with the full pathname of
+of the tclsh that you want the SQLite extension to work with. See
+step-by-step instructions at the links below for more information:
+
+ https://sqlite.org/src/doc/trunk/doc/compile-for-unix.md
+ https://sqlite.org/src/doc/trunk/doc/compile-for-windows.md
+
+And info about the extension's Tcl interface can be found at:
+
+ https://sqlite.org/tclsqlite.html
+
+The whole point of the amalgamation-autoconf tarball (in which this
+README.txt file is embedded) is to provide a means of compiling SQLite
+that does not require first installing TCL and/or "tclsh". The
+canonical Makefile in the SQLite source tree provides more
+capabilities (such as the the ability to run test cases to ensure that
+the build worked) and is better maintained. The only downside of the
+canonical Makefile is that it requires a TCL installation. But if you
+are wanting to build the TCL extension for SQLite, then presumably you
+already have a TCL installation. So why not just use the more-capable
+and better-maintained canoncal Makefile?
+
+As of version 3.50.0, this build process uses "teaish":
+
+ https://fossil.wanderinghorse.net/r/teaish
+
+which is conceptually derived from the pre-3.50 toolchain, TEA:
+
+ http://core.tcl-lang.org/tclconfig
+ http://core.tcl-lang.org/sampleextension
+
+It to works for us. It might also work for you. But we cannot
+promise that.
+
+If you want to use this TEA builder and it works for you, that's fine.
+But if you have trouble, the first thing you should do is go back
+to using the canonical Makefile in the SQLite source tree.
+
+------------------------------------------------------------------
+
+
+UNIX BUILD
+==========
+
+Building under most UNIX systems is easy, just run the configure
+script and then run make. For example:
+
+ $ cd sqlite-*-tea
+ $ ./configure --with-tcl=/path/to/tcl/install/root
+ $ make
+ $ make install
+
+WINDOWS BUILD
+=============
+
+The recommended method to build extensions under windows is to use the
+Msys + Mingw build process. This provides a Unix-style build while
+generating native Windows binaries. Using the Msys + Mingw build tools
+means that you can use the same configure script as per the Unix build
+to create a Makefile. See the tcl/win/README file for the URL of
+the Msys + Mingw download.
+If you have VC++ then you may wish to use the files in the win
+subdirectory and build the extension using just VC++. These files have
+been designed to be as generic as possible but will require some
+additional maintenance by the project developer to synchronise with
+the TEA configure.in and Makefile.in files. Instructions for using the
+VC++ makefile are written in the first part of the Makefile.vc
+file.
diff --git a/contrib/sqlite3/tea/_teaish.tester.tcl.in b/contrib/sqlite3/tea/_teaish.tester.tcl.in
new file mode 100644
index 000000000000..59d11f0a8f6e
--- /dev/null
+++ b/contrib/sqlite3/tea/_teaish.tester.tcl.in
@@ -0,0 +1,49 @@
+# -*- tcl -*-
+#
+# Unless this file is named _teaish.tester.tcl.in, you are probably
+# looking at an automatically generated/filtered copy and should
+# probably not edit it.
+#
+# This is the wrapper script invoked by teaish's "make test" recipe.
+# It gets passed 3 args:
+#
+# $1 = the DLL name, or "" if the extension has no DLL
+#
+# $2 = the "load prefix" for Tcl's [load] or empty if $1 is empty
+#
+# $3 = the /path/to/teaish/tester.tcl (test utility code)
+#
+@if TEAISH_VSATISFIES_CODE
+@TEAISH_VSATISFIES_CODE@
+@endif
+if {[llength [lindex $::argv 0]] > 0} {
+ load [file normalize [lindex $::argv 0]] [lindex $::argv 1];
+ # ----^^^^^^^ needed on Haiku when argv 0 is just a filename, else
+ # load cannot find the file.
+}
+source -encoding utf-8 [lindex $::argv 2]; # teaish/tester.tcl
+@if TEAISH_PKGINIT_TCL
+apply {{file} {
+ set dir [file dirname $::argv0]
+ source -encoding utf-8 $file
+}} [join {@TEAISH_PKGINIT_TCL@}]
+@endif
+@if TEAISH_TM_TCL
+apply {{file} {
+ set dir [file dirname $::argv0]
+ source -encoding utf-8 $file
+}} [join {@TEAISH_TM_TCL@}]
+@endif
+@if TEAISH_TEST_TCL
+apply {{file} {
+ # Populate state for [tester.tcl::teaish-build-flag*]
+ array set ::teaish__BuildFlags @TEAISH__DEFINES_MAP@
+ set dir [file normalize [file dirname $file]]
+ #test-fail "Just testing"
+ source -encoding utf-8 $file
+}} [join {@TEAISH_TEST_TCL@}]
+@else # TEAISH_TEST_TCL
+# No $TEAISH_TEST_TCL provided, so here's a default test which simply
+# loads the extension.
+puts {Extension @TEAISH_NAME@ @TEAISH_VERSION@ successfully loaded from @TEAISH_TESTER_TCL@}
+@endif
diff --git a/contrib/sqlite3/tea/aclocal.m4 b/contrib/sqlite3/tea/aclocal.m4
deleted file mode 100644
index 0b057391d291..000000000000
--- a/contrib/sqlite3/tea/aclocal.m4
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Include the TEA standard macro set
-#
-
-builtin(include,tclconfig/tcl.m4)
-
-#
-# Add here whatever m4 macros you want to define for your package
-#
diff --git a/contrib/sqlite3/tea/auto.def b/contrib/sqlite3/tea/auto.def
new file mode 100644
index 000000000000..7170b3d1fe02
--- /dev/null
+++ b/contrib/sqlite3/tea/auto.def
@@ -0,0 +1,8 @@
+#/do/not/tclsh
+# ^^^ help out editors which guess this file's content type.
+#
+# Main configure script entry point for the TEA(ish) framework. All
+# extension-specific customization goes in teaish.tcl.in or
+# teaish.tcl.
+use teaish/core
+teaish-configure-core
diff --git a/contrib/sqlite3/tea/configure b/contrib/sqlite3/tea/configure
index 2c5190d630e3..47378126f5ab 100755
--- a/contrib/sqlite3/tea/configure
+++ b/contrib/sqlite3/tea/configure
@@ -1,10179 +1,7 @@
-#! /bin/sh
-# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for sqlite 3.46.1.
-#
-#
-# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
-# Inc.
-#
-#
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-as_nop=:
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else $as_nop
- case `(set -o) 2>/dev/null` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac
-fi
-
-
-
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
-as_nl='
-'
-export as_nl
-IFS=" "" $as_nl"
-
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
-if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
-
-# The user is always right.
-if ${PATH_SEPARATOR+false} :; 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
-
-
-# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
- as_myself=$0
-fi
-if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
- exit 1
-fi
-
-
-# Use a proper internal environment variable to ensure we don't fall
- # into an infinite loop, continuously re-executing ourselves.
- if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
- _as_can_reexec=no; export _as_can_reexec;
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
- fi
- # We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
-if test "x$CONFIG_SHELL" = x; then
- as_bourne_compatible="as_nop=:
-if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '\${1+\"\$@\"}'='\"\$@\"'
- setopt NO_GLOB_SUBST
-else \$as_nop
- case \`(set -o) 2>/dev/null\` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac
-fi
-"
- as_required="as_fn_return () { (exit \$1); }
-as_fn_success () { as_fn_return 0; }
-as_fn_failure () { as_fn_return 1; }
-as_fn_ret_success () { return 0; }
-as_fn_ret_failure () { return 1; }
-
-exitcode=0
-as_fn_success || { exitcode=1; echo as_fn_success failed.; }
-as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
-as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
-as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" )
-then :
-
-else \$as_nop
- exitcode=1; echo positional parameters were not saved.
-fi
-test x\$exitcode = x0 || exit 1
-blah=\$(echo \$(echo blah))
-test x\"\$blah\" = xblah || exit 1
-test -x / || exit 1"
- as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
- as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
- eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
- test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
-test \$(( 1 + 1 )) = 2 || exit 1"
- if (eval "$as_required") 2>/dev/null
-then :
- as_have_required=yes
-else $as_nop
- as_have_required=no
-fi
- if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
-then :
-
-else $as_nop
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- as_found=:
- case $as_dir in #(
- /*)
- for as_base in sh bash ksh sh5; do
- # Try only shells that exist, to save several forks.
- as_shell=$as_dir$as_base
- if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
- as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
- CONFIG_SHELL=$as_shell as_have_required=yes
- if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
-then :
- break 2
-fi
-fi
- done;;
- esac
- as_found=false
-done
-IFS=$as_save_IFS
-if $as_found
-then :
-
-else $as_nop
- if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
- as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
- CONFIG_SHELL=$SHELL as_have_required=yes
-fi
-fi
-
-
- if test "x$CONFIG_SHELL" != x
-then :
- export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
-fi
-
- if test x$as_have_required = xno
-then :
- printf "%s\n" "$0: This script requires a shell more modern than all"
- printf "%s\n" "$0: the shells that I found on your system."
- if test ${ZSH_VERSION+y} ; then
- printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
- printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
- else
- printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system,
-$0: including any error possibly output before this
-$0: message. Then install a modern shell, or manually run
-$0: the script under such a shell if you do have one."
- fi
- exit 1
-fi
-fi
-fi
-SHELL=${CONFIG_SHELL-/bin/sh}
-export SHELL
-# Unset more variables known to interfere with behavior of common tools.
-CLICOLOR_FORCE= GREP_OPTIONS=
-unset CLICOLOR_FORCE GREP_OPTIONS
-
-## --------------------- ##
-## M4sh Shell Functions. ##
-## --------------------- ##
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
- { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
- return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
- set +e
- as_fn_set_status $1
- exit $1
-} # as_fn_exit
-# as_fn_nop
-# ---------
-# Do nothing but, unlike ":", preserve the value of $?.
-as_fn_nop ()
-{
- return $?
-}
-as_nop=as_fn_nop
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
- case $as_dir in #(
- -*) as_dir=./$as_dir;;
- esac
- test -d "$as_dir" || eval $as_mkdir_p || {
- as_dirs=
- while :; do
- case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
- *) as_qdir=$as_dir;;
- esac
- as_dirs="'$as_qdir' $as_dirs"
- as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_dir" : 'X\(//\)[^/]' \| \
- X"$as_dir" : 'X\(//\)$' \| \
- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- test -d "$as_dir" && break
- done
- test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
-then :
- eval 'as_fn_append ()
- {
- eval $1+=\$2
- }'
-else $as_nop
- as_fn_append ()
- {
- eval $1=\$$1\$2
- }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
-then :
- eval 'as_fn_arith ()
- {
- as_val=$(( $* ))
- }'
-else $as_nop
- as_fn_arith ()
- {
- as_val=`expr "$@" || test $? -eq 1`
- }
-fi # as_fn_arith
-
-# as_fn_nop
-# ---------
-# Do nothing but, unlike ":", preserve the value of $?.
-as_fn_nop ()
-{
- return $?
-}
-as_nop=as_fn_nop
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
- fi
- printf "%s\n" "$as_me: error: $2" >&2
- as_fn_exit $as_status
-} # as_fn_error
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
- test "X`expr 00001 : '.*\(...\)'`" = X001; then
- as_expr=expr
-else
- as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
- as_basename=basename
-else
- as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
- as_dirname=dirname
-else
- as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
- X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{
- s//\1/
- q
- }
- /^X\/\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\/\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-
- as_lineno_1=$LINENO as_lineno_1a=$LINENO
- as_lineno_2=$LINENO as_lineno_2a=$LINENO
- eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
- test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
- # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
- sed -n '
- p
- /[$]LINENO/=
- ' <$as_myself |
- sed '
- s/[$]LINENO.*/&-/
- t lineno
- b
- :lineno
- N
- :loop
- s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
- t loop
- s/-\n.*//
- ' >$as_me.lineno &&
- chmod +x "$as_me.lineno" ||
- { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
-
- # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
- # already done that, so ensure we don't try to do so again and fall
- # in an infinite loop. This has already happened in practice.
- _as_can_reexec=no; export _as_can_reexec
- # Don't try to exec as it changes $[0], causing all sort of problems
- # (the dirname of $[0] is not the place where we might find the
- # original and so on. Autoconf is especially sensitive to this).
- . "./$as_me.lineno"
- # Exit status is that of the last command.
- exit
-}
-
-
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
- case `echo 'xy\c'` in
- *c*) ECHO_T=' ';; # ECHO_T is single tab character.
- xy) ECHO_C='\c';;
- *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
- ECHO_T=' ';;
- esac;;
-*)
- ECHO_N='-n';;
-esac
-
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
-
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
- rm -f conf$$.dir/conf$$.file
-else
- rm -f conf$$.dir
- mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
- if ln -s conf$$.file conf$$ 2>/dev/null; then
- as_ln_s='ln -s'
- # ... but there are two gotchas:
- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
- elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
- else
- as_ln_s='cp -pR'
- fi
-else
- as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-if mkdir -p . 2>/dev/null; then
- as_mkdir_p='mkdir -p "$as_dir"'
-else
- test -d ./-p && rmdir ./-p
- as_mkdir_p=false
-fi
-
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-test -n "$DJDIR" || exec 7<&0 </dev/null
-exec 6>&1
-
-# Name of the host.
-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
-# so uname gets run too.
-ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
-
-#
-# Initializations.
-#
-ac_default_prefix=/usr/local
-ac_clean_files=
-ac_config_libobj_dir=.
-LIBOBJS=
-cross_compiling=no
-subdirs=
-MFLAGS=
-MAKEFLAGS=
-
-# Identity of this package.
-PACKAGE_NAME='sqlite'
-PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.46.1'
-PACKAGE_STRING='sqlite 3.46.1'
-PACKAGE_BUGREPORT=''
-PACKAGE_URL=''
-
-# Factoring default headers for most tests.
-ac_includes_default="\
-#include <stddef.h>
-#ifdef HAVE_STDIO_H
-# include <stdio.h>
-#endif
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif"
-
-ac_header_c_list=
-ac_subst_vars='LTLIBOBJS
-TCLSH_PROG
-VC_MANIFEST_EMBED_EXE
-VC_MANIFEST_EMBED_DLL
-RANLIB_STUB
-MAKE_STUB_LIB
-MAKE_STATIC_LIB
-MAKE_SHARED_LIB
-MAKE_LIB
-EGREP
-GREP
-LDFLAGS_DEFAULT
-CFLAGS_DEFAULT
-LD_LIBRARY_PATH_VAR
-SHLIB_CFLAGS
-SHLIB_LD_LIBS
-SHLIB_LD
-STLIB_LD
-LDFLAGS_OPTIMIZE
-LDFLAGS_DEBUG
-CFLAGS_WARNING
-CFLAGS_OPTIMIZE
-CFLAGS_DEBUG
-LIBOBJS
-RC
-AR
-STUBS_BUILD
-SHARED_BUILD
-TCL_THREADS
-TCL_INCLUDES
-PKG_OBJECTS
-PKG_SOURCES
-RANLIB
-SET_MAKE
-CPP
-TCL_SHLIB_LD_LIBS
-TCL_LD_FLAGS
-TCL_EXTRA_CFLAGS
-TCL_DEFS
-TCL_LIBS
-CLEANFILES
-OBJEXT
-ac_ct_CC
-CPPFLAGS
-LDFLAGS
-CFLAGS
-CC
-TCL_STUB_LIB_SPEC
-TCL_STUB_LIB_FLAG
-TCL_STUB_LIB_FILE
-TCL_LIB_SPEC
-TCL_LIB_FLAG
-TCL_LIB_FILE
-TCL_SRC_DIR
-TCL_BIN_DIR
-TCL_PATCH_LEVEL
-TCL_VERSION
-INSTALL_LIBRARY
-INSTALL_SCRIPT
-INSTALL_PROGRAM
-INSTALL_DATA
-INSTALL_DATA_DIR
-INSTALL
-PKG_CFLAGS
-PKG_LIBS
-PKG_INCLUDES
-PKG_HEADERS
-PKG_TCL_SOURCES
-PKG_STUB_OBJECTS
-PKG_STUB_SOURCES
-PKG_STUB_LIB_FILE
-PKG_LIB_FILE9
-PKG_LIB_FILE8
-PKG_LIB_FILE
-EXEEXT
-CYGPATH
-target_alias
-host_alias
-build_alias
-LIBS
-ECHO_T
-ECHO_N
-ECHO_C
-DEFS
-mandir
-localedir
-libdir
-psdir
-pdfdir
-dvidir
-htmldir
-infodir
-docdir
-oldincludedir
-includedir
-runstatedir
-localstatedir
-sharedstatedir
-sysconfdir
-datadir
-datarootdir
-libexecdir
-sbindir
-bindir
-program_transform_name
-prefix
-exec_prefix
-PACKAGE_URL
-PACKAGE_BUGREPORT
-PACKAGE_STRING
-PACKAGE_VERSION
-PACKAGE_TARNAME
-PACKAGE_NAME
-PATH_SEPARATOR
-SHELL'
-ac_subst_files=''
-ac_user_opts='
-enable_option_checking
-with_tcl
-with_system_sqlite
-with_tclinclude
-enable_threads
-enable_shared
-enable_stubs
-enable_64bit
-enable_64bit_vis
-enable_rpath
-enable_symbols
-'
- ac_precious_vars='build_alias
-host_alias
-target_alias
-CC
-CFLAGS
-LDFLAGS
-LIBS
-CPPFLAGS
-CPP'
-
-
-# Initialize some variables set by options.
-ac_init_help=
-ac_init_version=false
-ac_unrecognized_opts=
-ac_unrecognized_sep=
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-cache_file=/dev/null
-exec_prefix=NONE
-no_create=
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-verbose=
-x_includes=NONE
-x_libraries=NONE
-
-# Installation directory options.
-# These are left unexpanded so users can "make install exec_prefix=/foo"
-# and all the variables that are supposed to be based on exec_prefix
-# by default will actually change.
-# Use braces instead of parens because sh, perl, etc. also accept them.
-# (The list follows the same order as the GNU Coding Standards.)
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datarootdir='${prefix}/share'
-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}'
-infodir='${datarootdir}/info'
-htmldir='${docdir}'
-dvidir='${docdir}'
-pdfdir='${docdir}'
-psdir='${docdir}'
-libdir='${exec_prefix}/lib'
-localedir='${datarootdir}/locale'
-mandir='${datarootdir}/man'
-
-ac_prev=
-ac_dashdash=
-for ac_option
-do
- # If the previous option needs an argument, assign it.
- if test -n "$ac_prev"; then
- eval $ac_prev=\$ac_option
- ac_prev=
- continue
- fi
-
- case $ac_option in
- *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
- *=) ac_optarg= ;;
- *) ac_optarg=yes ;;
- esac
-
- case $ac_dashdash$ac_option in
- --)
- ac_dashdash=yes ;;
-
- -bindir | --bindir | --bindi | --bind | --bin | --bi)
- ac_prev=bindir ;;
- -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
- bindir=$ac_optarg ;;
-
- -build | --build | --buil | --bui | --bu)
- ac_prev=build_alias ;;
- -build=* | --build=* | --buil=* | --bui=* | --bu=*)
- build_alias=$ac_optarg ;;
-
- -cache-file | --cache-file | --cache-fil | --cache-fi \
- | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
- ac_prev=cache_file ;;
- -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
- | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
- cache_file=$ac_optarg ;;
-
- --config-cache | -C)
- cache_file=config.cache ;;
-
- -datadir | --datadir | --datadi | --datad)
- ac_prev=datadir ;;
- -datadir=* | --datadir=* | --datadi=* | --datad=*)
- datadir=$ac_optarg ;;
-
- -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
- | --dataroo | --dataro | --datar)
- ac_prev=datarootdir ;;
- -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
- | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
- datarootdir=$ac_optarg ;;
-
- -disable-* | --disable-*)
- ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"enable_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval enable_$ac_useropt=no ;;
-
- -docdir | --docdir | --docdi | --doc | --do)
- ac_prev=docdir ;;
- -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
- docdir=$ac_optarg ;;
-
- -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
- ac_prev=dvidir ;;
- -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
- dvidir=$ac_optarg ;;
-
- -enable-* | --enable-*)
- ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"enable_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval enable_$ac_useropt=\$ac_optarg ;;
-
- -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
- | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
- | --exec | --exe | --ex)
- ac_prev=exec_prefix ;;
- -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
- | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
- | --exec=* | --exe=* | --ex=*)
- exec_prefix=$ac_optarg ;;
-
- -gas | --gas | --ga | --g)
- # Obsolete; use --with-gas.
- with_gas=yes ;;
-
- -help | --help | --hel | --he | -h)
- ac_init_help=long ;;
- -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
- ac_init_help=recursive ;;
- -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
- ac_init_help=short ;;
-
- -host | --host | --hos | --ho)
- ac_prev=host_alias ;;
- -host=* | --host=* | --hos=* | --ho=*)
- host_alias=$ac_optarg ;;
-
- -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
- ac_prev=htmldir ;;
- -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
- | --ht=*)
- htmldir=$ac_optarg ;;
-
- -includedir | --includedir | --includedi | --included | --include \
- | --includ | --inclu | --incl | --inc)
- ac_prev=includedir ;;
- -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
- | --includ=* | --inclu=* | --incl=* | --inc=*)
- includedir=$ac_optarg ;;
-
- -infodir | --infodir | --infodi | --infod | --info | --inf)
- ac_prev=infodir ;;
- -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
- infodir=$ac_optarg ;;
-
- -libdir | --libdir | --libdi | --libd)
- ac_prev=libdir ;;
- -libdir=* | --libdir=* | --libdi=* | --libd=*)
- libdir=$ac_optarg ;;
-
- -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
- | --libexe | --libex | --libe)
- ac_prev=libexecdir ;;
- -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
- | --libexe=* | --libex=* | --libe=*)
- libexecdir=$ac_optarg ;;
-
- -localedir | --localedir | --localedi | --localed | --locale)
- ac_prev=localedir ;;
- -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
- localedir=$ac_optarg ;;
-
- -localstatedir | --localstatedir | --localstatedi | --localstated \
- | --localstate | --localstat | --localsta | --localst | --locals)
- ac_prev=localstatedir ;;
- -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
- | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
- localstatedir=$ac_optarg ;;
-
- -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
- ac_prev=mandir ;;
- -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
- mandir=$ac_optarg ;;
-
- -nfp | --nfp | --nf)
- # Obsolete; use --without-fp.
- with_fp=no ;;
-
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c | -n)
- no_create=yes ;;
-
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
- no_recursion=yes ;;
-
- -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
- | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
- | --oldin | --oldi | --old | --ol | --o)
- ac_prev=oldincludedir ;;
- -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
- | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
- | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
- oldincludedir=$ac_optarg ;;
-
- -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
- ac_prev=prefix ;;
- -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
- prefix=$ac_optarg ;;
-
- -program-prefix | --program-prefix | --program-prefi | --program-pref \
- | --program-pre | --program-pr | --program-p)
- ac_prev=program_prefix ;;
- -program-prefix=* | --program-prefix=* | --program-prefi=* \
- | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
- program_prefix=$ac_optarg ;;
-
- -program-suffix | --program-suffix | --program-suffi | --program-suff \
- | --program-suf | --program-su | --program-s)
- ac_prev=program_suffix ;;
- -program-suffix=* | --program-suffix=* | --program-suffi=* \
- | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
- program_suffix=$ac_optarg ;;
-
- -program-transform-name | --program-transform-name \
- | --program-transform-nam | --program-transform-na \
- | --program-transform-n | --program-transform- \
- | --program-transform | --program-transfor \
- | --program-transfo | --program-transf \
- | --program-trans | --program-tran \
- | --progr-tra | --program-tr | --program-t)
- ac_prev=program_transform_name ;;
- -program-transform-name=* | --program-transform-name=* \
- | --program-transform-nam=* | --program-transform-na=* \
- | --program-transform-n=* | --program-transform-=* \
- | --program-transform=* | --program-transfor=* \
- | --program-transfo=* | --program-transf=* \
- | --program-trans=* | --program-tran=* \
- | --progr-tra=* | --program-tr=* | --program-t=*)
- program_transform_name=$ac_optarg ;;
-
- -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
- ac_prev=pdfdir ;;
- -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
- pdfdir=$ac_optarg ;;
-
- -psdir | --psdir | --psdi | --psd | --ps)
- ac_prev=psdir ;;
- -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
- psdir=$ac_optarg ;;
-
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -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=* \
- | --sbi=* | --sb=*)
- sbindir=$ac_optarg ;;
-
- -sharedstatedir | --sharedstatedir | --sharedstatedi \
- | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
- | --sharedst | --shareds | --shared | --share | --shar \
- | --sha | --sh)
- ac_prev=sharedstatedir ;;
- -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
- | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
- | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
- | --sha=* | --sh=*)
- sharedstatedir=$ac_optarg ;;
-
- -site | --site | --sit)
- ac_prev=site ;;
- -site=* | --site=* | --sit=*)
- site=$ac_optarg ;;
-
- -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
- ac_prev=srcdir ;;
- -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
- srcdir=$ac_optarg ;;
-
- -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
- | --syscon | --sysco | --sysc | --sys | --sy)
- ac_prev=sysconfdir ;;
- -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
- | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
- sysconfdir=$ac_optarg ;;
-
- -target | --target | --targe | --targ | --tar | --ta | --t)
- ac_prev=target_alias ;;
- -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
- target_alias=$ac_optarg ;;
-
- -v | -verbose | --verbose | --verbos | --verbo | --verb)
- verbose=yes ;;
-
- -version | --version | --versio | --versi | --vers | -V)
- ac_init_version=: ;;
-
- -with-* | --with-*)
- ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"with_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval with_$ac_useropt=\$ac_optarg ;;
-
- -without-* | --without-*)
- ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"with_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval with_$ac_useropt=no ;;
-
- --x)
- # Obsolete; use --with-x.
- with_x=yes ;;
-
- -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
- | --x-incl | --x-inc | --x-in | --x-i)
- ac_prev=x_includes ;;
- -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
- | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
- x_includes=$ac_optarg ;;
-
- -x-libraries | --x-libraries | --x-librarie | --x-librari \
- | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
- ac_prev=x_libraries ;;
- -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
- | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
- x_libraries=$ac_optarg ;;
-
- -*) as_fn_error $? "unrecognized option: \`$ac_option'
-Try \`$0 --help' for more information"
- ;;
-
- *=*)
- ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
- # Reject names that are not valid shell variable names.
- case $ac_envvar in #(
- '' | [0-9]* | *[!_$as_cr_alnum]* )
- as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
- esac
- eval $ac_envvar=\$ac_optarg
- export $ac_envvar ;;
-
- *)
- # FIXME: should be removed in autoconf 3.0.
- printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2
- expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
- printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2
- : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
- ;;
-
- esac
-done
-
-if test -n "$ac_prev"; then
- ac_option=--`echo $ac_prev | sed 's/_/-/g'`
- as_fn_error $? "missing argument to $ac_option"
-fi
-
-if test -n "$ac_unrecognized_opts"; then
- case $enable_option_checking in
- no) ;;
- fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
- *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
- esac
-fi
-
-# Check all directory arguments for consistency.
-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 runstatedir
-do
- eval ac_val=\$$ac_var
- # Remove trailing slashes.
- case $ac_val in
- */ )
- ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
- eval $ac_var=\$ac_val;;
- esac
- # Be sure to have absolute directory names.
- case $ac_val in
- [\\/$]* | ?:[\\/]* ) continue;;
- NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
- esac
- as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
-done
-
-# There might be people who depend on the old broken behavior: `$host'
-# used to hold the argument of --host etc.
-# FIXME: To remove some day.
-build=$build_alias
-host=$host_alias
-target=$target_alias
-
-# FIXME: To remove some day.
-if test "x$host_alias" != x; then
- if test "x$build_alias" = x; then
- cross_compiling=maybe
- elif test "x$build_alias" != "x$host_alias"; then
- cross_compiling=yes
- fi
-fi
-
-ac_tool_prefix=
-test -n "$host_alias" && ac_tool_prefix=$host_alias-
-
-test "$silent" = yes && exec 6>/dev/null
-
-
-ac_pwd=`pwd` && test -n "$ac_pwd" &&
-ac_ls_di=`ls -di .` &&
-ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
- as_fn_error $? "working directory cannot be determined"
-test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
- as_fn_error $? "pwd does not report name of working directory"
-
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
- ac_srcdir_defaulted=yes
- # Try the directory containing this script, then the parent directory.
- ac_confdir=`$as_dirname -- "$as_myself" ||
-$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_myself" : 'X\(//\)[^/]' \| \
- X"$as_myself" : 'X\(//\)$' \| \
- X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_myself" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- srcdir=$ac_confdir
- if test ! -r "$srcdir/$ac_unique_file"; then
- srcdir=..
- fi
-else
- ac_srcdir_defaulted=no
-fi
-if test ! -r "$srcdir/$ac_unique_file"; then
- test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
- as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
-fi
-ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
-ac_abs_confdir=`(
- cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
- pwd)`
-# When building in place, set srcdir=.
-if test "$ac_abs_confdir" = "$ac_pwd"; then
- srcdir=.
-fi
-# Remove unnecessary trailing slashes from srcdir.
-# Double slashes in file names in object file debugging info
-# mess up M-x gdb in Emacs.
-case $srcdir in
-*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
-esac
-for ac_var in $ac_precious_vars; do
- eval ac_env_${ac_var}_set=\${${ac_var}+set}
- eval ac_env_${ac_var}_value=\$${ac_var}
- eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
- eval ac_cv_env_${ac_var}_value=\$${ac_var}
-done
-
-#
-# Report the --help message.
-#
-if test "$ac_init_help" = "long"; then
- # Omit some internal or obsolete options to make the list less imposing.
- # This message is too long to be a string in the A/UX 3.1 sh.
- cat <<_ACEOF
-\`configure' configures sqlite 3.46.1 to adapt to many kinds of systems.
-
-Usage: $0 [OPTION]... [VAR=VALUE]...
-
-To assign environment variables (e.g., CC, CFLAGS...), specify them as
-VAR=VALUE. See below for descriptions of some of the useful variables.
-
-Defaults for the options are specified in brackets.
-
-Configuration:
- -h, --help display this help and exit
- --help=short display options specific to this package
- --help=recursive display the short help of all the included packages
- -V, --version display version information and exit
- -q, --quiet, --silent do not print \`checking ...' messages
- --cache-file=FILE cache test results in FILE [disabled]
- -C, --config-cache alias for \`--cache-file=config.cache'
- -n, --no-create do not create output files
- --srcdir=DIR find the sources in DIR [configure dir or \`..']
-
-Installation directories:
- --prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
- --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
-
-By default, \`make install' will install all the files in
-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
-an installation prefix other than \`$ac_default_prefix' using \`--prefix',
-for instance \`--prefix=\$HOME'.
-
-For better control, use the options below.
-
-Fine tuning of the installation directories:
- --bindir=DIR user executables [EPREFIX/bin]
- --sbindir=DIR system admin executables [EPREFIX/sbin]
- --libexecdir=DIR program executables [EPREFIX/libexec]
- --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]
- --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
- --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
- --infodir=DIR info documentation [DATAROOTDIR/info]
- --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
- --mandir=DIR man documentation [DATAROOTDIR/man]
- --docdir=DIR documentation root [DATAROOTDIR/doc/sqlite]
- --htmldir=DIR html documentation [DOCDIR]
- --dvidir=DIR dvi documentation [DOCDIR]
- --pdfdir=DIR pdf documentation [DOCDIR]
- --psdir=DIR ps documentation [DOCDIR]
-_ACEOF
-
- cat <<\_ACEOF
-_ACEOF
-fi
-
-if test -n "$ac_init_help"; then
- case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.46.1:";;
- esac
- cat <<\_ACEOF
-
-Optional Features:
- --disable-option-checking ignore unrecognized --enable/--with options
- --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
- --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
- --enable-threads build with threads (default: on)
- --enable-shared build and link with shared libraries (default: on)
- --enable-stubs build and link with stub libraries. Always true for
- shared builds (default: on)
- --enable-64bit enable 64bit support (default: off)
- --enable-64bit-vis enable 64bit Sparc VIS support (default: off)
- --disable-rpath disable rpath support (default: on)
- --enable-symbols build with debugging symbols (default: off)
-
-Optional Packages:
- --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
- --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --with-tcl directory containing tcl configuration
- (tclConfig.sh)
- --with-system-sqlite use a system-supplied libsqlite3 instead of the
- bundled one
- --with-tclinclude directory containing the public Tcl header files
-
-Some influential environment variables:
- CC C compiler command
- CFLAGS C compiler flags
- LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
- LIBS libraries to pass to the linker, e.g. -l<library>
- CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
- CPP C preprocessor
-
-Use these variables to override the choices made by `configure' or to help
-it to find libraries and programs with nonstandard names/locations.
-
-Report bugs to the package provider.
-_ACEOF
-ac_status=$?
-fi
-
-if test "$ac_init_help" = "recursive"; then
- # If there are subdirs, report their specific --help.
- for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
- test -d "$ac_dir" ||
- { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
- continue
- ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
- # A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
- case $ac_top_builddir_sub in
- "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
- esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
- .) # We are building in place.
- ac_srcdir=.
- ac_top_srcdir=$ac_top_builddir_sub
- ac_abs_top_srcdir=$ac_pwd ;;
- [\\/]* | ?:[\\/]* ) # Absolute name.
- ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir
- ac_abs_top_srcdir=$srcdir ;;
- *) # Relative name.
- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_build_prefix$srcdir
- ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
- cd "$ac_dir" || { ac_status=$?; continue; }
- # Check for configure.gnu first; this name is used for a wrapper for
- # Metaconfig's "Configure" on case-insensitive file systems.
- if test -f "$ac_srcdir/configure.gnu"; then
- echo &&
- $SHELL "$ac_srcdir/configure.gnu" --help=recursive
- elif test -f "$ac_srcdir/configure"; then
- echo &&
- $SHELL "$ac_srcdir/configure" --help=recursive
- else
- printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2
- fi || ac_status=$?
- cd "$ac_pwd" || { ac_status=$?; break; }
- done
-fi
-
-test -n "$ac_init_help" && exit $ac_status
-if $ac_init_version; then
- cat <<\_ACEOF
-sqlite configure 3.46.1
-generated by GNU Autoconf 2.71
-
-Copyright (C) 2021 Free Software Foundation, Inc.
-This configure script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it.
-_ACEOF
- exit
-fi
-
-## ------------------------ ##
-## Autoconf initialization. ##
-## ------------------------ ##
-
-# ac_fn_c_try_compile LINENO
-# --------------------------
-# Try to compile conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_compile ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest.beam
- if { { ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compile") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest.$ac_objext
-then :
- ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1
-fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_compile
-
-# ac_fn_c_try_cpp LINENO
-# ----------------------
-# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_cpp ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if { { ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } > conftest.i && {
- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
- test ! -s conftest.err
- }
-then :
- ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1
-fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_cpp
-
-# ac_fn_c_try_run LINENO
-# ----------------------
-# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that
-# executables *can* be run.
-ac_fn_c_try_run ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }
-then :
- ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: program exited with status $ac_status" >&5
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=$ac_status
-fi
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_run
-
-# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists and can be compiled using the include files in
-# INCLUDES, setting the cache variable VAR accordingly.
-ac_fn_c_check_header_compile ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- eval "$3=yes"
-else $as_nop
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_compile
-
-# ac_fn_c_try_link LINENO
-# -----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_link ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest$ac_exeext && {
- test "$cross_compiling" = yes ||
- test -x conftest$ac_exeext
- }
-then :
- ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1
-fi
- # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
- # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
- # interfere with the next link command; also delete a directory that is
- # left behind by Apple's compiler. We do this before executing the actions.
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_link
-
-# ac_fn_c_check_func LINENO FUNC VAR
-# ----------------------------------
-# Tests whether FUNC exists, setting the cache variable VAR accordingly
-ac_fn_c_check_func ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
- For example, HP-UX 11i <limits.h> declares gettimeofday. */
-#define $2 innocuous_$2
-
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $2 (); below. */
-
-#include <limits.h>
-#undef $2
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $2 ();
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined __stub_$2 || defined __stub___$2
-choke me
-#endif
-
-int
-main (void)
-{
-return $2 ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- eval "$3=yes"
-else $as_nop
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_func
-ac_configure_args_raw=
-for ac_arg
-do
- case $ac_arg in
- *\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- as_fn_append ac_configure_args_raw " '$ac_arg'"
-done
-
-case $ac_configure_args_raw in
- *$as_nl*)
- ac_safe_unquote= ;;
- *)
- ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab.
- ac_unsafe_a="$ac_unsafe_z#~"
- ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g"
- ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
-esac
-
-cat >config.log <<_ACEOF
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-
-It was created by sqlite $as_me 3.46.1, which was
-generated by GNU Autoconf 2.71. Invocation command line was
-
- $ $0$ac_configure_args_raw
-
-_ACEOF
-exec 5>>config.log
-{
-cat <<_ASUNAME
-## --------- ##
-## Platform. ##
-## --------- ##
-
-hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
-
-/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
-/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
-/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
-
-_ASUNAME
-
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- printf "%s\n" "PATH: $as_dir"
- done
-IFS=$as_save_IFS
-
-} >&5
-
-cat >&5 <<_ACEOF
-
-
-## ----------- ##
-## Core tests. ##
-## ----------- ##
-
-_ACEOF
-
-
-# Keep a trace of the command line.
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Strip out --silent because we don't want to record it for future runs.
-# Also quote any args containing shell meta-characters.
-# Make two passes to allow for proper duplicate-argument suppression.
-ac_configure_args=
-ac_configure_args0=
-ac_configure_args1=
-ac_must_keep_next=false
-for ac_pass in 1 2
-do
- for ac_arg
- do
- case $ac_arg in
- -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil)
- continue ;;
- *\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- case $ac_pass in
- 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
- 2)
- as_fn_append ac_configure_args1 " '$ac_arg'"
- if test $ac_must_keep_next = true; then
- ac_must_keep_next=false # Got value, back to normal.
- else
- case $ac_arg in
- *=* | --config-cache | -C | -disable-* | --disable-* \
- | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
- | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
- | -with-* | --with-* | -without-* | --without-* | --x)
- case "$ac_configure_args0 " in
- "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
- esac
- ;;
- -* ) ac_must_keep_next=true ;;
- esac
- fi
- as_fn_append ac_configure_args " '$ac_arg'"
- ;;
- esac
- done
-done
-{ ac_configure_args0=; unset ac_configure_args0;}
-{ ac_configure_args1=; unset ac_configure_args1;}
-
-# When interrupted or exit'd, cleanup temporary files, and complete
-# config.log. We remove comments because anyway the quotes in there
-# would cause problems or look ugly.
-# WARNING: Use '\'' to represent an apostrophe within the trap.
-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
-trap 'exit_status=$?
- # Sanitize IFS.
- IFS=" "" $as_nl"
- # Save into config.log some information that might help in debugging.
- {
- echo
-
- printf "%s\n" "## ---------------- ##
-## Cache variables. ##
-## ---------------- ##"
- echo
- # The following way of writing the cache mishandles newlines in values,
-(
- for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
- eval ac_val=\$$ac_var
- case $ac_val in #(
- *${as_nl}*)
- case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
- esac
- case $ac_var in #(
- _ | IFS | as_nl) ;; #(
- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
- *) { eval $ac_var=; unset $ac_var;} ;;
- esac ;;
- esac
- done
- (set) 2>&1 |
- case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
- *${as_nl}ac_space=\ *)
- sed -n \
- "s/'\''/'\''\\\\'\'''\''/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
- ;; #(
- *)
- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
- ;;
- esac |
- sort
-)
- echo
-
- printf "%s\n" "## ----------------- ##
-## Output variables. ##
-## ----------------- ##"
- echo
- for ac_var in $ac_subst_vars
- do
- eval ac_val=\$$ac_var
- case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
- esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
- done | sort
- echo
-
- if test -n "$ac_subst_files"; then
- printf "%s\n" "## ------------------- ##
-## File substitutions. ##
-## ------------------- ##"
- echo
- for ac_var in $ac_subst_files
- do
- eval ac_val=\$$ac_var
- case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
- esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
- done | sort
- echo
- fi
-
- if test -s confdefs.h; then
- printf "%s\n" "## ----------- ##
-## confdefs.h. ##
-## ----------- ##"
- echo
- cat confdefs.h
- echo
- fi
- test "$ac_signal" != 0 &&
- printf "%s\n" "$as_me: caught signal $ac_signal"
- printf "%s\n" "$as_me: exit $exit_status"
- } >&5
- rm -f core *.core core.conftest.* &&
- rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
- exit $exit_status
-' 0
-for ac_signal in 1 2 13 15; do
- trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
-done
-ac_signal=0
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -f -r conftest* confdefs.h
-
-printf "%s\n" "/* confdefs.h */" > confdefs.h
-
-# Predefined preprocessor variables.
-
-printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h
-
-
-# Let the site file select an alternate cache file if it wants to.
-# Prefer an explicitly selected file to automatically selected ones.
-if test -n "$CONFIG_SITE"; then
- ac_site_files="$CONFIG_SITE"
-elif test "x$prefix" != xNONE; then
- ac_site_files="$prefix/share/config.site $prefix/etc/config.site"
-else
- ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
-fi
-
-for ac_site_file in $ac_site_files
-do
- case $ac_site_file in #(
- */*) :
- ;; #(
- *) :
- ac_site_file=./$ac_site_file ;;
-esac
- if test -f "$ac_site_file" && test -r "$ac_site_file"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;}
- sed 's/^/| /' "$ac_site_file" >&5
- . "$ac_site_file" \
- || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed to load site script $ac_site_file
-See \`config.log' for more details" "$LINENO" 5; }
- fi
-done
-
-if test -r "$cache_file"; then
- # Some versions of bash will fail to source /dev/null (special files
- # actually), so we avoid doing that. DJGPP emulates it as a regular file.
- if test /dev/null != "$cache_file" && test -f "$cache_file"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-printf "%s\n" "$as_me: loading cache $cache_file" >&6;}
- case $cache_file in
- [\\/]* | ?:[\\/]* ) . "$cache_file";;
- *) . "./$cache_file";;
- esac
- fi
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-printf "%s\n" "$as_me: creating cache $cache_file" >&6;}
- >$cache_file
-fi
-
-# Test code for whether the C compiler supports C89 (global declarations)
-ac_c_conftest_c89_globals='
-/* Does the compiler advertise C89 conformance?
- Do not test the value of __STDC__, because some compilers set it to 0
- while being otherwise adequately conformant. */
-#if !defined __STDC__
-# error "Compiler does not advertise C89 conformance"
-#endif
-
-#include <stddef.h>
-#include <stdarg.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */
-struct buf { int x; };
-struct buf * (*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 do not provoke an error unfortunately, instead are silently treated
- as an "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 is necessary to write \x00 == 0 to get something
- that is 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 **, int *(*)(struct buf *, struct stat *, int),
- int, int);'
-
-# Test code for whether the C compiler supports C89 (body of main).
-ac_c_conftest_c89_main='
-ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]);
-'
-
-# Test code for whether the C compiler supports C99 (global declarations)
-ac_c_conftest_c99_globals='
-// Does the compiler advertise C99 conformance?
-#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
-# error "Compiler does not advertise C99 conformance"
-#endif
-
-#include <stdbool.h>
-extern int puts (const char *);
-extern int printf (const char *, ...);
-extern int dprintf (int, const char *, ...);
-extern void *malloc (size_t);
-
-// Check varargs macros. These examples are taken from C99 6.10.3.5.
-// dprintf is used instead of fprintf to avoid needing to declare
-// FILE and stderr.
-#define debug(...) dprintf (2, __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
- #error "your preprocessor is broken"
-#endif
-#if BIG_OK
-#else
- #error "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 bool
-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 = 0;
- float fnumber = 0;
-
- 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);
-
- return *str && number && fnumber;
-}
-'
-
-# Test code for whether the C compiler supports C99 (body of main).
-ac_c_conftest_c99_main='
- // Check bool.
- _Bool success = false;
- success |= (argc != 0);
-
- // Check restrict.
- if (test_restrict ("String literal") == 0)
- success = true;
- char *restrict newvar = "Another string";
-
- // Check varargs.
- success &= 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[0] = argv[0][0];
- dynamic_array[ni.number - 1] = 543;
-
- // work around unused variable warnings
- ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\''
- || dynamic_array[ni.number - 1] != 543);
-'
-
-# Test code for whether the C compiler supports C11 (global declarations)
-ac_c_conftest_c11_globals='
-// Does the compiler advertise C11 conformance?
-#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
-# error "Compiler does not advertise C11 conformance"
-#endif
-
-// Check _Alignas.
-char _Alignas (double) aligned_as_double;
-char _Alignas (0) no_special_alignment;
-extern char aligned_as_int;
-char _Alignas (0) _Alignas (int) aligned_as_int;
-
-// Check _Alignof.
-enum
-{
- int_alignment = _Alignof (int),
- int_array_alignment = _Alignof (int[100]),
- char_alignment = _Alignof (char)
-};
-_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
-
-// Check _Noreturn.
-int _Noreturn does_not_return (void) { for (;;) continue; }
-
-// Check _Static_assert.
-struct test_static_assert
-{
- int x;
- _Static_assert (sizeof (int) <= sizeof (long int),
- "_Static_assert does not work in struct");
- long int y;
-};
-
-// Check UTF-8 literals.
-#define u8 syntax error!
-char const utf8_literal[] = u8"happens to be ASCII" "another string";
-
-// Check duplicate typedefs.
-typedef long *long_ptr;
-typedef long int *long_ptr;
-typedef long_ptr long_ptr;
-
-// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
-struct anonymous
-{
- union {
- struct { int i; int j; };
- struct { int k; long int l; } w;
- };
- int m;
-} v1;
-'
-
-# Test code for whether the C compiler supports C11 (body of main).
-ac_c_conftest_c11_main='
- _Static_assert ((offsetof (struct anonymous, i)
- == offsetof (struct anonymous, w.k)),
- "Anonymous union alignment botch");
- v1.i = 2;
- v1.w.k = 5;
- ok |= v1.i != 5;
-'
-
-# Test code for whether the C compiler supports C11 (complete).
-ac_c_conftest_c11_program="${ac_c_conftest_c89_globals}
-${ac_c_conftest_c99_globals}
-${ac_c_conftest_c11_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- ${ac_c_conftest_c99_main}
- ${ac_c_conftest_c11_main}
- return ok;
-}
-"
-
-# Test code for whether the C compiler supports C99 (complete).
-ac_c_conftest_c99_program="${ac_c_conftest_c89_globals}
-${ac_c_conftest_c99_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- ${ac_c_conftest_c99_main}
- return ok;
-}
-"
-
-# Test code for whether the C compiler supports C89 (complete).
-ac_c_conftest_c89_program="${ac_c_conftest_c89_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- return ok;
-}
-"
-
-as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H"
-as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H"
-as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H"
-as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
-as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
-as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
-as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
-as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
-as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
-# Check that the precious variables saved in the cache have kept the same
-# value.
-ac_cache_corrupted=false
-for ac_var in $ac_precious_vars; do
- eval ac_old_set=\$ac_cv_env_${ac_var}_set
- eval ac_new_set=\$ac_env_${ac_var}_set
- eval ac_old_val=\$ac_cv_env_${ac_var}_value
- eval ac_new_val=\$ac_env_${ac_var}_value
- case $ac_old_set,$ac_new_set in
- set,)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,set)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,);;
- *)
- if test "x$ac_old_val" != "x$ac_new_val"; then
- # differences in whitespace do not lead to failure.
- ac_old_val_w=`echo x $ac_old_val`
- ac_new_val_w=`echo x $ac_new_val`
- if test "$ac_old_val_w" != "$ac_new_val_w"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
- ac_cache_corrupted=:
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
- eval $ac_var=\$ac_old_val
- fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
-printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
-printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;}
- fi;;
- esac
- # Pass precious variables to config.status.
- if test "$ac_new_set" = set; then
- case $ac_new_val in
- *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
- *) ac_arg=$ac_var=$ac_new_val ;;
- esac
- case " $ac_configure_args " in
- *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
- *) as_fn_append ac_configure_args " '$ac_arg'" ;;
- esac
- fi
-done
-if $ac_cache_corrupted; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file'
- and start over" "$LINENO" 5
-fi
-## -------------------- ##
-## Main body of script. ##
-## -------------------- ##
-
-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
-
-
-
-#--------------------------------------------------------------------
-# Call TEA_INIT as the first TEA_ macro to set up initial vars.
-# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
-# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
-#--------------------------------------------------------------------
-
-
- TEA_VERSION="3.13"
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking TEA configuration" >&5
-printf %s "checking TEA configuration... " >&6; }
- if test x"${PACKAGE_NAME}" = x ; then
- as_fn_error $? "
-The PACKAGE_NAME variable must be defined by your TEA configure.ac" "$LINENO" 5
- fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5
-printf "%s\n" "ok (TEA ${TEA_VERSION})" >&6; }
-
- # If the user did not set CFLAGS, set it now to keep macros
- # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2".
- if test "${CFLAGS+set}" != "set" ; then
- CFLAGS=""
- fi
-
- case "`uname -s`" in
- *win32*|*WIN32*|*MINGW32_*|*MINGW64_*|*MSYS_*)
- # Extract the first word of "cygpath", so it can be a program name with args.
-set dummy cygpath; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CYGPATH+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$CYGPATH"; then
- ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_CYGPATH="cygpath -m"
- printf "%s\n" "$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 "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo"
-fi
-fi
-CYGPATH=$ac_cv_prog_CYGPATH
-if test -n "$CYGPATH"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5
-printf "%s\n" "$CYGPATH" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- EXEEXT=".exe"
- TEA_PLATFORM="windows"
- ;;
- *CYGWIN_*)
- EXEEXT=".exe"
- # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG
- ;;
- *)
- CYGPATH=echo
- # Maybe we are cross-compiling....
- case ${host_alias} in
- *mingw32*)
- EXEEXT=".exe"
- TEA_PLATFORM="windows"
- ;;
- *)
- EXEEXT=""
- TEA_PLATFORM="unix"
- ;;
- esac
- ;;
- esac
-
- # Check if exec_prefix is set. If not use fall back to prefix.
- # Note when adjusted, so that TEA_PREFIX can correct for this.
- # This is needed for recursive configures, since autoconf propagates
- # $prefix, but not $exec_prefix (doh!).
- if test x$exec_prefix = xNONE ; then
- exec_prefix_default=yes
- exec_prefix=$prefix
- fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&5
-printf "%s\n" "$as_me: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&6;}
-
-
-
-
- # This package name must be replaced statically for AC_SUBST to work
-
-
-
- # Substitute STUB_LIB_FILE in case package creates a stub library too.
-
-
- # We AC_SUBST these here to ensure they are subst'ed,
- # in case the user doesn't call TEA_ADD_...
-
-
-
-
-
-
-
-
- # Configure the installer.
-
- INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c'
- INSTALL_DATA_DIR='${INSTALL} -d -m 755'
- INSTALL_DATA='${INSTALL} -m 644'
- INSTALL_PROGRAM='${INSTALL} -m 755'
- INSTALL_SCRIPT='${INSTALL} -m 755'
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking system version" >&5
-printf %s "checking system version... " >&6; }
-if test ${tcl_cv_sys_version+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- # TEA specific:
- if test "${TEA_PLATFORM}" = "windows" ; then
- tcl_cv_sys_version=windows
- else
- tcl_cv_sys_version=`uname -s`-`uname -r`
- if test "$?" -ne 0 ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5
-printf "%s\n" "$as_me: WARNING: can't find uname command" >&2;}
- tcl_cv_sys_version=unknown
- else
- if test "`uname -s`" = "AIX" ; then
- tcl_cv_sys_version=AIX-`uname -v`.`uname -r`
- fi
- if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then
- tcl_cv_sys_version=NetBSD-Debian
- fi
- fi
- fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5
-printf "%s\n" "$tcl_cv_sys_version" >&6; }
- system=$tcl_cv_sys_version
-
- case $system in
- HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;;
- *) INSTALL_LIBRARY='${INSTALL} -m 644' ;;
- esac
-
-
-
-
-
-
-
-
-
-
-
-
-#--------------------------------------------------------------------
-# Load the tclConfig.sh file
-#--------------------------------------------------------------------
-
-
-
- #
- # Ok, lets find the tcl configuration
- # First, look for one uninstalled.
- # the alternative search directory is invoked by --with-tcl
- #
-
- if test x"${no_tcl}" = x ; then
- # we reset no_tcl in case something fails here
- no_tcl=true
-
-# Check whether --with-tcl was given.
-if test ${with_tcl+y}
-then :
- withval=$with_tcl; with_tclconfig="${withval}"
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5
-printf %s "checking for Tcl configuration... " >&6; }
- if test ${ac_cv_c_tclconfig+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
-
- # First check to see if --with-tcl was specified.
- if test x"${with_tclconfig}" != x ; then
- case "${with_tclconfig}" in
- */tclConfig.sh )
- if test -f "${with_tclconfig}"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&5
-printf "%s\n" "$as_me: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&2;}
- with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`"
- fi ;;
- esac
- if test -f "${with_tclconfig}/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`"
- else
- as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5
- fi
- fi
-
- # then check for a private Tcl installation
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- ../tcl \
- `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
- `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \
- `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \
- ../../tcl \
- `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
- `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \
- `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \
- ../../../tcl \
- `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
- `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \
- `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do
- if test "${TEA_PLATFORM}" = "windows" \
- -a -f "$i/win/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/win; pwd)`"
- break
- fi
- if test -f "$i/unix/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/unix; pwd)`"
- break
- fi
- done
- fi
-
- # on Darwin, check in Framework installation locations
- if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then
- for i in `ls -d ~/Library/Frameworks 2>/dev/null` \
- `ls -d /Library/Frameworks 2>/dev/null` \
- `ls -d /Network/Library/Frameworks 2>/dev/null` \
- `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \
- `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \
- `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \
- ; do
- if test -f "$i/Tcl.framework/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`"
- break
- fi
- done
- fi
-
- # TEA specific: on Windows, check in common installation locations
- if test "${TEA_PLATFORM}" = "windows" \
- -a x"${ac_cv_c_tclconfig}" = x ; then
- for i in `ls -d C:/Tcl/lib 2>/dev/null` \
- `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \
- ; do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i; pwd)`"
- break
- fi
- done
- fi
-
- # check in a few common install locations
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in `ls -d ${libdir} 2>/dev/null` \
- `ls -d ${exec_prefix}/lib 2>/dev/null` \
- `ls -d ${prefix}/lib 2>/dev/null` \
- `ls -d /usr/local/lib 2>/dev/null` \
- `ls -d /usr/contrib/lib 2>/dev/null` \
- `ls -d /usr/pkg/lib 2>/dev/null` \
- `ls -d /usr/lib 2>/dev/null` \
- `ls -d /usr/lib64 2>/dev/null` \
- `ls -d /usr/lib/tcl8.6 2>/dev/null` \
- `ls -d /usr/lib/tcl8.5 2>/dev/null` \
- `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \
- `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \
- `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \
- `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \
- ; do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i; pwd)`"
- break
- fi
- done
- fi
-
- # check in a few other private locations
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- ${srcdir}/../tcl \
- `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
- `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \
- `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do
- if test "${TEA_PLATFORM}" = "windows" \
- -a -f "$i/win/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/win; pwd)`"
- break
- fi
- if test -f "$i/unix/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/unix; pwd)`"
- break
- fi
- done
- fi
-
-fi
-
-
- if test x"${ac_cv_c_tclconfig}" = x ; then
- TCL_BIN_DIR="# no Tcl configs found"
- as_fn_error $? "Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh" "$LINENO" 5
- else
- no_tcl=
- TCL_BIN_DIR="${ac_cv_c_tclconfig}"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found ${TCL_BIN_DIR}/tclConfig.sh" >&5
-printf "%s\n" "found ${TCL_BIN_DIR}/tclConfig.sh" >&6; }
- 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
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$ac_ct_CC" && break
-done
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
-set dummy ${ac_tool_prefix}clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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}clang"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "clang", so it can be a program name with args.
-set dummy clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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="clang"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-
-fi
-
-
-test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$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.
-printf "%s\n" "$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 -version; 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\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
- 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
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-done
-
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
-# Try to create an executable without -o first, disregard a.out.
-# It will help us diagnose broken compilers, and finding out an intuition
-# of exeext.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-printf %s "checking whether the C compiler works... " >&6; }
-ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-
-# The possible output files:
-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
-
-ac_rmfiles=
-for ac_file in $ac_files
-do
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
- * ) ac_rmfiles="$ac_rmfiles $ac_file";;
- esac
-done
-rm -f $ac_rmfiles
-
-if { { ac_try="$ac_link_default"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link_default") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
-# in a Makefile. We should not override ac_cv_exeext if it was cached,
-# so that the user can short-circuit this test for compilers unknown to
-# Autoconf.
-for ac_file in $ac_files ''
-do
- test -f "$ac_file" || continue
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
- ;;
- [ab].out )
- # We found the default executable, but exeext='' is most
- # certainly right.
- break;;
- *.* )
- if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no;
- then :; else
- ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- fi
- # We set ac_cv_exeext here because the later test for it is not
- # safe: cross compilers may not add the suffix if given an `-o'
- # argument, so we may need to know it at that point already.
- # Even if this section looks crufty: it has the advantage of
- # actually working.
- break;;
- * )
- break;;
- esac
-done
-test "$ac_cv_exeext" = no && ac_cv_exeext=
-
-else $as_nop
- ac_file=''
-fi
-if test -z "$ac_file"
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "C compiler cannot create executables
-See \`config.log' for more details" "$LINENO" 5; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-printf %s "checking for C compiler default output file name... " >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-printf "%s\n" "$ac_file" >&6; }
-ac_exeext=$ac_cv_exeext
-
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
-ac_clean_files=$ac_clean_files_save
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-printf %s "checking for suffix of executables... " >&6; }
-if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- # If both `conftest.exe' and `conftest' are `present' (well, observable)
-# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
-# work properly (i.e., refer to `conftest.exe'), while it won't with
-# `rm'.
-for ac_file in conftest.exe conftest conftest.*; do
- test -f "$ac_file" || continue
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
- *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- break;;
- * ) break;;
- esac
-done
-else $as_nop
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest conftest$ac_cv_exeext
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-printf "%s\n" "$ac_cv_exeext" >&6; }
-
-rm -f conftest.$ac_ext
-EXEEXT=$ac_cv_exeext
-ac_exeext=$EXEEXT
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdio.h>
-int
-main (void)
-{
-FILE *f = fopen ("conftest.out", "w");
- return ferror (f) || fclose (f) != 0;
-
- ;
- return 0;
-}
-_ACEOF
-ac_clean_files="$ac_clean_files conftest.out"
-# Check that the compiler produces executables we can run. If not, either
-# the compiler is broken, or we cross compile.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-printf %s "checking whether we are cross compiling... " >&6; }
-if test "$cross_compiling" != yes; then
- { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- if { ac_try='./conftest$ac_cv_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }; then
- cross_compiling=no
- else
- if test "$cross_compiling" = maybe; then
- cross_compiling=yes
- else
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details" "$LINENO" 5; }
- fi
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-printf "%s\n" "$cross_compiling" >&6; }
-
-rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
-ac_clean_files=$ac_clean_files_save
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-printf %s "checking for suffix of object files... " >&6; }
-if test ${ac_cv_objext+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.o conftest.obj
-if { { ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compile") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- for ac_file in conftest.o conftest.obj conftest.*; do
- test -f "$ac_file" || continue;
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
- *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
- break;;
- esac
-done
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest.$ac_cv_objext conftest.$ac_ext
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-printf "%s\n" "$ac_cv_objext" >&6; }
-OBJEXT=$ac_cv_objext
-ac_objext=$OBJEXT
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
-printf %s "checking whether the compiler supports GNU C... " >&6; }
-if test ${ac_cv_c_compiler_gnu+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_compiler_gnu=yes
-else $as_nop
- ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-if test $ac_compiler_gnu = yes; then
- GCC=yes
-else
- GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+y}
-ac_save_CFLAGS=$CFLAGS
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-printf %s "checking whether $CC accepts -g... " >&6; }
-if test ${ac_cv_prog_cc_g+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_g=yes
-else $as_nop
- CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else $as_nop
- ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- 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.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
-if test $ac_test_CFLAGS; 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
-ac_prog_cc_stdc=no
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
-printf %s "checking for $CC option to enable C11 features... " >&6; }
-if test ${ac_cv_prog_cc_c11+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c11=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c11_program
-_ACEOF
-for ac_arg in '' -std=gnu11
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c11=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c11" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c11" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c11" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
-printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
- CC="$CC $ac_cv_prog_cc_c11"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
- ac_prog_cc_stdc=c11
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
-printf %s "checking for $CC option to enable C99 features... " >&6; }
-if test ${ac_cv_prog_cc_c99+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c99=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c99_program
-_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
-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 conftest.beam
- test "x$ac_cv_prog_cc_c99" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c99" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c99" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
- CC="$CC $ac_cv_prog_cc_c99"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
- ac_prog_cc_stdc=c99
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
-printf %s "checking for $CC option to enable C89 features... " >&6; }
-if test ${ac_cv_prog_cc_c89+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c89_program
-_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 conftest.beam
- test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c89" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c89" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
- CC="$CC $ac_cv_prog_cc_c89"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
- ac_prog_cc_stdc=c89
-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
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for existence of ${TCL_BIN_DIR}/tclConfig.sh" >&5
-printf %s "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... " >&6; }
-
- if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: loading" >&5
-printf "%s\n" "loading" >&6; }
- . "${TCL_BIN_DIR}/tclConfig.sh"
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5
-printf "%s\n" "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; }
- fi
-
- # If the TCL_BIN_DIR is the build directory (not the install directory),
- # then set the common variable name to the value of the build variables.
- # For example, the variable TCL_LIB_SPEC will be set to the value
- # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
- # instead of TCL_BUILD_LIB_SPEC since it will work with both an
- # installed and uninstalled version of Tcl.
- if test -f "${TCL_BIN_DIR}/Makefile" ; then
- TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}"
- TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}"
- TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}"
- elif test "`uname -s`" = "Darwin"; then
- # If Tcl was built as a framework, attempt to use the libraries
- # from the framework at the given location so that linking works
- # against Tcl.framework installed in an arbitrary location.
- case ${TCL_DEFS} in
- *TCL_FRAMEWORK*)
- if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then
- for i in "`cd "${TCL_BIN_DIR}"; pwd`" \
- "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do
- if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then
- TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}"
- break
- fi
- done
- fi
- if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then
- TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}"
- TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"
- fi
- ;;
- esac
- fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking platform" >&5
-printf %s "checking platform... " >&6; }
- hold_cc=$CC; CC="$TCL_CC"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- #ifdef _WIN32
- #error win32
- #endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
- # first test we've already retrieved platform (cross-compile), fallback to unix otherwise:
- TEA_PLATFORM="${TEA_PLATFORM-unix}"
- CYGPATH=echo
-
-else $as_nop
-
- TEA_PLATFORM="windows"
- # Extract the first word of "cygpath", so it can be a program name with args.
-set dummy cygpath; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CYGPATH+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$CYGPATH"; then
- ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_CYGPATH="cygpath -m"
- printf "%s\n" "$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 "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo"
-fi
-fi
-CYGPATH=$ac_cv_prog_CYGPATH
-if test -n "$CYGPATH"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5
-printf "%s\n" "$CYGPATH" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- CC=$hold_cc
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEA_PLATFORM" >&5
-printf "%s\n" "$TEA_PLATFORM" >&6; }
-
- # The BUILD_$pkg is to define the correct extern storage class
- # handling when making this package
-
-printf "%s\n" "#define BUILD_${PACKAGE_NAME} /**/" >>confdefs.h
-
- # Do this here as we have fully defined TEA_PLATFORM now
- if test "${TEA_PLATFORM}" = "windows" ; then
- EXEEXT=".exe"
- CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp"
- fi
-
- # TEA specific:
-
-
-
-
-
-
-
-
-#--------------------------------------------------------------------
-# Load the tkConfig.sh file if necessary (Tk extension)
-#--------------------------------------------------------------------
-
-#TEA_PATH_TKCONFIG
-#TEA_LOAD_TKCONFIG
-
-#-----------------------------------------------------------------------
-# Handle the --prefix=... option by defaulting to what Tcl gave.
-# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER.
-#-----------------------------------------------------------------------
-
-
- if test "${prefix}" = "NONE"; then
- prefix_default=yes
- if test x"${TCL_PREFIX}" != x; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&5
-printf "%s\n" "$as_me: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&6;}
- prefix=${TCL_PREFIX}
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --prefix defaulting to /usr/local" >&5
-printf "%s\n" "$as_me: --prefix defaulting to /usr/local" >&6;}
- prefix=/usr/local
- fi
- fi
- if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \
- -o x"${exec_prefix_default}" = x"yes" ; then
- if test x"${TCL_EXEC_PREFIX}" != x; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&5
-printf "%s\n" "$as_me: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&6;}
- exec_prefix=${TCL_EXEC_PREFIX}
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to ${prefix}" >&5
-printf "%s\n" "$as_me: --exec-prefix defaulting to ${prefix}" >&6;}
- exec_prefix=$prefix
- fi
- fi
-
-
-#-----------------------------------------------------------------------
-# Standard compiler checks.
-# This sets up CC by using the CC env var, or looks for gcc otherwise.
-# This also calls AC_PROG_CC and a few others to create the basic setup
-# necessary to compile executables.
-#-----------------------------------------------------------------------
-
-
- # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE)
- # in this macro, they need to go into TEA_SETUP_COMPILER instead.
-
- 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 -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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$ac_ct_CC" && break
-done
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
-set dummy ${ac_tool_prefix}clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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}clang"
- printf "%s\n" "$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
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "clang", so it can be a program name with args.
-set dummy clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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="clang"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-
-fi
-
-
-test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$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.
-printf "%s\n" "$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 -version; 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\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
- 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
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-done
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
-printf %s "checking whether the compiler supports GNU C... " >&6; }
-if test ${ac_cv_c_compiler_gnu+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_compiler_gnu=yes
-else $as_nop
- ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-if test $ac_compiler_gnu = yes; then
- GCC=yes
-else
- GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+y}
-ac_save_CFLAGS=$CFLAGS
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-printf %s "checking whether $CC accepts -g... " >&6; }
-if test ${ac_cv_prog_cc_g+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_g=yes
-else $as_nop
- CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else $as_nop
- ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- 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.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
-if test $ac_test_CFLAGS; 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
-ac_prog_cc_stdc=no
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
-printf %s "checking for $CC option to enable C11 features... " >&6; }
-if test ${ac_cv_prog_cc_c11+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c11=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c11_program
-_ACEOF
-for ac_arg in '' -std=gnu11
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c11=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c11" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c11" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c11" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
-printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
- CC="$CC $ac_cv_prog_cc_c11"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
- ac_prog_cc_stdc=c11
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
-printf %s "checking for $CC option to enable C99 features... " >&6; }
-if test ${ac_cv_prog_cc_c99+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c99=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c99_program
-_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
-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 conftest.beam
- test "x$ac_cv_prog_cc_c99" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c99" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c99" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
- CC="$CC $ac_cv_prog_cc_c99"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
- ac_prog_cc_stdc=c99
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
-printf %s "checking for $CC option to enable C89 features... " >&6; }
-if test ${ac_cv_prog_cc_c89+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c89_program
-_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 conftest.beam
- test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c89" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c89" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
- CC="$CC $ac_cv_prog_cc_c89"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
- ac_prog_cc_stdc=c89
-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=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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-printf %s "checking how to run the C preprocessor... " >&6; }
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
- CPP=
-fi
-if test -z "$CPP"; then
- if test ${ac_cv_prog_CPP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- # Double quotes because $CC needs to be expanded
- for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp
- do
- ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <limits.h>
- Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
-
-else $as_nop
- # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
- # OK, works on sane cases. Now check whether nonexistent headers
- # can be detected and how.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
- # Broken: success on invalid input.
-continue
-else $as_nop
- # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok
-then :
- break
-fi
-
- done
- ac_cv_prog_CPP=$CPP
-
-fi
- CPP=$ac_cv_prog_CPP
-else
- ac_cv_prog_CPP=$CPP
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-printf "%s\n" "$CPP" >&6; }
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <limits.h>
- Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
-
-else $as_nop
- # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
- # OK, works on sane cases. Now check whether nonexistent headers
- # can be detected and how.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
- # Broken: success on invalid input.
-continue
-else $as_nop
- # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok
-then :
-
-else $as_nop
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-ac_ext=c
-ac_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
-
-
- #--------------------------------------------------------------------
- # Checks to see if the make program sets the $MAKE variable.
- #--------------------------------------------------------------------
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
-printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
-set x ${MAKE-make}
-ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
-if eval test \${ac_cv_prog_make_${ac_make}_set+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- SET_MAKE=
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- SET_MAKE="MAKE=${MAKE-make}"
-fi
-
-
- #--------------------------------------------------------------------
- # Find ranlib
- #--------------------------------------------------------------------
-
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_RANLIB="${ac_tool_prefix}ranlib"
- printf "%s\n" "$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
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-printf "%s\n" "$RANLIB" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
- ac_ct_RANLIB=$RANLIB
- # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_RANLIB"; then
- ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_RANLIB="ranlib"
- printf "%s\n" "$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_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-printf "%s\n" "$ac_ct_RANLIB" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_RANLIB" = x; then
- RANLIB=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- RANLIB=$ac_ct_RANLIB
- fi
-else
- RANLIB="$ac_cv_prog_RANLIB"
-fi
-
-
- #--------------------------------------------------------------------
- # Determines the correct binary file extension (.o, .obj, .exe etc.)
- #--------------------------------------------------------------------
-
-
-
-
-ac_header= ac_cache=
-for ac_item in $ac_header_c_list
-do
- if test $ac_cache; then
- ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
- if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
- printf "%s\n" "#define $ac_item 1" >> confdefs.h
- fi
- ac_header= ac_cache=
- elif test $ac_header; then
- ac_cache=$ac_item
- else
- ac_header=$ac_item
- fi
-done
-
-
-
-
-
-
-
-
-if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
-then :
-
-printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-
- # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here.
-
-
- #------------------------------------------------------------------------
- # If we're using GCC, see if the compiler understands -pipe. If so, use it.
- # It makes compiling go faster. (This is only a performance feature.)
- #------------------------------------------------------------------------
-
- if test -z "$no_pipe" -a -n "$GCC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the compiler understands -pipe" >&5
-printf %s "checking if the compiler understands -pipe... " >&6; }
-if test ${tcl_cv_cc_pipe+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_cc_pipe=yes
-else $as_nop
- tcl_cv_cc_pipe=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- CFLAGS=$hold_cflags
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_pipe" >&5
-printf "%s\n" "$tcl_cv_cc_pipe" >&6; }
- if test $tcl_cv_cc_pipe = yes; then
- CFLAGS="$CFLAGS -pipe"
- fi
- fi
-
- #--------------------------------------------------------------------
- # Common compiler flag setup
- #--------------------------------------------------------------------
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
-printf %s "checking whether byte ordering is bigendian... " >&6; }
-if test ${ac_cv_c_bigendian+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_c_bigendian=unknown
- # 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.beam 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>
-
-int
-main (void)
-{
-#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
- && defined LITTLE_ENDIAN && 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
-/* end confdefs.h. */
-#include <sys/types.h>
- #include <sys/param.h>
-
-int
-main (void)
-{
-#if BYTE_ORDER != BIG_ENDIAN
- not big endian
- #endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_c_bigendian=yes
-else $as_nop
- ac_cv_c_bigendian=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam 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 (void)
-{
-#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 (void)
-{
-#ifndef _BIG_ENDIAN
- not big endian
- #endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_c_bigendian=yes
-else $as_nop
- ac_cv_c_bigendian=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- 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. */
-unsigned short int ascii_mm[] =
- { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
- unsigned short int ascii_ii[] =
- { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
- int use_ascii (int i) {
- return ascii_mm[i] + ascii_ii[i];
- }
- unsigned short int ebcdic_ii[] =
- { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
- unsigned 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 (void)
-{
-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.beam conftest.$ac_ext
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_includes_default
-int
-main (void)
-{
-
- /* 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 :
- ac_cv_c_bigendian=no
-else $as_nop
- ac_cv_c_bigendian=yes
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
-printf "%s\n" "$ac_cv_c_bigendian" >&6; }
- case $ac_cv_c_bigendian in #(
- yes)
- printf "%s\n" "#define WORDS_BIGENDIAN 1" >>confdefs.h
-;; #(
- no)
- ;; #(
- universal)
-
-printf "%s\n" "#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
-
-
-
-#-----------------------------------------------------------------------
-# __CHANGE__
-# Specify the C source files to compile in TEA_ADD_SOURCES,
-# public headers that need to be installed in TEA_ADD_HEADERS,
-# stub library C source files to compile in TEA_ADD_STUB_SOURCES,
-# and runtime Tcl library files in TEA_ADD_TCL_SOURCES.
-# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS
-# and PKG_TCL_SOURCES.
-#-----------------------------------------------------------------------
-
-
- vars="tclsqlite3.c"
- for i in $vars; do
- case $i in
- \$*)
- # allow $-var names
- PKG_SOURCES="$PKG_SOURCES $i"
- PKG_OBJECTS="$PKG_OBJECTS $i"
- ;;
- *)
- # check for existence - allows for generic/win/unix VPATH
- # To add more dirs here (like 'src'), you have to update VPATH
- # in Makefile.in as well
- if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \
- -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \
- -a ! -f "${srcdir}/macosx/$i" \
- ; then
- as_fn_error $? "could not find source file '$i'" "$LINENO" 5
- fi
- PKG_SOURCES="$PKG_SOURCES $i"
- # this assumes it is in a VPATH dir
- i=`basename $i`
- # handle user calling this before or after TEA_SETUP_COMPILER
- if test x"${OBJEXT}" != x ; then
- j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}"
- else
- j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}"
- fi
- PKG_OBJECTS="$PKG_OBJECTS $j"
- ;;
- esac
- done
-
-
-
-
- vars=""
- for i in $vars; do
- # check for existence, be strict because it is installed
- if test ! -f "${srcdir}/$i" ; then
- as_fn_error $? "could not find header file '${srcdir}/$i'" "$LINENO" 5
- fi
- PKG_HEADERS="$PKG_HEADERS $i"
- done
-
-
-
- vars=""
- for i in $vars; do
- PKG_INCLUDES="$PKG_INCLUDES $i"
- done
-
-
-
- vars=""
- for i in $vars; do
- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
- # Convert foo.lib to -lfoo for GCC. No-op if not *.lib
- i=`echo "$i" | sed -e 's/^\([^-].*\)\.[lL][iI][bB]$/-l\1/'`
- fi
- PKG_LIBS="$PKG_LIBS $i"
- done
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_FTS3=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_FTS4=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_FTS5=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_3_SUFFIX_ONLY=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_RTREE=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_GEOPOLY=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_DESERIALIZE=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_DBPAGE_VTAB=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_BYTECODE_VTAB=1"
-
-
-
- PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_DBSTAT_VTAB=1"
-
-
-
- vars=""
- for i in $vars; do
- # check for existence - allows for generic/win/unix VPATH
- if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \
- -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \
- -a ! -f "${srcdir}/macosx/$i" \
- ; then
- as_fn_error $? "could not find stub source file '$i'" "$LINENO" 5
- fi
- PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i"
- # this assumes it is in a VPATH dir
- i=`basename $i`
- # handle user calling this before or after TEA_SETUP_COMPILER
- if test x"${OBJEXT}" != x ; then
- j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}"
- else
- j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}"
- fi
- PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j"
- done
-
-
-
-
- vars=""
- for i in $vars; do
- # check for existence, be strict because it is installed
- if test ! -f "${srcdir}/$i" ; then
- as_fn_error $? "could not find tcl source file '${srcdir}/$i'" "$LINENO" 5
- fi
- PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i"
- done
-
-
-
-#--------------------------------------------------------------------
-# The --with-system-sqlite causes the TCL bindings to SQLite to use
-# the system shared library for SQLite rather than statically linking
-# against its own private copy. This is dangerous and leads to
-# undersirable dependences and is not recommended.
-# Patchs from rmax.
-#--------------------------------------------------------------------
-
-# Check whether --with-system-sqlite was given.
-if test ${with_system_sqlite+y}
-then :
- withval=$with_system_sqlite;
-else $as_nop
- with_system_sqlite=no
-fi
-
-if test x$with_system_sqlite != xno; then
- ac_fn_c_check_header_compile "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default"
-if test "x$ac_cv_header_sqlite3_h" = xyes
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_initialize in -lsqlite3" >&5
-printf %s "checking for sqlite3_initialize in -lsqlite3... " >&6; }
-if test ${ac_cv_lib_sqlite3_sqlite3_initialize+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsqlite3 $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. */
-char sqlite3_initialize ();
-int
-main (void)
-{
-return sqlite3_initialize ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_sqlite3_sqlite3_initialize=yes
-else $as_nop
- ac_cv_lib_sqlite3_sqlite3_initialize=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_initialize" >&5
-printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_initialize" >&6; }
-if test "x$ac_cv_lib_sqlite3_sqlite3_initialize" = xyes
-then :
- printf "%s\n" "#define USE_SYSTEM_SQLITE 1" >>confdefs.h
-
- LIBS="$LIBS -lsqlite3"
-fi
-
-fi
-
-fi
-
-#--------------------------------------------------------------------
-# __CHANGE__
-#
-# You can add more files to clean if your extension creates any extra
-# files by extending CLEANFILES.
-# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
-# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
-#
-# A few miscellaneous platform-specific items:
-# TEA_ADD_* any platform specific compiler/build info here.
-#--------------------------------------------------------------------
-
-#CLEANFILES="$CLEANFILES pkgIndex.tcl"
-if test "${TEA_PLATFORM}" = "windows" ; then
- # Ensure no empty if clauses
- :
- #TEA_ADD_SOURCES([win/winFile.c])
- #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"])
-else
- # Ensure no empty else clauses
- :
- #TEA_ADD_SOURCES([unix/unixFile.c])
- #TEA_ADD_LIBS([-lsuperfly])
-fi
-
-#--------------------------------------------------------------------
-# __CHANGE__
-# Choose which headers you need. Extension authors should try very
-# hard to only rely on the Tcl public header files. Internal headers
-# contain private data structures and are subject to change without
-# notice.
-# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG
-#--------------------------------------------------------------------
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Tcl public headers" >&5
-printf %s "checking for Tcl public headers... " >&6; }
-
-
-# Check whether --with-tclinclude was given.
-if test ${with_tclinclude+y}
-then :
- withval=$with_tclinclude; with_tclinclude=${withval}
-fi
-
-
- if test ${ac_cv_c_tclh+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- # Use the value from --with-tclinclude, if it was given
-
- if test x"${with_tclinclude}" != x ; then
- if test -f "${with_tclinclude}/tcl.h" ; then
- ac_cv_c_tclh=${with_tclinclude}
- else
- as_fn_error $? "${with_tclinclude} directory does not contain tcl.h" "$LINENO" 5
- fi
- else
- list=""
- if test "`uname -s`" = "Darwin"; then
- # If Tcl was built as a framework, attempt to use
- # the framework's Headers directory
- case ${TCL_DEFS} in
- *TCL_FRAMEWORK*)
- list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`"
- ;;
- esac
- fi
-
- # Look in the source dir only if Tcl is not installed,
- # and in that situation, look there before installed locations.
- if test -f "${TCL_BIN_DIR}/Makefile" ; then
- list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`"
- fi
-
- # Check order: pkg --prefix location, Tcl's --prefix location,
- # relative to directory of tclConfig.sh.
-
- eval "temp_includedir=${includedir}"
- list="$list \
- `ls -d ${temp_includedir} 2>/dev/null` \
- `ls -d ${TCL_PREFIX}/include 2>/dev/null` \
- `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`"
- if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then
- list="$list /usr/local/include /usr/include"
- if test x"${TCL_INCLUDE_SPEC}" != x ; then
- d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'`
- list="$list `ls -d ${d} 2>/dev/null`"
- fi
- fi
- for i in $list ; do
- if test -f "$i/tcl.h" ; then
- ac_cv_c_tclh=$i
- break
- fi
- done
- fi
-
-fi
-
-
- # Print a message based on how we determined the include path
-
- if test x"${ac_cv_c_tclh}" = x ; then
- as_fn_error $? "tcl.h not found. Please specify its location with --with-tclinclude" "$LINENO" 5
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tclh}" >&5
-printf "%s\n" "${ac_cv_c_tclh}" >&6; }
- fi
-
- # Convert to a native path and substitute into the output files.
-
- INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}`
-
- TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\"
-
-
-
-#TEA_PRIVATE_TCL_HEADERS
-
-#TEA_PUBLIC_TK_HEADERS
-#TEA_PRIVATE_TK_HEADERS
-#TEA_PATH_X
-
-#--------------------------------------------------------------------
-# Check whether --enable-threads or --disable-threads was given.
-# This auto-enables if Tcl was compiled threaded.
-#--------------------------------------------------------------------
-
-
- # Check whether --enable-threads was given.
-if test ${enable_threads+y}
-then :
- enableval=$enable_threads; tcl_ok=$enableval
-else $as_nop
- tcl_ok=yes
-fi
-
-
- if test "${enable_threads+set}" = set; then
- enableval="$enable_threads"
- tcl_ok=$enableval
- else
- tcl_ok=yes
- fi
-
- if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then
- TCL_THREADS=1
-
- if test "${TEA_PLATFORM}" != "windows" ; then
- # We are always OK on Windows, so check what this platform wants:
-
- # USE_THREAD_ALLOC tells us to try the special thread-based
- # allocator that significantly reduces lock contention
-
-printf "%s\n" "#define USE_THREAD_ALLOC 1" >>confdefs.h
-
-
-printf "%s\n" "#define _REENTRANT 1" >>confdefs.h
-
- if test "`uname -s`" = "SunOS" ; then
-
-printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
-
- fi
-
-printf "%s\n" "#define _THREAD_SAFE 1" >>confdefs.h
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5
-printf %s "checking for pthread_mutex_init in -lpthread... " >&6; }
-if test ${ac_cv_lib_pthread_pthread_mutex_init+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpthread $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. */
-char pthread_mutex_init ();
-int
-main (void)
-{
-return pthread_mutex_init ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_pthread_pthread_mutex_init=yes
-else $as_nop
- ac_cv_lib_pthread_pthread_mutex_init=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5
-printf "%s\n" "$ac_cv_lib_pthread_pthread_mutex_init" >&6; }
-if test "x$ac_cv_lib_pthread_pthread_mutex_init" = xyes
-then :
- tcl_ok=yes
-else $as_nop
- tcl_ok=no
-fi
-
- if test "$tcl_ok" = "no"; then
- # Check a little harder for __pthread_mutex_init in the same
- # library, as some systems hide it there until pthread.h is
- # defined. We could alternatively do an AC_TRY_COMPILE with
- # pthread.h, but that will work with libpthread really doesn't
- # exist, like AIX 4.2. [Bug: 4359]
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5
-printf %s "checking for __pthread_mutex_init in -lpthread... " >&6; }
-if test ${ac_cv_lib_pthread___pthread_mutex_init+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpthread $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. */
-char __pthread_mutex_init ();
-int
-main (void)
-{
-return __pthread_mutex_init ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_pthread___pthread_mutex_init=yes
-else $as_nop
- ac_cv_lib_pthread___pthread_mutex_init=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5
-printf "%s\n" "$ac_cv_lib_pthread___pthread_mutex_init" >&6; }
-if test "x$ac_cv_lib_pthread___pthread_mutex_init" = xyes
-then :
- tcl_ok=yes
-else $as_nop
- tcl_ok=no
-fi
-
- fi
-
- if test "$tcl_ok" = "yes"; then
- # The space is needed
- THREADS_LIBS=" -lpthread"
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5
-printf %s "checking for pthread_mutex_init in -lpthreads... " >&6; }
-if test ${ac_cv_lib_pthreads_pthread_mutex_init+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpthreads $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. */
-char pthread_mutex_init ();
-int
-main (void)
-{
-return pthread_mutex_init ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_pthreads_pthread_mutex_init=yes
-else $as_nop
- ac_cv_lib_pthreads_pthread_mutex_init=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5
-printf "%s\n" "$ac_cv_lib_pthreads_pthread_mutex_init" >&6; }
-if test "x$ac_cv_lib_pthreads_pthread_mutex_init" = xyes
-then :
- tcl_ok=yes
-else $as_nop
- tcl_ok=no
-fi
-
- if test "$tcl_ok" = "yes"; then
- # The space is needed
- THREADS_LIBS=" -lpthreads"
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5
-printf %s "checking for pthread_mutex_init in -lc... " >&6; }
-if test ${ac_cv_lib_c_pthread_mutex_init+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lc $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. */
-char pthread_mutex_init ();
-int
-main (void)
-{
-return pthread_mutex_init ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_c_pthread_mutex_init=yes
-else $as_nop
- ac_cv_lib_c_pthread_mutex_init=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_mutex_init" >&5
-printf "%s\n" "$ac_cv_lib_c_pthread_mutex_init" >&6; }
-if test "x$ac_cv_lib_c_pthread_mutex_init" = xyes
-then :
- tcl_ok=yes
-else $as_nop
- tcl_ok=no
-fi
-
- if test "$tcl_ok" = "no"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5
-printf %s "checking for pthread_mutex_init in -lc_r... " >&6; }
-if test ${ac_cv_lib_c_r_pthread_mutex_init+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lc_r $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. */
-char pthread_mutex_init ();
-int
-main (void)
-{
-return pthread_mutex_init ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_c_r_pthread_mutex_init=yes
-else $as_nop
- ac_cv_lib_c_r_pthread_mutex_init=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5
-printf "%s\n" "$ac_cv_lib_c_r_pthread_mutex_init" >&6; }
-if test "x$ac_cv_lib_c_r_pthread_mutex_init" = xyes
-then :
- tcl_ok=yes
-else $as_nop
- tcl_ok=no
-fi
-
- if test "$tcl_ok" = "yes"; then
- # The space is needed
- THREADS_LIBS=" -pthread"
- else
- TCL_THREADS=0
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5
-printf "%s\n" "$as_me: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&2;}
- fi
- fi
- fi
- fi
- fi
- else
- TCL_THREADS=0
- fi
- # Do checking message here to not mess up interleaved configure output
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5
-printf %s "checking for building with threads... " >&6; }
- if test "${TCL_THREADS}" = 1; then
-
-printf "%s\n" "#define TCL_THREADS 1" >>confdefs.h
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5
-printf "%s\n" "yes (default)" >&6; }
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- fi
- # TCL_THREADS sanity checking. See if our request for building with
- # threads is the same as the way Tcl was built. If not, warn the user.
- case ${TCL_DEFS} in
- *THREADS=1*)
- if test "${TCL_THREADS}" = "0"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING:
- Building ${PACKAGE_NAME} without threads enabled, but building against Tcl
- that IS thread-enabled. It is recommended to use --enable-threads." >&5
-printf "%s\n" "$as_me: WARNING:
- Building ${PACKAGE_NAME} without threads enabled, but building against Tcl
- that IS thread-enabled. It is recommended to use --enable-threads." >&2;}
- fi
- ;;
- esac
-
-
-if test "${TCL_THREADS}" = "1" ; then
-
-printf "%s\n" "#define SQLITE_THREADSAFE 1" >>confdefs.h
-
- # Not automatically added by Tcl because its assumed Tcl links to them,
- # but it may not if it isn't really a threaded build.
-
- vars="$THREADS_LIBS"
- for i in $vars; do
- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
- # Convert foo.lib to -lfoo for GCC. No-op if not *.lib
- i=`echo "$i" | sed -e 's/^\([^-].*\)\.[lL][iI][bB]$/-l\1/'`
- fi
- PKG_LIBS="$PKG_LIBS $i"
- done
-
-
-else
-
-printf "%s\n" "#define SQLITE_THREADSAFE 0" >>confdefs.h
-
-fi
-
-#--------------------------------------------------------------------
-# The statement below defines a collection of symbols related to
-# building as a shared library instead of a static library.
-#--------------------------------------------------------------------
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5
-printf %s "checking how to build libraries... " >&6; }
- # Check whether --enable-shared was given.
-if test ${enable_shared+y}
-then :
- enableval=$enable_shared; shared_ok=$enableval
-else $as_nop
- shared_ok=yes
-fi
-
-
- if test "${enable_shared+set}" = set; then
- enableval="$enable_shared"
- shared_ok=$enableval
- else
- shared_ok=yes
- fi
-
- # Check whether --enable-stubs was given.
-if test ${enable_stubs+y}
-then :
- enableval=$enable_stubs; stubs_ok=$enableval
-else $as_nop
- stubs_ok=yes
-fi
-
-
- if test "${enable_stubs+set}" = set; then
- enableval="$enable_stubs"
- stubs_ok=$enableval
- else
- stubs_ok=yes
- fi
-
- # Stubs are always enabled for shared builds
- if test "$shared_ok" = "yes" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: shared" >&5
-printf "%s\n" "shared" >&6; }
- SHARED_BUILD=1
- STUBS_BUILD=1
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: static" >&5
-printf "%s\n" "static" >&6; }
- SHARED_BUILD=0
-
-printf "%s\n" "#define STATIC_BUILD 1" >>confdefs.h
-
- if test "$stubs_ok" = "yes" ; then
- STUBS_BUILD=1
- else
- STUBS_BUILD=0
- fi
- fi
- if test "${STUBS_BUILD}" = "1" ; then
-
-printf "%s\n" "#define USE_TCL_STUBS 1" >>confdefs.h
-
-
-printf "%s\n" "#define USE_TCLOO_STUBS 1" >>confdefs.h
-
- if test "${TEA_WINDOWINGSYSTEM}" != ""; then
-
-printf "%s\n" "#define USE_TK_STUBS 1" >>confdefs.h
-
- fi
- fi
-
-
-
-
-
-#--------------------------------------------------------------------
-# This macro figures out what flags to use with the compiler/linker
-# when building shared/static debug/optimized objects. This information
-# can be taken from the tclConfig.sh file, but this figures it all out.
-#--------------------------------------------------------------------
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_RANLIB="${ac_tool_prefix}ranlib"
- printf "%s\n" "$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
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-printf "%s\n" "$RANLIB" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
- ac_ct_RANLIB=$RANLIB
- # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_RANLIB"; then
- ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_RANLIB="ranlib"
- printf "%s\n" "$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_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-printf "%s\n" "$ac_ct_RANLIB" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_RANLIB" = x; then
- RANLIB=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- RANLIB=$ac_ct_RANLIB
- fi
-else
- RANLIB="$ac_cv_prog_RANLIB"
-fi
-
-
-
-
- # Step 0.a: Enable 64 bit support?
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5
-printf %s "checking if 64bit support is requested... " >&6; }
- # Check whether --enable-64bit was given.
-if test ${enable_64bit+y}
-then :
- enableval=$enable_64bit; do64bit=$enableval
-else $as_nop
- do64bit=no
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $do64bit" >&5
-printf "%s\n" "$do64bit" >&6; }
-
- # Step 0.b: Enable Solaris 64 bit VIS support?
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if 64bit Sparc VIS support is requested" >&5
-printf %s "checking if 64bit Sparc VIS support is requested... " >&6; }
- # Check whether --enable-64bit-vis was given.
-if test ${enable_64bit_vis+y}
-then :
- enableval=$enable_64bit_vis; do64bitVIS=$enableval
-else $as_nop
- do64bitVIS=no
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $do64bitVIS" >&5
-printf "%s\n" "$do64bitVIS" >&6; }
- # Force 64bit on with VIS
- if test "$do64bitVIS" = "yes"
-then :
- do64bit=yes
-fi
-
- # Step 0.c: Check if visibility support is available. Do this here so
- # that platform specific alternatives can be used below if this fails.
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler supports visibility \"hidden\"" >&5
-printf %s "checking if compiler supports visibility \"hidden\"... " >&6; }
-if test ${tcl_cv_cc_visibility_hidden+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
- extern __attribute__((__visibility__("hidden"))) void f(void);
- void f(void) {}
-int
-main (void)
-{
-f();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_cc_visibility_hidden=yes
-else $as_nop
- tcl_cv_cc_visibility_hidden=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- CFLAGS=$hold_cflags
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_visibility_hidden" >&5
-printf "%s\n" "$tcl_cv_cc_visibility_hidden" >&6; }
- if test $tcl_cv_cc_visibility_hidden = yes
-then :
-
-
-printf "%s\n" "#define MODULE_SCOPE extern __attribute__((__visibility__(\"hidden\")))" >>confdefs.h
-
-
-printf "%s\n" "#define HAVE_HIDDEN 1" >>confdefs.h
-
-
-fi
-
- # Step 0.d: Disable -rpath support?
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if rpath support is requested" >&5
-printf %s "checking if rpath support is requested... " >&6; }
- # Check whether --enable-rpath was given.
-if test ${enable_rpath+y}
-then :
- enableval=$enable_rpath; doRpath=$enableval
-else $as_nop
- doRpath=yes
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $doRpath" >&5
-printf "%s\n" "$doRpath" >&6; }
-
- # Set the variable "system" to hold the name and version number
- # for the system.
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking system version" >&5
-printf %s "checking system version... " >&6; }
-if test ${tcl_cv_sys_version+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- # TEA specific:
- if test "${TEA_PLATFORM}" = "windows" ; then
- tcl_cv_sys_version=windows
- else
- tcl_cv_sys_version=`uname -s`-`uname -r`
- if test "$?" -ne 0 ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5
-printf "%s\n" "$as_me: WARNING: can't find uname command" >&2;}
- tcl_cv_sys_version=unknown
- else
- if test "`uname -s`" = "AIX" ; then
- tcl_cv_sys_version=AIX-`uname -v`.`uname -r`
- fi
- if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then
- tcl_cv_sys_version=NetBSD-Debian
- fi
- fi
- fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5
-printf "%s\n" "$tcl_cv_sys_version" >&6; }
- system=$tcl_cv_sys_version
-
-
- # Require ranlib early so we can override it in special cases below.
-
-
-
- # Set configuration options based on system name and version.
- # This is similar to Tcl's unix/tcl.m4 except that we've added a
- # "windows" case and removed some core-only vars.
-
- do64bit_ok=no
- # default to '{$LIBS}' and set to "" on per-platform necessary basis
- SHLIB_LD_LIBS='${LIBS}'
- # When ld needs options to work in 64-bit mode, put them in
- # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load]
- # is disabled by the user. [Bug 1016796]
- LDFLAGS_ARCH=""
- UNSHARED_LIB_SUFFIX=""
- # TEA specific: use PACKAGE_VERSION instead of VERSION
- TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`'
- ECHO_VERSION='`echo ${PACKAGE_VERSION}`'
- TCL_LIB_VERSIONS_OK=ok
- CFLAGS_DEBUG=-g
- if test "$GCC" = yes
-then :
-
- CFLAGS_OPTIMIZE=-O2
- CFLAGS_WARNING="-Wall"
-
-else $as_nop
-
- CFLAGS_OPTIMIZE=-O
- CFLAGS_WARNING=""
-
-fi
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ar; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_AR+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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}ar"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
-printf "%s\n" "$AR" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_AR"; then
- ac_ct_AR=$AR
- # Extract the first word of "ar", so it can be a program name with args.
-set dummy ar; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_AR+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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="ar"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
-printf "%s\n" "$ac_ct_AR" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_AR" = x; then
- AR=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- AR=$ac_ct_AR
- fi
-else
- AR="$ac_cv_prog_AR"
-fi
-
- STLIB_LD='${AR} cr'
- LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH"
- if test "x$SHLIB_VERSION" = x
-then :
- SHLIB_VERSION=""
-else $as_nop
- SHLIB_VERSION=".$SHLIB_VERSION"
-fi
- case $system in
- # TEA specific:
- windows)
- MACHINE="X86"
- if test "$do64bit" != "no" ; then
- case "$do64bit" in
- amd64|x64|yes)
- MACHINE="AMD64" ; # default to AMD64 64-bit build
- ;;
- arm64|aarch64)
- MACHINE="ARM64"
- ;;
- ia64)
- MACHINE="IA64"
- ;;
- esac
- fi
-
- if test "$GCC" != "yes" ; then
- if test "${SHARED_BUILD}" = "0" ; then
- runtime=-MT
- else
- runtime=-MD
- fi
- case "x`echo \${VisualStudioVersion}`" in
- x1[4-9]*)
- lflags="${lflags} -nodefaultlib:libucrt.lib"
-
- vars="ucrt.lib"
- for i in $vars; do
- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
- # Convert foo.lib to -lfoo for GCC. No-op if not *.lib
- i=`echo "$i" | sed -e 's/^\([^-].*\)\.[lL][iI][bB]$/-l\1/'`
- fi
- PKG_LIBS="$PKG_LIBS $i"
- done
-
-
- ;;
- *)
- ;;
- esac
-
- if test "$do64bit" != "no" ; then
- CC="cl.exe"
- RC="rc.exe"
- lflags="${lflags} -nologo -MACHINE:${MACHINE} "
- LINKBIN="link.exe"
- CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d"
- CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
- # Avoid 'unresolved external symbol __security_cookie'
- # errors, c.f. http://support.microsoft.com/?id=894573
-
- vars="bufferoverflowU.lib"
- for i in $vars; do
- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
- # Convert foo.lib to -lfoo for GCC. No-op if not *.lib
- i=`echo "$i" | sed -e 's/^\([^-].*\)\.[lL][iI][bB]$/-l\1/'`
- fi
- PKG_LIBS="$PKG_LIBS $i"
- done
-
-
- else
- RC="rc"
- lflags="${lflags} -nologo"
- LINKBIN="link"
- CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d"
- CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
- fi
- fi
-
- if test "$GCC" = "yes"; then
- # mingw gcc mode
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args.
-set dummy ${ac_tool_prefix}windres; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_RC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$RC"; then
- ac_cv_prog_RC="$RC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_RC="${ac_tool_prefix}windres"
- printf "%s\n" "$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
-RC=$ac_cv_prog_RC
-if test -n "$RC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RC" >&5
-printf "%s\n" "$RC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_RC"; then
- ac_ct_RC=$RC
- # Extract the first word of "windres", so it can be a program name with args.
-set dummy windres; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_RC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_RC"; then
- ac_cv_prog_ac_ct_RC="$ac_ct_RC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- 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_RC="windres"
- printf "%s\n" "$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_RC=$ac_cv_prog_ac_ct_RC
-if test -n "$ac_ct_RC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RC" >&5
-printf "%s\n" "$ac_ct_RC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_RC" = x; then
- RC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- RC=$ac_ct_RC
- fi
-else
- RC="$ac_cv_prog_RC"
-fi
-
- CFLAGS_DEBUG="-g"
- CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
- SHLIB_LD='${CC} -shared'
- UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
- LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}"
- LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}"
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cross-compile version of gcc" >&5
-printf %s "checking for cross-compile version of gcc... " >&6; }
-if test ${ac_cv_cross+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
- #ifdef _WIN32
- #error cross-compiler
- #endif
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_cross=yes
-else $as_nop
- ac_cv_cross=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cross" >&5
-printf "%s\n" "$ac_cv_cross" >&6; }
- if test "$ac_cv_cross" = "yes"; then
- case "$do64bit" in
- amd64|x64|yes)
- CC="x86_64-w64-mingw32-${CC}"
- LD="x86_64-w64-mingw32-ld"
- AR="x86_64-w64-mingw32-ar"
- RANLIB="x86_64-w64-mingw32-ranlib"
- RC="x86_64-w64-mingw32-windres"
- ;;
- arm64|aarch64)
- CC="aarch64-w64-mingw32-clang"
- LD="aarch64-w64-mingw32-ld"
- AR="aarch64-w64-mingw32-ar"
- RANLIB="aarch64-w64-mingw32-ranlib"
- RC="aarch64-w64-mingw32-windres"
- ;;
- *)
- CC="i686-w64-mingw32-${CC}"
- LD="i686-w64-mingw32-ld"
- AR="i686-w64-mingw32-ar"
- RANLIB="i686-w64-mingw32-ranlib"
- RC="i686-w64-mingw32-windres"
- ;;
- esac
- fi
-
- else
- SHLIB_LD="${LINKBIN} -dll ${lflags}"
- # link -lib only works when -lib is the first arg
- STLIB_LD="${LINKBIN} -lib ${lflags}"
- UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib'
- PATHTYPE=-w
- # For information on what debugtype is most useful, see:
- # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp
- # and also
- # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx
- # This essentially turns it all on.
- LDFLAGS_DEBUG="-debug -debugtype:cv"
- LDFLAGS_OPTIMIZE="-release"
- LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
- LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
- fi
-
- SHLIB_SUFFIX=".dll"
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll'
-
- TCL_LIB_VERSIONS_OK=nodots
- ;;
- AIX-*)
- if test "$GCC" != "yes"
-then :
-
- # AIX requires the _r compiler when gcc isn't being used
- case "${CC}" in
- *_r|*_r\ *)
- # ok ...
- ;;
- *)
- # Make sure only first arg gets _r
- CC=`echo "$CC" | sed -e 's/^\([^ ]*\)/\1_r/'`
- ;;
- esac
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using $CC for compiling with threads" >&5
-printf "%s\n" "Using $CC for compiling with threads" >&6; }
-
-fi
- LIBS="$LIBS -lc"
- SHLIB_CFLAGS=""
- SHLIB_SUFFIX=".so"
-
- LD_LIBRARY_PATH_VAR="LIBPATH"
-
- # Check to enable 64-bit flags for compiler/linker
- if test "$do64bit" = yes
-then :
-
- if test "$GCC" = yes
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5
-printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;}
-
-else $as_nop
-
- do64bit_ok=yes
- CFLAGS="$CFLAGS -q64"
- LDFLAGS_ARCH="-q64"
- RANLIB="${RANLIB} -X64"
- AR="${AR} -X64"
- SHLIB_LD_FLAGS="-b64"
-
-fi
-
-fi
-
- if test "`uname -m`" = ia64
-then :
-
- # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC
- SHLIB_LD="/usr/ccs/bin/ld -G -z text"
- if test "$GCC" = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
-
-else $as_nop
-
- CC_SEARCH_FLAGS='"-R${LIB_RUNTIME_DIR}"'
-
-fi
- LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
-
-else $as_nop
-
- if test "$GCC" = yes
-then :
-
- SHLIB_LD='${CC} -shared -Wl,-bexpall'
-
-else $as_nop
-
- SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry"
- LDFLAGS="$LDFLAGS -brtl"
-
-fi
- SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}"
- CC_SEARCH_FLAGS='"-L${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
-
-fi
- ;;
- BeOS*)
- SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} -nostart'
- SHLIB_SUFFIX=".so"
-
- #-----------------------------------------------------------
- # Check for inet_ntoa in -lbind, for BeOS (which also needs
- # -lsocket, even if the network functions are in -lnet which
- # is always linked to, for compatibility.
- #-----------------------------------------------------------
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lbind" >&5
-printf %s "checking for inet_ntoa in -lbind... " >&6; }
-if test ${ac_cv_lib_bind_inet_ntoa+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lbind $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. */
-char inet_ntoa ();
-int
-main (void)
-{
-return inet_ntoa ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_bind_inet_ntoa=yes
-else $as_nop
- ac_cv_lib_bind_inet_ntoa=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bind_inet_ntoa" >&5
-printf "%s\n" "$ac_cv_lib_bind_inet_ntoa" >&6; }
-if test "x$ac_cv_lib_bind_inet_ntoa" = xyes
-then :
- LIBS="$LIBS -lbind -lsocket"
-fi
-
- ;;
- BSD/OS-2.1*|BSD/OS-3*)
- SHLIB_CFLAGS=""
- SHLIB_LD="shlicc -r"
- SHLIB_SUFFIX=".so"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- BSD/OS-4.*)
- SHLIB_CFLAGS="-export-dynamic -fPIC"
- SHLIB_LD='${CC} -shared'
- SHLIB_SUFFIX=".so"
- LDFLAGS="$LDFLAGS -export-dynamic"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- CYGWIN_*)
- SHLIB_CFLAGS=""
- SHLIB_LD='${CC} -shared'
- SHLIB_SUFFIX=".dll"
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$@.a"
- EXEEXT=".exe"
- do64bit_ok=yes
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- dgux*)
- SHLIB_CFLAGS="-K PIC"
- SHLIB_LD='${CC} -G'
- SHLIB_LD_LIBS=""
- SHLIB_SUFFIX=".so"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- Haiku*)
- LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
- SHLIB_CFLAGS="-fPIC"
- SHLIB_SUFFIX=".so"
- SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5
-printf %s "checking for inet_ntoa in -lnetwork... " >&6; }
-if test ${ac_cv_lib_network_inet_ntoa+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lnetwork $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. */
-char inet_ntoa ();
-int
-main (void)
-{
-return inet_ntoa ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_network_inet_ntoa=yes
-else $as_nop
- ac_cv_lib_network_inet_ntoa=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_inet_ntoa" >&5
-printf "%s\n" "$ac_cv_lib_network_inet_ntoa" >&6; }
-if test "x$ac_cv_lib_network_inet_ntoa" = xyes
-then :
- LIBS="$LIBS -lnetwork"
-fi
-
- ;;
- HP-UX-*.11.*)
- # Use updated header definitions where possible
-
-printf "%s\n" "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h
-
- # TEA specific: Needed by Tcl, but not most extensions
- #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?])
- #LIBS="$LIBS -lxnet" # Use the XOPEN network library
-
- if test "`uname -m`" = ia64
-then :
-
- SHLIB_SUFFIX=".so"
-
-else $as_nop
-
- SHLIB_SUFFIX=".sl"
-
-fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
-printf %s "checking for shl_load in -ldld... " >&6; }
-if test ${ac_cv_lib_dld_shl_load+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $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. */
-char shl_load ();
-int
-main (void)
-{
-return shl_load ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dld_shl_load=yes
-else $as_nop
- ac_cv_lib_dld_shl_load=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
-printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; }
-if test "x$ac_cv_lib_dld_shl_load" = xyes
-then :
- tcl_ok=yes
-else $as_nop
- tcl_ok=no
-fi
-
- if test "$tcl_ok" = yes
-then :
-
- SHLIB_CFLAGS="+z"
- SHLIB_LD="ld -b"
- LDFLAGS="$LDFLAGS -Wl,-E"
- CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."'
- LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."'
- LD_LIBRARY_PATH_VAR="SHLIB_PATH"
-
-fi
- if test "$GCC" = yes
-then :
-
- SHLIB_LD='${CC} -shared'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
-
-else $as_nop
-
- CFLAGS="$CFLAGS -z"
-
-fi
-
- # Check to enable 64-bit flags for compiler/linker
- if test "$do64bit" = "yes"
-then :
-
- if test "$GCC" = yes
-then :
-
- case `${CC} -dumpmachine` in
- hppa64*)
- # 64-bit gcc in use. Fix flags for GNU ld.
- do64bit_ok=yes
- SHLIB_LD='${CC} -shared'
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
-fi
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- ;;
- *)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5
-printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;}
- ;;
- esac
-
-else $as_nop
-
- do64bit_ok=yes
- CFLAGS="$CFLAGS +DD64"
- LDFLAGS_ARCH="+DD64"
-
-fi
-
-fi ;;
- HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*)
- SHLIB_SUFFIX=".sl"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
-printf %s "checking for shl_load in -ldld... " >&6; }
-if test ${ac_cv_lib_dld_shl_load+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $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. */
-char shl_load ();
-int
-main (void)
-{
-return shl_load ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dld_shl_load=yes
-else $as_nop
- ac_cv_lib_dld_shl_load=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
-printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; }
-if test "x$ac_cv_lib_dld_shl_load" = xyes
-then :
- tcl_ok=yes
-else $as_nop
- tcl_ok=no
-fi
-
- if test "$tcl_ok" = yes
-then :
-
- SHLIB_CFLAGS="+z"
- SHLIB_LD="ld -b"
- SHLIB_LD_LIBS=""
- LDFLAGS="$LDFLAGS -Wl,-E"
- CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."'
- LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."'
- LD_LIBRARY_PATH_VAR="SHLIB_PATH"
-
-fi ;;
- IRIX-5.*)
- SHLIB_CFLAGS=""
- SHLIB_LD="ld -shared -rdata_shared"
- SHLIB_SUFFIX=".so"
- case " $LIBOBJS " in
- *" mkstemp.$ac_objext "* ) ;;
- *) LIBOBJS="$LIBOBJS mkstemp.$ac_objext"
- ;;
-esac
-
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'
-fi
- ;;
- IRIX-6.*)
- SHLIB_CFLAGS=""
- SHLIB_LD="ld -n32 -shared -rdata_shared"
- SHLIB_SUFFIX=".so"
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'
-fi
- if test "$GCC" = yes
-then :
-
- CFLAGS="$CFLAGS -mabi=n32"
- LDFLAGS="$LDFLAGS -mabi=n32"
-
-else $as_nop
-
- case $system in
- IRIX-6.3)
- # Use to build 6.2 compatible binaries on 6.3.
- CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS"
- ;;
- *)
- CFLAGS="$CFLAGS -n32"
- ;;
- esac
- LDFLAGS="$LDFLAGS -n32"
-
-fi
- ;;
- IRIX64-6.*)
- SHLIB_CFLAGS=""
- SHLIB_LD="ld -n32 -shared -rdata_shared"
- SHLIB_SUFFIX=".so"
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'
-fi
-
- # Check to enable 64-bit flags for compiler/linker
-
- if test "$do64bit" = yes
-then :
-
- if test "$GCC" = yes
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported by gcc" >&5
-printf "%s\n" "$as_me: WARNING: 64bit mode not supported by gcc" >&2;}
-
-else $as_nop
-
- do64bit_ok=yes
- SHLIB_LD="ld -64 -shared -rdata_shared"
- CFLAGS="$CFLAGS -64"
- LDFLAGS_ARCH="-64"
-
-fi
-
-fi
- ;;
- Linux*|GNU*|NetBSD-Debian|DragonFly-*|FreeBSD-*)
- SHLIB_CFLAGS="-fPIC"
- SHLIB_SUFFIX=".so"
-
- # TEA specific:
- CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
-
- # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS
- SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared'
- LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
-
- case $system in
- DragonFly-*|FreeBSD-*)
- if test "${TCL_THREADS}" = "1"
-then :
-
- # The -pthread needs to go in the LDFLAGS, not LIBS
- LIBS=`echo $LIBS | sed s/-pthread//`
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- LDFLAGS="$LDFLAGS $PTHREAD_LIBS"
-fi
- ;;
- esac
-
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
-fi
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- if test "`uname -m`" = "alpha"
-then :
- CFLAGS="$CFLAGS -mieee"
-fi
- if test $do64bit = yes
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -m64 flag" >&5
-printf %s "checking if compiler accepts -m64 flag... " >&6; }
-if test ${tcl_cv_cc_m64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- hold_cflags=$CFLAGS
- CFLAGS="$CFLAGS -m64"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_cc_m64=yes
-else $as_nop
- tcl_cv_cc_m64=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- CFLAGS=$hold_cflags
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_m64" >&5
-printf "%s\n" "$tcl_cv_cc_m64" >&6; }
- if test $tcl_cv_cc_m64 = yes
-then :
-
- CFLAGS="$CFLAGS -m64"
- do64bit_ok=yes
-
-fi
-
-fi
-
- # The combo of gcc + glibc has a bug related to inlining of
- # functions like strtod(). The -fno-builtin flag should address
- # this problem but it does not work. The -fno-inline flag is kind
- # of overkill but it works. Disable inlining only when one of the
- # files in compat/*.c is being linked in.
-
- if test x"${USE_COMPAT}" != x
-then :
- CFLAGS="$CFLAGS -fno-inline"
-fi
- ;;
- Lynx*)
- SHLIB_CFLAGS="-fPIC"
- SHLIB_SUFFIX=".so"
- CFLAGS_OPTIMIZE=-02
- SHLIB_LD='${CC} -shared'
- LD_FLAGS="-Wl,--export-dynamic"
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
-fi
- ;;
- OpenBSD-*)
- arch=`arch -s`
- case "$arch" in
- alpha|sparc64)
- SHLIB_CFLAGS="-fPIC"
- ;;
- *)
- SHLIB_CFLAGS="-fpic"
- ;;
- esac
- SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
- SHLIB_SUFFIX=".so"
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
-fi
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
- LDFLAGS="$LDFLAGS -Wl,-export-dynamic"
- CFLAGS_OPTIMIZE="-O2"
- # On OpenBSD: Compile with -pthread
- # Don't link with -lpthread
- LIBS=`echo $LIBS | sed s/-lpthread//`
- CFLAGS="$CFLAGS -pthread"
- # OpenBSD doesn't do version numbers with dots.
- UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
- TCL_LIB_VERSIONS_OK=nodots
- ;;
- NetBSD-*)
- # NetBSD has ELF and can use 'cc -shared' to build shared libs
- SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
- SHLIB_SUFFIX=".so"
- LDFLAGS="$LDFLAGS -export-dynamic"
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
-fi
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- # The -pthread needs to go in the CFLAGS, not LIBS
- LIBS=`echo $LIBS | sed s/-pthread//`
- CFLAGS="$CFLAGS -pthread"
- LDFLAGS="$LDFLAGS -pthread"
- ;;
- Darwin-*)
- CFLAGS_OPTIMIZE="-Os"
- SHLIB_CFLAGS="-fno-common"
- # To avoid discrepancies between what headers configure sees during
- # preprocessing tests and compiling tests, move any -isysroot and
- # -mmacosx-version-min flags from CFLAGS to CPPFLAGS:
- CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \
- awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \
- if ($i~/^(isysroot|mmacosx-version-min)/) print "-"$i}'`"
- CFLAGS="`echo " ${CFLAGS}" | \
- awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \
- if (!($i~/^(isysroot|mmacosx-version-min)/)) print "-"$i}'`"
- if test $do64bit = yes
-then :
-
- case `arch` in
- ppc)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch ppc64 flag" >&5
-printf %s "checking if compiler accepts -arch ppc64 flag... " >&6; }
-if test ${tcl_cv_cc_arch_ppc64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- hold_cflags=$CFLAGS
- CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_cc_arch_ppc64=yes
-else $as_nop
- tcl_cv_cc_arch_ppc64=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- CFLAGS=$hold_cflags
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_ppc64" >&5
-printf "%s\n" "$tcl_cv_cc_arch_ppc64" >&6; }
- if test $tcl_cv_cc_arch_ppc64 = yes
-then :
-
- CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5"
- do64bit_ok=yes
-
-fi;;
- i386)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch x86_64 flag" >&5
-printf %s "checking if compiler accepts -arch x86_64 flag... " >&6; }
-if test ${tcl_cv_cc_arch_x86_64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- hold_cflags=$CFLAGS
- CFLAGS="$CFLAGS -arch x86_64"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_cc_arch_x86_64=yes
-else $as_nop
- tcl_cv_cc_arch_x86_64=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- CFLAGS=$hold_cflags
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_x86_64" >&5
-printf "%s\n" "$tcl_cv_cc_arch_x86_64" >&6; }
- if test $tcl_cv_cc_arch_x86_64 = yes
-then :
-
- CFLAGS="$CFLAGS -arch x86_64"
- do64bit_ok=yes
-
-fi;;
- *)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&5
-printf "%s\n" "$as_me: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&2;};;
- esac
-
-else $as_nop
-
- # Check for combined 32-bit and 64-bit fat build
- if echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \
- && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '
-then :
-
- fat_32_64=yes
-fi
-
-fi
- # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS
- SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}'
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ld accepts -single_module flag" >&5
-printf %s "checking if ld accepts -single_module flag... " >&6; }
-if test ${tcl_cv_ld_single_module+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- hold_ldflags=$LDFLAGS
- LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-int i;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_ld_single_module=yes
-else $as_nop
- tcl_cv_ld_single_module=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- LDFLAGS=$hold_ldflags
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_single_module" >&5
-printf "%s\n" "$tcl_cv_ld_single_module" >&6; }
- if test $tcl_cv_ld_single_module = yes
-then :
-
- SHLIB_LD="${SHLIB_LD} -Wl,-single_module"
-
-fi
- # TEA specific: link shlib with current and compatibility version flags
- vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([0-9]\{1,5\}\)\(\(\.[0-9]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d`
- SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}"
- SHLIB_SUFFIX=".dylib"
- LDFLAGS="$LDFLAGS -headerpad_max_install_names"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5
-printf %s "checking if ld accepts -search_paths_first flag... " >&6; }
-if test ${tcl_cv_ld_search_paths_first+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- hold_ldflags=$LDFLAGS
- LDFLAGS="$LDFLAGS -Wl,-search_paths_first"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-int i;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_ld_search_paths_first=yes
-else $as_nop
- tcl_cv_ld_search_paths_first=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- LDFLAGS=$hold_ldflags
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_search_paths_first" >&5
-printf "%s\n" "$tcl_cv_ld_search_paths_first" >&6; }
- if test $tcl_cv_ld_search_paths_first = yes
-then :
-
- LDFLAGS="$LDFLAGS -Wl,-search_paths_first"
-
-fi
- if test "$tcl_cv_cc_visibility_hidden" != yes
-then :
-
-
-printf "%s\n" "#define MODULE_SCOPE __private_extern__" >>confdefs.h
-
- tcl_cv_cc_visibility_hidden=yes
-
-fi
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH"
- # TEA specific: for combined 32 & 64 bit fat builds of Tk
- # extensions, verify that 64-bit build is possible.
- if test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"
-then :
-
- if test "${TEA_WINDOWINGSYSTEM}" = x11
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit X11" >&5
-printf %s "checking for 64-bit X11... " >&6; }
-if test ${tcl_cv_lib_x11_64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"'
- done
- CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include"
- LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <X11/Xlib.h>
-int
-main (void)
-{
-XrmInitialize();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_lib_x11_64=yes
-else $as_nop
- tcl_cv_lib_x11_64=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval $v'="$hold_'$v'"'
- done
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_x11_64" >&5
-printf "%s\n" "$tcl_cv_lib_x11_64" >&6; }
-
-fi
- if test "${TEA_WINDOWINGSYSTEM}" = aqua
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit Tk" >&5
-printf %s "checking for 64-bit Tk... " >&6; }
-if test ${tcl_cv_lib_tk_64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"'
- done
- CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}"
- LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <tk.h>
-int
-main (void)
-{
-Tk_InitStubs(NULL, "", 0);
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_lib_tk_64=yes
-else $as_nop
- tcl_cv_lib_tk_64=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval $v'="$hold_'$v'"'
- done
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_tk_64" >&5
-printf "%s\n" "$tcl_cv_lib_tk_64" >&6; }
-
-fi
- # remove 64-bit arch flags from CFLAGS et al. if configuration
- # does not support 64-bit.
- if test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Removing 64-bit architectures from compiler & linker flags" >&5
-printf "%s\n" "$as_me: Removing 64-bit architectures from compiler & linker flags" >&6;}
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"'
- done
-fi
-
-fi
- ;;
- OS/390-*)
- CFLAGS_OPTIMIZE="" # Optimizer is buggy
-
-printf "%s\n" "#define _OE_SOCKETS 1" >>confdefs.h
-
- ;;
- OSF1-V*)
- # Digital OSF/1
- SHLIB_CFLAGS=""
- if test "$SHARED_BUILD" = 1
-then :
-
- SHLIB_LD='ld -shared -expect_unresolved "*"'
-
-else $as_nop
-
- SHLIB_LD='ld -non_shared -expect_unresolved "*"'
-
-fi
- SHLIB_SUFFIX=".so"
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
-fi
- if test "$GCC" = yes
-then :
- CFLAGS="$CFLAGS -mieee"
-else $as_nop
-
- CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"
-fi
- # see pthread_intro(3) for pthread support on osf1, k.furukawa
- CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
- CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
- LIBS=`echo $LIBS | sed s/-lpthreads//`
- if test "$GCC" = yes
-then :
-
- LIBS="$LIBS -lpthread -lmach -lexc"
-
-else $as_nop
-
- CFLAGS="$CFLAGS -pthread"
- LDFLAGS="$LDFLAGS -pthread"
-
-fi
- ;;
- QNX-6*)
- # QNX RTP
- # This may work for all QNX, but it was only reported for v6.
- SHLIB_CFLAGS="-fPIC"
- SHLIB_LD="ld -Bshareable -x"
- SHLIB_LD_LIBS=""
- SHLIB_SUFFIX=".so"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- SCO_SV-3.2*)
- if test "$GCC" = yes
-then :
-
- SHLIB_CFLAGS="-fPIC -melf"
- LDFLAGS="$LDFLAGS -melf -Wl,-Bexport"
-
-else $as_nop
-
- SHLIB_CFLAGS="-Kpic -belf"
- LDFLAGS="$LDFLAGS -belf -Wl,-Bexport"
-
-fi
- SHLIB_LD="ld -G"
- SHLIB_LD_LIBS=""
- SHLIB_SUFFIX=".so"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- SunOS-5.[0-6])
- # Careful to not let 5.10+ fall into this case
-
- # Note: If _REENTRANT isn't defined, then Solaris
- # won't define thread-safe library routines.
-
-
-printf "%s\n" "#define _REENTRANT 1" >>confdefs.h
-
-
-printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
-
-
- SHLIB_CFLAGS="-KPIC"
- SHLIB_SUFFIX=".so"
- if test "$GCC" = yes
-then :
-
- SHLIB_LD='${CC} -shared'
- CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
-
-else $as_nop
-
- SHLIB_LD="/usr/ccs/bin/ld -G -z text"
- CC_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
-
-fi
- ;;
- SunOS-5*)
- # Note: If _REENTRANT isn't defined, then Solaris
- # won't define thread-safe library routines.
-
-
-printf "%s\n" "#define _REENTRANT 1" >>confdefs.h
-
-
-printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
-
-
- SHLIB_CFLAGS="-KPIC"
-
- # Check to enable 64-bit flags for compiler/linker
- if test "$do64bit" = yes
-then :
-
- arch=`isainfo`
- if test "$arch" = "sparcv9 sparc"
-then :
-
- if test "$GCC" = yes
-then :
-
- if test "`${CC} -dumpversion | awk -F. '{print $1}'`" -lt 3
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&5
-printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&2;}
-
-else $as_nop
-
- do64bit_ok=yes
- CFLAGS="$CFLAGS -m64 -mcpu=v9"
- LDFLAGS="$LDFLAGS -m64 -mcpu=v9"
- SHLIB_CFLAGS="-fPIC"
-
-fi
-
-else $as_nop
-
- do64bit_ok=yes
- if test "$do64bitVIS" = yes
-then :
-
- CFLAGS="$CFLAGS -xarch=v9a"
- LDFLAGS_ARCH="-xarch=v9a"
-
-else $as_nop
-
- CFLAGS="$CFLAGS -xarch=v9"
- LDFLAGS_ARCH="-xarch=v9"
-
-fi
- # Solaris 64 uses this as well
- #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64"
-
-fi
-
-else $as_nop
- if test "$arch" = "amd64 i386"
-then :
-
- if test "$GCC" = yes
-then :
-
- case $system in
- SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*)
- do64bit_ok=yes
- CFLAGS="$CFLAGS -m64"
- LDFLAGS="$LDFLAGS -m64";;
- *)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5
-printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;};;
- esac
-
-else $as_nop
-
- do64bit_ok=yes
- case $system in
- SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*)
- CFLAGS="$CFLAGS -m64"
- LDFLAGS="$LDFLAGS -m64";;
- *)
- CFLAGS="$CFLAGS -xarch=amd64"
- LDFLAGS="$LDFLAGS -xarch=amd64";;
- esac
-
-fi
-
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported for $arch" >&5
-printf "%s\n" "$as_me: WARNING: 64bit mode not supported for $arch" >&2;}
-fi
-fi
-
-fi
-
- SHLIB_SUFFIX=".so"
- if test "$GCC" = yes
-then :
-
- SHLIB_LD='${CC} -shared'
- CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- if test "$do64bit_ok" = yes
-then :
-
- if test "$arch" = "sparcv9 sparc"
-then :
-
- # We need to specify -static-libgcc or we need to
- # add the path to the sparv9 libgcc.
- # JH: static-libgcc is necessary for core Tcl, but may
- # not be necessary for extensions.
- SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc"
- # for finding sparcv9 libgcc, get the regular libgcc
- # path, remove so name and append 'sparcv9'
- #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..."
- #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir"
-
-else $as_nop
- if test "$arch" = "amd64 i386"
-then :
-
- # JH: static-libgcc is necessary for core Tcl, but may
- # not be necessary for extensions.
- SHLIB_LD="$SHLIB_LD -m64 -static-libgcc"
-
-fi
-fi
-
-fi
-
-else $as_nop
-
- case $system in
- SunOS-5.[1-9][0-9]*)
- # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS
- SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';;
- *)
- SHLIB_LD='/usr/ccs/bin/ld -G -z text';;
- esac
- CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
-
-fi
- ;;
- UNIX_SV* | UnixWare-5*)
- SHLIB_CFLAGS="-KPIC"
- SHLIB_LD='${CC} -G'
- SHLIB_LD_LIBS=""
- SHLIB_SUFFIX=".so"
- # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers
- # that don't grok the -Bexport option. Test that it does.
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld accepts -Bexport flag" >&5
-printf %s "checking for ld accepts -Bexport flag... " >&6; }
-if test ${tcl_cv_ld_Bexport+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- hold_ldflags=$LDFLAGS
- LDFLAGS="$LDFLAGS -Wl,-Bexport"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-int i;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_ld_Bexport=yes
-else $as_nop
- tcl_cv_ld_Bexport=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- LDFLAGS=$hold_ldflags
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_Bexport" >&5
-printf "%s\n" "$tcl_cv_ld_Bexport" >&6; }
- if test $tcl_cv_ld_Bexport = yes
-then :
-
- LDFLAGS="$LDFLAGS -Wl,-Bexport"
-
-fi
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- esac
-
- if test "$do64bit" = yes -a "$do64bit_ok" = no
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit support being disabled -- don't know magic for this platform" >&5
-printf "%s\n" "$as_me: WARNING: 64bit support being disabled -- don't know magic for this platform" >&2;}
-
-fi
-
-
-
- # Add in the arch flags late to ensure it wasn't removed.
- # Not necessary in TEA, but this is aligned with core
- LDFLAGS="$LDFLAGS $LDFLAGS_ARCH"
-
- # If we're running gcc, then change the C flags for compiling shared
- # libraries to the right flags for gcc, instead of those for the
- # standard manufacturer compiler.
-
- if test "$GCC" = yes
-then :
-
- case $system in
- AIX-*) ;;
- BSD/OS*) ;;
- CYGWIN_*|MINGW32_*|MINGW64_*|MSYS_*) ;;
- IRIX*) ;;
- NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;;
- Darwin-*) ;;
- SCO_SV-3.2*) ;;
- windows) ;;
- *) SHLIB_CFLAGS="-fPIC" ;;
- esac
-fi
-
- if test "$tcl_cv_cc_visibility_hidden" != yes
-then :
-
-
-printf "%s\n" "#define MODULE_SCOPE extern" >>confdefs.h
-
-
-fi
-
- if test "$SHARED_LIB_SUFFIX" = ""
-then :
-
- # TEA specific: use PACKAGE_VERSION instead of VERSION
- SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}'
-fi
- if test "$UNSHARED_LIB_SUFFIX" = ""
-then :
-
- # TEA specific: use PACKAGE_VERSION instead of VERSION
- UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a'
-fi
-
- if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SEH support in compiler" >&5
-printf %s "checking for SEH support in compiler... " >&6; }
-if test ${tcl_cv_seh+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test "$cross_compiling" = yes
-then :
- tcl_cv_seh=no
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-
- int main(int argc, char** argv) {
- int a, b = 0;
- __try {
- a = 666 / b;
- }
- __except (EXCEPTION_EXECUTE_HANDLER) {
- return 0;
- }
- return 1;
- }
-
-_ACEOF
-if ac_fn_c_try_run "$LINENO"
-then :
- tcl_cv_seh=yes
-else $as_nop
- tcl_cv_seh=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_seh" >&5
-printf "%s\n" "$tcl_cv_seh" >&6; }
- if test "$tcl_cv_seh" = "no" ; then
-
-printf "%s\n" "#define HAVE_NO_SEH 1" >>confdefs.h
-
- fi
-
- #
- # Check to see if the excpt.h include file provided contains the
- # definition for EXCEPTION_DISPOSITION; if not, which is the case
- # with Cygwin's version as of 2002-04-10, define it to be int,
- # sufficient for getting the current code to work.
- #
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for EXCEPTION_DISPOSITION support in include files" >&5
-printf %s "checking for EXCEPTION_DISPOSITION support in include files... " >&6; }
-if test ${tcl_cv_eh_disposition+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-# undef WIN32_LEAN_AND_MEAN
-
-int
-main (void)
-{
-
- EXCEPTION_DISPOSITION x;
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_eh_disposition=yes
-else $as_nop
- tcl_cv_eh_disposition=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_eh_disposition" >&5
-printf "%s\n" "$tcl_cv_eh_disposition" >&6; }
- if test "$tcl_cv_eh_disposition" = "no" ; then
-
-printf "%s\n" "#define EXCEPTION_DISPOSITION int" >>confdefs.h
-
- fi
-
- # Check to see if winnt.h defines CHAR, SHORT, and LONG
- # even if VOID has already been #defined. The win32api
- # used by mingw and cygwin is known to do this.
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for winnt.h that ignores VOID define" >&5
-printf %s "checking for winnt.h that ignores VOID define... " >&6; }
-if test ${tcl_cv_winnt_ignore_void+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-#define VOID void
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-
-int
-main (void)
-{
-
- CHAR c;
- SHORT s;
- LONG l;
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_winnt_ignore_void=yes
-else $as_nop
- tcl_cv_winnt_ignore_void=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_winnt_ignore_void" >&5
-printf "%s\n" "$tcl_cv_winnt_ignore_void" >&6; }
- if test "$tcl_cv_winnt_ignore_void" = "yes" ; then
-
-printf "%s\n" "#define HAVE_WINNT_IGNORE_VOID 1" >>confdefs.h
-
- fi
- fi
-
- # See if the compiler supports casting to a union type.
- # This is used to stop gcc from printing a compiler
- # warning when initializing a union member.
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cast to union support" >&5
-printf %s "checking for cast to union support... " >&6; }
-if test ${tcl_cv_cast_to_union+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- union foo { int i; double d; };
- union foo f = (union foo) (int) 0;
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_cast_to_union=yes
-else $as_nop
- tcl_cv_cast_to_union=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cast_to_union" >&5
-printf "%s\n" "$tcl_cv_cast_to_union" >&6; }
- if test "$tcl_cv_cast_to_union" = "yes"; then
-
-printf "%s\n" "#define HAVE_CAST_TO_UNION 1" >>confdefs.h
-
- fi
-
- ac_fn_c_check_header_compile "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdbool_h" = xyes
-then :
-
-printf "%s\n" "#define HAVE_STDBOOL_H 1" >>confdefs.h
-
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- # These must be called after we do the basic CFLAGS checks and
- # verify any possible 64-bit or similar switches are necessary
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for required early compiler flags" >&5
-printf %s "checking for required early compiler flags... " >&6; }
- tcl_flags=""
-
- if test ${tcl_cv_flag__isoc99_source+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-int
-main (void)
-{
-char *p = (char *)strtoll; char *q = (char *)strtoull;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_flag__isoc99_source=no
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#define _ISOC99_SOURCE 1
-#include <stdlib.h>
-int
-main (void)
-{
-char *p = (char *)strtoll; char *q = (char *)strtoull;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_flag__isoc99_source=yes
-else $as_nop
- tcl_cv_flag__isoc99_source=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
- if test "x${tcl_cv_flag__isoc99_source}" = "xyes" ; then
-
-printf "%s\n" "#define _ISOC99_SOURCE 1" >>confdefs.h
-
- tcl_flags="$tcl_flags _ISOC99_SOURCE"
- fi
-
-
- if test ${tcl_cv_flag__largefile64_source+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/stat.h>
-int
-main (void)
-{
-struct stat64 buf; int i = stat64("/", &buf);
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_flag__largefile64_source=no
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#define _LARGEFILE64_SOURCE 1
-#include <sys/stat.h>
-int
-main (void)
-{
-struct stat64 buf; int i = stat64("/", &buf);
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_flag__largefile64_source=yes
-else $as_nop
- tcl_cv_flag__largefile64_source=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
- if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then
-
-printf "%s\n" "#define _LARGEFILE64_SOURCE 1" >>confdefs.h
-
- tcl_flags="$tcl_flags _LARGEFILE64_SOURCE"
- fi
-
-
- if test ${tcl_cv_flag__largefile_source64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/stat.h>
-int
-main (void)
-{
-char *p = (char *)open64;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_flag__largefile_source64=no
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#define _LARGEFILE_SOURCE64 1
-#include <sys/stat.h>
-int
-main (void)
-{
-char *p = (char *)open64;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_flag__largefile_source64=yes
-else $as_nop
- tcl_cv_flag__largefile_source64=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
- if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then
-
-printf "%s\n" "#define _LARGEFILE_SOURCE64 1" >>confdefs.h
-
- tcl_flags="$tcl_flags _LARGEFILE_SOURCE64"
- fi
-
- if test "x${tcl_flags}" = "x" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5
-printf "%s\n" "none" >&6; }
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${tcl_flags}" >&5
-printf "%s\n" "${tcl_flags}" >&6; }
- fi
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit integer type" >&5
-printf %s "checking for 64-bit integer type... " >&6; }
- if test ${tcl_cv_type_64bit+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- tcl_cv_type_64bit=none
- # See if the compiler knows natively about __int64
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-__int64 value = (__int64) 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_type_64bit=__int64
-else $as_nop
- tcl_type_64bit="long long"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- # See if we could use long anyway Note that we substitute in the
- # type that is our current guess for a 64-bit type inside this check
- # program, so it should be modified only carefully...
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-switch (0) {
- case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ;
- }
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_type_64bit=${tcl_type_64bit}
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
- if test "${tcl_cv_type_64bit}" = none ; then
-
-printf "%s\n" "#define TCL_WIDE_INT_IS_LONG 1" >>confdefs.h
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- elif test "${tcl_cv_type_64bit}" = "__int64" \
- -a "${TEA_PLATFORM}" = "windows" ; then
- # TEA specific: We actually want to use the default tcl.h checks in
- # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER*
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using Tcl header defaults" >&5
-printf "%s\n" "using Tcl header defaults" >&6; }
- else
-
-printf "%s\n" "#define TCL_WIDE_INT_TYPE ${tcl_cv_type_64bit}" >>confdefs.h
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${tcl_cv_type_64bit}" >&5
-printf "%s\n" "${tcl_cv_type_64bit}" >&6; }
-
- # Now check for auxiliary declarations
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct dirent64" >&5
-printf %s "checking for struct dirent64... " >&6; }
-if test ${tcl_cv_struct_dirent64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
-#include <dirent.h>
-int
-main (void)
-{
-struct dirent64 p;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_struct_dirent64=yes
-else $as_nop
- tcl_cv_struct_dirent64=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_dirent64" >&5
-printf "%s\n" "$tcl_cv_struct_dirent64" >&6; }
- if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then
-
-printf "%s\n" "#define HAVE_STRUCT_DIRENT64 1" >>confdefs.h
-
- fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for DIR64" >&5
-printf %s "checking for DIR64... " >&6; }
-if test ${tcl_cv_DIR64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
-#include <dirent.h>
-int
-main (void)
-{
-struct dirent64 *p; DIR64 d = opendir64(".");
- p = readdir64(d); rewinddir64(d); closedir64(d);
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_DIR64=yes
-else $as_nop
- tcl_cv_DIR64=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_DIR64" >&5
-printf "%s\n" "$tcl_cv_DIR64" >&6; }
- if test "x${tcl_cv_DIR64}" = "xyes" ; then
-
-printf "%s\n" "#define HAVE_DIR64 1" >>confdefs.h
-
- fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5
-printf %s "checking for struct stat64... " >&6; }
-if test ${tcl_cv_struct_stat64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/stat.h>
-int
-main (void)
-{
-struct stat64 p;
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_struct_stat64=yes
-else $as_nop
- tcl_cv_struct_stat64=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_stat64" >&5
-printf "%s\n" "$tcl_cv_struct_stat64" >&6; }
- if test "x${tcl_cv_struct_stat64}" = "xyes" ; then
-
-printf "%s\n" "#define HAVE_STRUCT_STAT64 1" >>confdefs.h
-
- fi
-
- ac_fn_c_check_func "$LINENO" "open64" "ac_cv_func_open64"
-if test "x$ac_cv_func_open64" = xyes
-then :
- printf "%s\n" "#define HAVE_OPEN64 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "lseek64" "ac_cv_func_lseek64"
-if test "x$ac_cv_func_lseek64" = xyes
-then :
- printf "%s\n" "#define HAVE_LSEEK64 1" >>confdefs.h
-
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for off64_t" >&5
-printf %s "checking for off64_t... " >&6; }
- if test ${tcl_cv_type_off64_t+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
-int
-main (void)
-{
-off64_t offset;
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_type_off64_t=yes
-else $as_nop
- tcl_cv_type_off64_t=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
- if test "x${tcl_cv_type_off64_t}" = "xyes" && \
- test "x${ac_cv_func_lseek64}" = "xyes" && \
- test "x${ac_cv_func_open64}" = "xyes" ; then
-
-printf "%s\n" "#define HAVE_TYPE_OFF64_T 1" >>confdefs.h
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- fi
- fi
-
-
-
-#--------------------------------------------------------------------
-# Set the default compiler switches based on the --enable-symbols option.
-#--------------------------------------------------------------------
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build with symbols" >&5
-printf %s "checking for build with symbols... " >&6; }
- # Check whether --enable-symbols was given.
-if test ${enable_symbols+y}
-then :
- enableval=$enable_symbols; tcl_ok=$enableval
-else $as_nop
- tcl_ok=no
-fi
-
- if test "$tcl_ok" = "no"; then
- CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG"
- LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-
-printf "%s\n" "#define TCL_CFG_OPTIMIZED 1" >>confdefs.h
-
- else
- CFLAGS_DEFAULT="${CFLAGS_DEBUG}"
- LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}"
- if test "$tcl_ok" = "yes"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (standard debugging)" >&5
-printf "%s\n" "yes (standard debugging)" >&6; }
- fi
- fi
-
-
-
- if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then
-
-printf "%s\n" "#define TCL_MEM_DEBUG 1" >>confdefs.h
-
- fi
-
- if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then
- if test "$tcl_ok" = "all"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled symbols mem debugging" >&5
-printf "%s\n" "enabled symbols mem debugging" >&6; }
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5
-printf "%s\n" "enabled $tcl_ok debugging" >&6; }
- fi
- fi
-
-
-#--------------------------------------------------------------------
-# This macro generates a line to use when building a library. It
-# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
-# and TEA_LOAD_TCLCONFIG macros above.
-#--------------------------------------------------------------------
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-printf %s "checking for grep that handles long lines and -e... " >&6; }
-if test ${ac_cv_path_GREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -z "$GREP"; then
- ac_path_GREP_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$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in grep ggrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_GREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
- # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'GREP' >> "conftest.nl"
- "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_GREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_GREP="$ac_path_GREP"
- ac_path_GREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_GREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_GREP"; then
- as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-printf "%s\n" "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-printf %s "checking for egrep... " >&6; }
-if test ${ac_cv_path_EGREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
- then ac_cv_path_EGREP="$GREP -E"
- else
- if test -z "$EGREP"; then
- ac_path_EGREP_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$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in egrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
- # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'EGREP' >> "conftest.nl"
- "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_EGREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_EGREP="$ac_path_EGREP"
- ac_path_EGREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_EGREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_EGREP"; then
- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_EGREP=$EGREP
-fi
-
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-printf "%s\n" "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
-
-
-
- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then
- MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(PKG_OBJECTS)"
- MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-#if defined(_MSC_VER) && _MSC_VER >= 1400
-print("manifest needed")
-#endif
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "manifest needed" >/dev/null 2>&1
-then :
-
- # Could do a CHECK_PROG for mt, but should always be with MSVC8+
- VC_MANIFEST_EMBED_DLL="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;2 ; fi"
- VC_MANIFEST_EMBED_EXE="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;1 ; fi"
- MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}"
-
- CLEANFILES="$CLEANFILES *.manifest"
-
-
-fi
-rm -rf conftest*
-
- MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\$@ \$(PKG_STUB_OBJECTS)"
- else
- MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(PKG_OBJECTS)"
- MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
- MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(PKG_STUB_OBJECTS)"
- fi
-
- if test "${SHARED_BUILD}" = "1" ; then
- MAKE_LIB="${MAKE_SHARED_LIB} "
- else
- MAKE_LIB="${MAKE_STATIC_LIB} "
- fi
-
- #--------------------------------------------------------------------
- # Shared libraries and static libraries have different names.
- # Use the double eval to make sure any variables in the suffix is
- # substituted. (@@@ Might not be necessary anymore)
- #--------------------------------------------------------------------
-
- PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}"
- PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9"
- if test "${TCL_MAJOR_VERSION}" -gt 8 ; then
- PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}"
- else
- PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}"
- fi
- if test "${TEA_PLATFORM}" = "windows" ; then
- if test "${SHARED_BUILD}" = "1" ; then
- # We force the unresolved linking of symbols that are really in
- # the private libraries of Tcl and Tk.
- if test x"${TK_BIN_DIR}" != x ; then
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\""
- fi
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\""
- if test "$GCC" = "yes"; then
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc"
- fi
- eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- else
- if test "$GCC" = "yes"; then
- PACKAGE_LIB_PREFIX=lib${PACKAGE_LIB_PREFIX}
- fi
- eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- fi
- # Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
- if test "$GCC" = "yes"; then
- PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE}
- fi
- # These aren't needed on Windows (either MSVC or gcc)
- RANLIB=:
- RANLIB_STUB=:
- else
- RANLIB_STUB="${RANLIB}"
- if test "${SHARED_BUILD}" = "1" ; then
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}"
- if test x"${TK_BIN_DIR}" != x ; then
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}"
- fi
- eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- RANLIB=:
- else
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- fi
- # Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
- fi
-
- # These are escaped so that only CFLAGS is picked up at configure time.
- # The other values will be substituted at make time.
- CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}"
- if test "${SHARED_BUILD}" = "1" ; then
- CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}"
- fi
-
-
-
-
-
-
-
-
-
-
-#--------------------------------------------------------------------
-# Determine the name of the tclsh and/or wish executables in the
-# Tcl and Tk build directories or the location they were installed
-# into. These paths are used to support running test cases only,
-# the Makefile should not be making use of these paths to generate
-# a pkgIndex.tcl file or anything else at extension build time.
-#--------------------------------------------------------------------
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5
-printf %s "checking for tclsh... " >&6; }
- if test -f "${TCL_BIN_DIR}/Makefile" ; then
- # tclConfig.sh is in Tcl build directory
- if test "${TEA_PLATFORM}" = "windows"; then
- if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
- elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}"
- elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}"
- elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}"
- fi
- else
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh"
- fi
- else
- # tclConfig.sh is in install location
- if test "${TEA_PLATFORM}" = "windows"; then
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
- else
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}"
- fi
- list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \
- `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \
- `ls -d ${TCL_PREFIX}/bin 2>/dev/null`"
- for i in $list ; do
- if test -f "$i/${TCLSH_PROG}" ; then
- REAL_TCL_BIN_DIR="`cd "$i"; pwd`/"
- break
- fi
- done
- TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}"
- fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${TCLSH_PROG}" >&5
-printf "%s\n" "${TCLSH_PROG}" >&6; }
-
-
-#TEA_PROG_WISH
-
-#--------------------------------------------------------------------
-# Setup a *Config.sh.in configuration file.
-#--------------------------------------------------------------------
-
-#TEA_EXPORT_CONFIG([sample])
-#AC_SUBST(SAMPLE_VAR)
-
-#--------------------------------------------------------------------
-# Specify files to substitute AC variables in. You may alternatively
-# have a special pkgIndex.tcl.in or other files which require
-# substituting the AC variables in. Include these here.
-#--------------------------------------------------------------------
-
-ac_config_files="$ac_config_files Makefile pkgIndex.tcl"
-
-#AC_CONFIG_FILES([sampleConfig.sh])
-
-#--------------------------------------------------------------------
-# Finally, substitute all of the various values into the files
-# specified with AC_CONFIG_FILES.
-#--------------------------------------------------------------------
-
-cat >confcache <<\_ACEOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs, see configure's option --config-cache.
-# It is not useful on other systems. If it contains results you don't
-# want to keep, you may remove or edit it.
-#
-# config.status only pays attention to the cache file if you give it
-# the --recheck option to rerun configure.
-#
-# `ac_cv_env_foo' variables (set or unset) will be overridden when
-# loading this file, other *unset* `ac_cv_foo' will be assigned the
-# following values.
-
-_ACEOF
-
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, we kill variables containing newlines.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(
- for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
- eval ac_val=\$$ac_var
- case $ac_val in #(
- *${as_nl}*)
- case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
- esac
- case $ac_var in #(
- _ | IFS | as_nl) ;; #(
- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
- *) { eval $ac_var=; unset $ac_var;} ;;
- esac ;;
- esac
- done
-
- (set) 2>&1 |
- case $as_nl`(ac_space=' '; set) 2>&1` in #(
- *${as_nl}ac_space=\ *)
- # `set' does not quote correctly, so add quotes: double-quote
- # substitution turns \\\\ into \\, and sed turns \\ into \.
- sed -n \
- "s/'/'\\\\''/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
- ;; #(
- *)
- # `set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
- ;;
- esac |
- sort
-) |
- sed '
- /^ac_cv_env_/b end
- t clear
- :clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/
- t end
- s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
- :end' >>confcache
-if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
- if test -w "$cache_file"; then
- if test "x$cache_file" != "x/dev/null"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-printf "%s\n" "$as_me: updating cache $cache_file" >&6;}
- if test ! -f "$cache_file" || test -h "$cache_file"; then
- cat confcache >"$cache_file"
- else
- case $cache_file in #(
- */* | ?:*)
- mv -f confcache "$cache_file"$$ &&
- mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
- mv -f confcache "$cache_file" ;;
- esac
- fi
- fi
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;}
- fi
-fi
-rm -f confcache
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-# Transform confdefs.h into DEFS.
-# Protect against shell expansion while executing Makefile rules.
-# Protect against Makefile macro expansion.
-#
-# If the first sed substitution is executed (which looks for macros that
-# take arguments), then branch to the quote section. Otherwise,
-# look for a macro that doesn't take arguments.
-ac_script='
-:mline
-/\\$/{
- N
- s,\\\n,,
- b mline
-}
-t clear
-:clear
-s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
-t quote
-s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
-t quote
-b any
-:quote
-s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
-s/\[/\\&/g
-s/\]/\\&/g
-s/\$/$$/g
-H
-:any
-${
- g
- s/^\n//
- s/\n/ /g
- p
-}
-'
-DEFS=`sed -n "$ac_script" confdefs.h`
-
-
-ac_libobjs=
-ac_ltlibobjs=
-U=
-for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
- # 1. Remove the extension, and $U if already installed.
- ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
- ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"`
- # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
- # will be set to the directory where LIBOBJS objects are built.
- as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
- as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
-done
-LIBOBJS=$ac_libobjs
-
-LTLIBOBJS=$ac_ltlibobjs
-
-
-
-CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""
-
-: "${CONFIG_STATUS=./config.status}"
-ac_write_fail=0
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;}
-as_write_fail=0
-cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-# Run this file to recreate the current configuration.
-# Compiler output produced by configure, useful for debugging
-# configure, is in config.log if it exists.
-
-debug=false
-ac_cs_recheck=false
-ac_cs_silent=false
-
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-as_nop=:
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else $as_nop
- case `(set -o) 2>/dev/null` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac
-fi
-
-
-
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
-as_nl='
-'
-export as_nl
-IFS=" "" $as_nl"
-
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
-if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
-
-# The user is always right.
-if ${PATH_SEPARATOR+false} :; 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
-
-
-# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
- as_myself=$0
-fi
-if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
- exit 1
-fi
-
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
- fi
- printf "%s\n" "$as_me: error: $2" >&2
- as_fn_exit $as_status
-} # as_fn_error
-
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
- return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
- set +e
- as_fn_set_status $1
- exit $1
-} # as_fn_exit
-
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
- { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
-then :
- eval 'as_fn_append ()
- {
- eval $1+=\$2
- }'
-else $as_nop
- as_fn_append ()
- {
- eval $1=\$$1\$2
- }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
-then :
- eval 'as_fn_arith ()
- {
- as_val=$(( $* ))
- }'
-else $as_nop
- as_fn_arith ()
- {
- as_val=`expr "$@" || test $? -eq 1`
- }
-fi # as_fn_arith
-
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
- test "X`expr 00001 : '.*\(...\)'`" = X001; then
- as_expr=expr
-else
- as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
- as_basename=basename
-else
- as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
- as_dirname=dirname
-else
- as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
- X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{
- s//\1/
- q
- }
- /^X\/\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\/\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
- case `echo 'xy\c'` in
- *c*) ECHO_T=' ';; # ECHO_T is single tab character.
- xy) ECHO_C='\c';;
- *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
- ECHO_T=' ';;
- esac;;
-*)
- ECHO_N='-n';;
-esac
-
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
- rm -f conf$$.dir/conf$$.file
-else
- rm -f conf$$.dir
- mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
- if ln -s conf$$.file conf$$ 2>/dev/null; then
- as_ln_s='ln -s'
- # ... but there are two gotchas:
- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
- elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
- else
- as_ln_s='cp -pR'
- fi
-else
- as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
- case $as_dir in #(
- -*) as_dir=./$as_dir;;
- esac
- test -d "$as_dir" || eval $as_mkdir_p || {
- as_dirs=
- while :; do
- case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
- *) as_qdir=$as_dir;;
- esac
- as_dirs="'$as_qdir' $as_dirs"
- as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_dir" : 'X\(//\)[^/]' \| \
- X"$as_dir" : 'X\(//\)$' \| \
- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- test -d "$as_dir" && break
- done
- test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-if mkdir -p . 2>/dev/null; then
- as_mkdir_p='mkdir -p "$as_dir"'
-else
- test -d ./-p && rmdir ./-p
- as_mkdir_p=false
-fi
-
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-exec 6>&1
-## ----------------------------------- ##
-## Main body of $CONFIG_STATUS script. ##
-## ----------------------------------- ##
-_ASEOF
-test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# Save the log message, to keep $0 and so on meaningful, and to
-# report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling.
-ac_log="
-This file was extended by sqlite $as_me 3.46.1, which was
-generated by GNU Autoconf 2.71. Invocation command line was
-
- CONFIG_FILES = $CONFIG_FILES
- CONFIG_HEADERS = $CONFIG_HEADERS
- CONFIG_LINKS = $CONFIG_LINKS
- CONFIG_COMMANDS = $CONFIG_COMMANDS
- $ $0 $@
-
-on `(hostname || uname -n) 2>/dev/null | sed 1q`
-"
-
-_ACEOF
-
-case $ac_config_files in *"
-"*) set x $ac_config_files; shift; ac_config_files=$*;;
-esac
-
-
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-# Files that config.status was made for.
-config_files="$ac_config_files"
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-ac_cs_usage="\
-\`$as_me' instantiates files and other configuration actions
-from templates according to the current configuration. Unless the files
-and actions are specified as TAGs, all are instantiated by default.
-
-Usage: $0 [OPTION]... [TAG]...
-
- -h, --help print this help, then exit
- -V, --version print version number and configuration settings, then exit
- --config print configuration, then exit
- -q, --quiet, --silent
- do not print progress messages
- -d, --debug don't remove temporary files
- --recheck update $as_me by reconfiguring in the same conditions
- --file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
-
-Configuration files:
-$config_files
-
-Report bugs to the package provider."
-
-_ACEOF
-ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
-ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"`
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config='$ac_cs_config_escaped'
-ac_cs_version="\\
-sqlite config.status 3.46.1
-configured by $0, generated by GNU Autoconf 2.71,
- with options \\"\$ac_cs_config\\"
-
-Copyright (C) 2021 Free Software Foundation, Inc.
-This config.status script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it."
-
-ac_pwd='$ac_pwd'
-srcdir='$srcdir'
-test -n "\$AWK" || AWK=awk
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# The default lists apply if the user does not specify any file.
-ac_need_defaults=:
-while test $# != 0
-do
- case $1 in
- --*=?*)
- ac_option=`expr "X$1" : 'X\([^=]*\)='`
- ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
- ac_shift=:
- ;;
- --*=)
- ac_option=`expr "X$1" : 'X\([^=]*\)='`
- ac_optarg=
- ac_shift=:
- ;;
- *)
- ac_option=$1
- ac_optarg=$2
- ac_shift=shift
- ;;
- esac
-
- case $ac_option in
- # Handling of the options.
- -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
- ac_cs_recheck=: ;;
- --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
- printf "%s\n" "$ac_cs_version"; exit ;;
- --config | --confi | --conf | --con | --co | --c )
- printf "%s\n" "$ac_cs_config"; exit ;;
- --debug | --debu | --deb | --de | --d | -d )
- debug=: ;;
- --file | --fil | --fi | --f )
- $ac_shift
- case $ac_optarg in
- *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
- '') as_fn_error $? "missing file argument" ;;
- esac
- as_fn_append CONFIG_FILES " '$ac_optarg'"
- ac_need_defaults=false;;
- --he | --h | --help | --hel | -h )
- printf "%s\n" "$ac_cs_usage"; exit ;;
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil | --si | --s)
- ac_cs_silent=: ;;
-
- # This is an error.
- -*) as_fn_error $? "unrecognized option: \`$1'
-Try \`$0 --help' for more information." ;;
-
- *) as_fn_append ac_config_targets " $1"
- ac_need_defaults=false ;;
-
- esac
- shift
-done
-
-ac_configure_extra_args=
-
-if $ac_cs_silent; then
- exec 6>/dev/null
- ac_configure_extra_args="$ac_configure_extra_args --silent"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-if \$ac_cs_recheck; then
- set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
- shift
- \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6
- CONFIG_SHELL='$SHELL'
- export CONFIG_SHELL
- exec "\$@"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-exec 5>>config.log
-{
- echo
- sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
- printf "%s\n" "$ac_log"
-} >&5
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-
-# Handling of arguments.
-for ac_config_target in $ac_config_targets
-do
- case $ac_config_target in
- "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
- "pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES pkgIndex.tcl" ;;
-
- *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
- esac
-done
-
-
-# If the user did not use the arguments to specify the items to instantiate,
-# then the envvar interface is used. Set only those that are not.
-# We use the long form for the default assignment because of an extremely
-# bizarre bug on SunOS 4.1.3.
-if $ac_need_defaults; then
- test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files
-fi
-
-# Have a temporary directory for convenience. Make it in the build tree
-# simply because there is no reason against having it here, and in addition,
-# creating and moving files from /tmp can sometimes cause problems.
-# Hook for its removal unless debugging.
-# Note that there is a small window in which the directory will not be cleaned:
-# after its creation but before its name has been assigned to `$tmp'.
-$debug ||
-{
- tmp= ac_tmp=
- trap 'exit_status=$?
- : "${ac_tmp:=$tmp}"
- { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
-' 0
- trap 'as_fn_exit 1' 1 2 13 15
-}
-# Create a (secure) tmp directory for tmp files.
-
-{
- tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
- test -d "$tmp"
-} ||
-{
- tmp=./conf$$-$RANDOM
- (umask 077 && mkdir "$tmp")
-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
-
-# Set up the scripts for CONFIG_FILES section.
-# No need to generate them if there are no CONFIG_FILES.
-# This happens for instance with `./config.status config.h'.
-if test -n "$CONFIG_FILES"; then
-
-
-ac_cr=`echo X | tr X '\015'`
-# On cygwin, bash can eat \r inside `` if the user requested igncr.
-# But we know of no other shell where ac_cr would be empty at this
-# point, so we can use a bashism as a fallback.
-if test "x$ac_cr" = x; then
- eval ac_cr=\$\'\\r\'
-fi
-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
- ac_cs_awk_cr='\\r'
-else
- ac_cs_awk_cr=$ac_cr
-fi
-
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
-_ACEOF
-
-
-{
- echo "cat >conf$$subs.awk <<_ACEOF" &&
- echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
- echo "_ACEOF"
-} >conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
-ac_delim='%!_!# '
-for ac_last_try in false false false false false :; do
- . ./conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-
- ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
- if test $ac_delim_n = $ac_delim_num; then
- break
- elif $ac_last_try; then
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
- else
- ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
- fi
-done
-rm -f conf$$subs.sh
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
-_ACEOF
-sed -n '
-h
-s/^/S["/; s/!.*/"]=/
-p
-g
-s/^[^!]*!//
-:repl
-t repl
-s/'"$ac_delim"'$//
-t delim
-:nl
-h
-s/\(.\{148\}\)..*/\1/
-t more1
-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
-p
-n
-b repl
-:more1
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t nl
-:delim
-h
-s/\(.\{148\}\)..*/\1/
-t more2
-s/["\\]/\\&/g; s/^/"/; s/$/"/
-p
-b
-:more2
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t delim
-' <conf$$subs.awk | sed '
-/^[^""]/{
- N
- s/\n//
-}
-' >>$CONFIG_STATUS || ac_write_fail=1
-rm -f conf$$subs.awk
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
- for (key in S) S_is_set[key] = 1
- FS = ""
-
-}
-{
- line = $ 0
- nfields = split(line, field, "@")
- substed = 0
- len = length(field[1])
- for (i = 2; i < nfields; i++) {
- key = field[i]
- keylen = length(key)
- if (S_is_set[key]) {
- value = S[key]
- line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
- len += length(value) + length(field[++i])
- substed = 1
- } else
- len += 1 + keylen
- }
-
- print line
-}
-
-_ACAWK
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
- sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
-else
- cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
- || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
-_ACEOF
-
-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
-# trailing colons and then remove the whole line if VPATH becomes empty
-# (actually we leave an empty line to preserve line numbers).
-if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
-h
-s///
-s/^/:/
-s/[ ]*$/:/
-s/:\$(srcdir):/:/g
-s/:\${srcdir}:/:/g
-s/:@srcdir@:/:/g
-s/^:*//
-s/:*$//
-x
-s/\(=[ ]*\).*/\1/
-G
-s/\n//
-s/^[^=]*=[ ]*$//
-}'
-fi
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-fi # test -n "$CONFIG_FILES"
-
-
-eval set X " :F $CONFIG_FILES "
-shift
-for ac_tag
-do
- case $ac_tag in
- :[FHLC]) ac_mode=$ac_tag; continue;;
- esac
- case $ac_mode$ac_tag in
- :[FHL]*:*);;
- :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
- :[FH]-) ac_tag=-:-;;
- :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
- esac
- ac_save_IFS=$IFS
- IFS=:
- set x $ac_tag
- IFS=$ac_save_IFS
- shift
- ac_file=$1
- shift
-
- case $ac_mode in
- :L) ac_source=$1;;
- :[FH])
- ac_file_inputs=
- for ac_f
- do
- case $ac_f in
- -) ac_f="$ac_tmp/stdin";;
- *) # Look for the file first in the build tree, then in the source tree
- # (if the path is not absolute). The absolute path cannot be DOS-style,
- # because $ac_f cannot contain `:'.
- test -f "$ac_f" ||
- case $ac_f in
- [\\/$]*) false;;
- *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
- esac ||
- as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
- esac
- case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
- as_fn_append ac_file_inputs " '$ac_f'"
- done
-
- # Let's still pretend it is `configure' which instantiates (i.e., don't
- # use $as_me), people would be surprised to read:
- # /* config.h. Generated by config.status. */
- configure_input='Generated from '`
- printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
- `' by configure.'
- if test x"$ac_file" != x-; then
- configure_input="$ac_file. $configure_input"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-printf "%s\n" "$as_me: creating $ac_file" >&6;}
- fi
- # Neutralize special characters interpreted by sed in replacement strings.
- case $configure_input in #(
- *\&* | *\|* | *\\* )
- ac_sed_conf_input=`printf "%s\n" "$configure_input" |
- sed 's/[\\\\&|]/\\\\&/g'`;; #(
- *) ac_sed_conf_input=$configure_input;;
- esac
-
- case $ac_tag in
- *:-:* | *:-) cat >"$ac_tmp/stdin" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
- esac
- ;;
- esac
-
- ac_dir=`$as_dirname -- "$ac_file" ||
-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$ac_file" : 'X\(//\)[^/]' \| \
- X"$ac_file" : 'X\(//\)$' \| \
- X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$ac_file" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- as_dir="$ac_dir"; as_fn_mkdir_p
- ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
- # A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
- case $ac_top_builddir_sub in
- "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
- esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
- .) # We are building in place.
- ac_srcdir=.
- ac_top_srcdir=$ac_top_builddir_sub
- ac_abs_top_srcdir=$ac_pwd ;;
- [\\/]* | ?:[\\/]* ) # Absolute name.
- ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir
- ac_abs_top_srcdir=$srcdir ;;
- *) # Relative name.
- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_build_prefix$srcdir
- ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-
- case $ac_mode in
- :F)
- #
- # CONFIG_FILE
- #
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# If the template does not know about datarootdir, expand it.
-# FIXME: This hack should be removed a few years after 2.60.
-ac_datarootdir_hack=; ac_datarootdir_seen=
-ac_sed_dataroot='
-/datarootdir/ {
- p
- q
-}
-/@datadir@/p
-/@docdir@/p
-/@infodir@/p
-/@localedir@/p
-/@mandir@/p'
-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
-*datarootdir*) ac_datarootdir_seen=yes;;
-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
- ac_datarootdir_hack='
- s&@datadir@&$datadir&g
- s&@docdir@&$docdir&g
- s&@infodir@&$infodir&g
- s&@localedir@&$localedir&g
- s&@mandir@&$mandir&g
- s&\\\${datarootdir}&$datarootdir&g' ;;
-esac
-_ACEOF
-
-# Neutralize VPATH when `$srcdir' = `.'.
-# Shell code in configure.ac might set extrasub.
-# FIXME: do we really want to maintain this feature?
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_sed_extra="$ac_vpsub
-$extrasub
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-:t
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s|@configure_input@|$ac_sed_conf_input|;t t
-s&@top_builddir@&$ac_top_builddir_sub&;t t
-s&@top_build_prefix@&$ac_top_build_prefix&;t t
-s&@srcdir@&$ac_srcdir&;t t
-s&@abs_srcdir@&$ac_abs_srcdir&;t t
-s&@top_srcdir@&$ac_top_srcdir&;t t
-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
-s&@builddir@&$ac_builddir&;t t
-s&@abs_builddir@&$ac_abs_builddir&;t t
-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
-$ac_datarootdir_hack
-"
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
- >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-
-test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
- { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
- "$ac_tmp/out"`; test -z "$ac_out"; } &&
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined" >&5
-printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined" >&2;}
-
- rm -f "$ac_tmp/stdin"
- case $ac_file in
- -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
- *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
- esac \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- ;;
-
-
-
- esac
-
-done # for ac_tag
-
-
-as_fn_exit 0
-_ACEOF
-ac_clean_files=$ac_clean_files_save
-
-test $ac_write_fail = 0 ||
- as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
-
-
-# configure is writing to config.log, and then calls config.status.
-# config.status does its own redirection, appending to config.log.
-# Unfortunately, on DOS this fails, as config.log is still kept open
-# by configure, so config.status won't be able to write to it; its
-# output is simply discarded. So we exec the FD to /dev/null,
-# effectively closing config.log, so it can be properly (re)opened and
-# appended to by config.status. When coming back to configure, we
-# need to make the FD available again.
-if test "$no_create" != yes; then
- ac_cs_success=:
- ac_config_status_args=
- test "$silent" = yes &&
- ac_config_status_args="$ac_config_status_args --quiet"
- exec 5>/dev/null
- $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
- exec 5>>config.log
- # Use ||, not &&, to avoid exiting from the if with $? = 1, which
- # would make configure fail if this is the last instruction.
- $ac_cs_success || as_fn_exit 1
-fi
-if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
-fi
-
-
+#!/bin/sh
+dir0="`dirname "$0"`"
+dirA="$dir0/../autosetup"
+# This is the case ^^^^^^^^^^^^ in the SQLite "autoconf" bundle.
+WRAPPER="$0"; export WRAPPER; exec "`"$dirA/autosetup-find-tclsh"`" \
+ "$dirA/autosetup" --teaish-extension-dir="$dir0" \
+ "$@"
diff --git a/contrib/sqlite3/tea/configure.ac b/contrib/sqlite3/tea/configure.ac
deleted file mode 100644
index ea7eeda70fff..000000000000
--- a/contrib/sqlite3/tea/configure.ac
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/bin/bash -norc
-dnl This file is an input file used by the GNU "autoconf" program to
-dnl generate the file "configure", which is run during Tcl installation
-dnl to configure the system for the local environment.
-
-#-----------------------------------------------------------------------
-# Sample configure.ac for Tcl Extensions. The only places you should
-# need to modify this file are marked by the string __CHANGE__
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# __CHANGE__
-# Set your package name and version numbers here.
-#
-# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
-# set as provided. These will also be added as -D defs in your Makefile
-# so you can encode the package version directly into the source files.
-# This will also define a special symbol for Windows (BUILD_<PACKAGE_NAME>
-# so that we create the export library with the dll.
-#-----------------------------------------------------------------------
-
-AC_INIT([sqlite],[3.46.1])
-
-#--------------------------------------------------------------------
-# Call TEA_INIT as the first TEA_ macro to set up initial vars.
-# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
-# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
-#--------------------------------------------------------------------
-
-TEA_INIT()
-
-AC_CONFIG_AUX_DIR(tclconfig)
-
-#--------------------------------------------------------------------
-# Load the tclConfig.sh file
-#--------------------------------------------------------------------
-
-TEA_PATH_TCLCONFIG
-TEA_LOAD_TCLCONFIG
-
-#--------------------------------------------------------------------
-# Load the tkConfig.sh file if necessary (Tk extension)
-#--------------------------------------------------------------------
-
-#TEA_PATH_TKCONFIG
-#TEA_LOAD_TKCONFIG
-
-#-----------------------------------------------------------------------
-# Handle the --prefix=... option by defaulting to what Tcl gave.
-# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER.
-#-----------------------------------------------------------------------
-
-TEA_PREFIX
-
-#-----------------------------------------------------------------------
-# Standard compiler checks.
-# This sets up CC by using the CC env var, or looks for gcc otherwise.
-# This also calls AC_PROG_CC and a few others to create the basic setup
-# necessary to compile executables.
-#-----------------------------------------------------------------------
-
-TEA_SETUP_COMPILER
-
-#-----------------------------------------------------------------------
-# __CHANGE__
-# Specify the C source files to compile in TEA_ADD_SOURCES,
-# public headers that need to be installed in TEA_ADD_HEADERS,
-# stub library C source files to compile in TEA_ADD_STUB_SOURCES,
-# and runtime Tcl library files in TEA_ADD_TCL_SOURCES.
-# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS
-# and PKG_TCL_SOURCES.
-#-----------------------------------------------------------------------
-
-TEA_ADD_SOURCES([tclsqlite3.c])
-TEA_ADD_HEADERS([])
-TEA_ADD_INCLUDES([])
-TEA_ADD_LIBS([])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS3=1])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS4=1])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS5=1])
-TEA_ADD_CFLAGS([-DSQLITE_3_SUFFIX_ONLY=1])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_RTREE=1])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_GEOPOLY=1])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_MATH_FUNCTIONS=1])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DESERIALIZE=1])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DBPAGE_VTAB=1])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_BYTECODE_VTAB=1])
-TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DBSTAT_VTAB=1])
-TEA_ADD_STUB_SOURCES([])
-TEA_ADD_TCL_SOURCES([])
-
-#--------------------------------------------------------------------
-# The --with-system-sqlite causes the TCL bindings to SQLite to use
-# the system shared library for SQLite rather than statically linking
-# against its own private copy. This is dangerous and leads to
-# undersirable dependences and is not recommended.
-# Patchs from rmax.
-#--------------------------------------------------------------------
-AC_ARG_WITH([system-sqlite],
- [AC_HELP_STRING([--with-system-sqlite],
- [use a system-supplied libsqlite3 instead of the bundled one])],
- [], [with_system_sqlite=no])
-if test x$with_system_sqlite != xno; then
- AC_CHECK_HEADER([sqlite3.h],
- [AC_CHECK_LIB([sqlite3],[sqlite3_initialize],
- [AC_DEFINE(USE_SYSTEM_SQLITE)
- LIBS="$LIBS -lsqlite3"])])
-fi
-
-#--------------------------------------------------------------------
-# __CHANGE__
-#
-# You can add more files to clean if your extension creates any extra
-# files by extending CLEANFILES.
-# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
-# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
-#
-# A few miscellaneous platform-specific items:
-# TEA_ADD_* any platform specific compiler/build info here.
-#--------------------------------------------------------------------
-
-#CLEANFILES="$CLEANFILES pkgIndex.tcl"
-if test "${TEA_PLATFORM}" = "windows" ; then
- # Ensure no empty if clauses
- :
- #TEA_ADD_SOURCES([win/winFile.c])
- #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"])
-else
- # Ensure no empty else clauses
- :
- #TEA_ADD_SOURCES([unix/unixFile.c])
- #TEA_ADD_LIBS([-lsuperfly])
-fi
-
-#--------------------------------------------------------------------
-# __CHANGE__
-# Choose which headers you need. Extension authors should try very
-# hard to only rely on the Tcl public header files. Internal headers
-# contain private data structures and are subject to change without
-# notice.
-# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG
-#--------------------------------------------------------------------
-
-TEA_PUBLIC_TCL_HEADERS
-#TEA_PRIVATE_TCL_HEADERS
-
-#TEA_PUBLIC_TK_HEADERS
-#TEA_PRIVATE_TK_HEADERS
-#TEA_PATH_X
-
-#--------------------------------------------------------------------
-# Check whether --enable-threads or --disable-threads was given.
-# This auto-enables if Tcl was compiled threaded.
-#--------------------------------------------------------------------
-
-TEA_ENABLE_THREADS
-if test "${TCL_THREADS}" = "1" ; then
- AC_DEFINE(SQLITE_THREADSAFE, 1, [Trigger sqlite threadsafe build])
- # Not automatically added by Tcl because its assumed Tcl links to them,
- # but it may not if it isn't really a threaded build.
- TEA_ADD_LIBS([$THREADS_LIBS])
-else
- AC_DEFINE(SQLITE_THREADSAFE, 0, [Trigger sqlite non-threadsafe build])
-fi
-
-#--------------------------------------------------------------------
-# The statement below defines a collection of symbols related to
-# building as a shared library instead of a static library.
-#--------------------------------------------------------------------
-
-TEA_ENABLE_SHARED
-
-#--------------------------------------------------------------------
-# This macro figures out what flags to use with the compiler/linker
-# when building shared/static debug/optimized objects. This information
-# can be taken from the tclConfig.sh file, but this figures it all out.
-#--------------------------------------------------------------------
-
-TEA_CONFIG_CFLAGS
-
-#--------------------------------------------------------------------
-# Set the default compiler switches based on the --enable-symbols option.
-#--------------------------------------------------------------------
-
-TEA_ENABLE_SYMBOLS
-
-#--------------------------------------------------------------------
-# This macro generates a line to use when building a library. It
-# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
-# and TEA_LOAD_TCLCONFIG macros above.
-#--------------------------------------------------------------------
-
-TEA_MAKE_LIB
-
-#--------------------------------------------------------------------
-# Determine the name of the tclsh and/or wish executables in the
-# Tcl and Tk build directories or the location they were installed
-# into. These paths are used to support running test cases only,
-# the Makefile should not be making use of these paths to generate
-# a pkgIndex.tcl file or anything else at extension build time.
-#--------------------------------------------------------------------
-
-TEA_PROG_TCLSH
-#TEA_PROG_WISH
-
-#--------------------------------------------------------------------
-# Setup a *Config.sh.in configuration file.
-#--------------------------------------------------------------------
-
-#TEA_EXPORT_CONFIG([sample])
-#AC_SUBST(SAMPLE_VAR)
-
-#--------------------------------------------------------------------
-# Specify files to substitute AC variables in. You may alternatively
-# have a special pkgIndex.tcl.in or other files which require
-# substituting the AC variables in. Include these here.
-#--------------------------------------------------------------------
-
-AC_CONFIG_FILES([Makefile pkgIndex.tcl])
-#AC_CONFIG_FILES([sampleConfig.sh])
-
-#--------------------------------------------------------------------
-# Finally, substitute all of the various values into the files
-# specified with AC_CONFIG_FILES.
-#--------------------------------------------------------------------
-
-AC_OUTPUT
diff --git a/contrib/sqlite3/tea/doc/sqlite3.n b/contrib/sqlite3/tea/doc/sqlite3.n
index 13913e5583d8..3514046342da 100644
--- a/contrib/sqlite3/tea/doc/sqlite3.n
+++ b/contrib/sqlite3/tea/doc/sqlite3.n
@@ -11,5 +11,5 @@ SQLite3 is a self-contains, zero-configuration, transactional SQL database
engine. This extension provides an easy to use interface for accessing
SQLite database files from Tcl.
.PP
-For full documentation see \fIhttp://www.sqlite.org/\fR and
-in particular \fIhttp://www.sqlite.org/tclsqlite.html\fR.
+For full documentation see \fIhttps://sqlite.org/\fR and
+in particular \fIhttps://sqlite.org/tclsqlite.html\fR.
diff --git a/contrib/sqlite3/tea/generic/tclsqlite3.c b/contrib/sqlite3/tea/generic/tclsqlite3.c
index 0810b079e2e6..197ce744836c 100644
--- a/contrib/sqlite3/tea/generic/tclsqlite3.c
+++ b/contrib/sqlite3/tea/generic/tclsqlite3.c
@@ -1,7 +1,7 @@
#ifdef USE_SYSTEM_SQLITE
# include <sqlite3.h>
#else
-#include "sqlite3.c"
+# include "sqlite3.c"
#endif
/*
** 2001 September 15
@@ -40,14 +40,23 @@
# include "msvc.h"
#endif
+/****** Copy of tclsqlite.h ******/
#if defined(INCLUDE_SQLITE_TCL_H)
-# include "sqlite_tcl.h"
+# include "sqlite_tcl.h" /* Special case for Windows using STDCALL */
#else
-# include "tcl.h"
+# include <tcl.h> /* All normal cases */
# ifndef SQLITE_TCLAPI
-# define SQLITE_TCLAPI
+# define SQLITE_TCLAPI
# endif
#endif
+/* Compatability between Tcl8.6 and Tcl9.0 */
+#if TCL_MAJOR_VERSION==9
+# define CONST const
+#elif !defined(Tcl_Size)
+ typedef int Tcl_Size;
+#endif
+/**** End copy of tclsqlite.h ****/
+
#include <errno.h>
/*
@@ -72,7 +81,9 @@
# define SQLITE_PTRSIZE 8
# endif
# endif /* SQLITE_PTRSIZE */
-# if defined(HAVE_STDINT_H)
+# if defined(HAVE_STDINT_H) || (defined(__STDC_VERSION__) && \
+ (__STDC_VERSION__ >= 199901L))
+# include <stdint.h>
typedef uintptr_t uptr;
# elif SQLITE_PTRSIZE==4
typedef unsigned int uptr;
@@ -214,7 +225,8 @@ struct SqliteDb {
struct IncrblobChannel {
sqlite3_blob *pBlob; /* sqlite3 blob handle */
SqliteDb *pDb; /* Associated database connection */
- int iSeek; /* Current seek offset */
+ sqlite3_int64 iSeek; /* Current seek offset */
+ unsigned int isClosed; /* TCL_CLOSE_READ or TCL_CLOSE_WRITE */
Tcl_Channel channel; /* Channel identifier */
IncrblobChannel *pNext; /* Linked list of all open incrblob channels */
IncrblobChannel *pPrev; /* Linked list of all open incrblob channels */
@@ -254,14 +266,23 @@ static void closeIncrblobChannels(SqliteDb *pDb){
/*
** Close an incremental blob channel.
*/
-static int SQLITE_TCLAPI incrblobClose(
+static int SQLITE_TCLAPI incrblobClose2(
ClientData instanceData,
- Tcl_Interp *interp
+ Tcl_Interp *interp,
+ int flags
){
IncrblobChannel *p = (IncrblobChannel *)instanceData;
- int rc = sqlite3_blob_close(p->pBlob);
+ int rc;
sqlite3 *db = p->pDb->db;
+ if( flags ){
+ p->isClosed |= flags;
+ return TCL_OK;
+ }
+
+ /* If we reach this point, then we really do need to close the channel */
+ rc = sqlite3_blob_close(p->pBlob);
+
/* Remove the channel from the SqliteDb.pIncrblob list. */
if( p->pNext ){
p->pNext->pPrev = p->pPrev;
@@ -282,6 +303,13 @@ static int SQLITE_TCLAPI incrblobClose(
}
return TCL_OK;
}
+static int SQLITE_TCLAPI incrblobClose(
+ ClientData instanceData,
+ Tcl_Interp *interp
+){
+ return incrblobClose2(instanceData, interp, 0);
+}
+
/*
** Read data from an incremental blob channel.
@@ -293,9 +321,9 @@ static int SQLITE_TCLAPI incrblobInput(
int *errorCodePtr
){
IncrblobChannel *p = (IncrblobChannel *)instanceData;
- int nRead = bufSize; /* Number of bytes to read */
- int nBlob; /* Total size of the blob */
- int rc; /* sqlite error code */
+ sqlite3_int64 nRead = bufSize; /* Number of bytes to read */
+ sqlite3_int64 nBlob; /* Total size of the blob */
+ int rc; /* sqlite error code */
nBlob = sqlite3_blob_bytes(p->pBlob);
if( (p->iSeek+nRead)>nBlob ){
@@ -305,7 +333,7 @@ static int SQLITE_TCLAPI incrblobInput(
return 0;
}
- rc = sqlite3_blob_read(p->pBlob, (void *)buf, nRead, p->iSeek);
+ rc = sqlite3_blob_read(p->pBlob, (void *)buf, (int)nRead, (int)p->iSeek);
if( rc!=SQLITE_OK ){
*errorCodePtr = rc;
return -1;
@@ -320,14 +348,14 @@ static int SQLITE_TCLAPI incrblobInput(
*/
static int SQLITE_TCLAPI incrblobOutput(
ClientData instanceData,
- CONST char *buf,
+ const char *buf,
int toWrite,
int *errorCodePtr
){
IncrblobChannel *p = (IncrblobChannel *)instanceData;
- int nWrite = toWrite; /* Number of bytes to write */
- int nBlob; /* Total size of the blob */
- int rc; /* sqlite error code */
+ sqlite3_int64 nWrite = toWrite; /* Number of bytes to write */
+ sqlite3_int64 nBlob; /* Total size of the blob */
+ int rc; /* sqlite error code */
nBlob = sqlite3_blob_bytes(p->pBlob);
if( (p->iSeek+nWrite)>nBlob ){
@@ -338,7 +366,7 @@ static int SQLITE_TCLAPI incrblobOutput(
return 0;
}
- rc = sqlite3_blob_write(p->pBlob, (void *)buf, nWrite, p->iSeek);
+ rc = sqlite3_blob_write(p->pBlob, (void*)buf,(int)nWrite, (int)p->iSeek);
if( rc!=SQLITE_OK ){
*errorCodePtr = EIO;
return -1;
@@ -348,12 +376,19 @@ static int SQLITE_TCLAPI incrblobOutput(
return nWrite;
}
+/* The datatype of Tcl_DriverWideSeekProc changes between tcl8.6 and tcl9.0 */
+#if TCL_MAJOR_VERSION==9
+# define WideSeekProcType long long
+#else
+# define WideSeekProcType Tcl_WideInt
+#endif
+
/*
** Seek an incremental blob channel.
*/
-static int SQLITE_TCLAPI incrblobSeek(
+static WideSeekProcType SQLITE_TCLAPI incrblobWideSeek(
ClientData instanceData,
- long offset,
+ WideSeekProcType offset,
int seekMode,
int *errorCodePtr
){
@@ -375,6 +410,14 @@ static int SQLITE_TCLAPI incrblobSeek(
return p->iSeek;
}
+static int SQLITE_TCLAPI incrblobSeek(
+ ClientData instanceData,
+ long offset,
+ int seekMode,
+ int *errorCodePtr
+){
+ return incrblobWideSeek(instanceData,offset,seekMode,errorCodePtr);
+}
static void SQLITE_TCLAPI incrblobWatch(
@@ -393,7 +436,7 @@ static int SQLITE_TCLAPI incrblobHandle(
static Tcl_ChannelType IncrblobChannelType = {
"incrblob", /* typeName */
- TCL_CHANNEL_VERSION_2, /* version */
+ TCL_CHANNEL_VERSION_5, /* version */
incrblobClose, /* closeProc */
incrblobInput, /* inputProc */
incrblobOutput, /* outputProc */
@@ -402,11 +445,11 @@ static Tcl_ChannelType IncrblobChannelType = {
0, /* getOptionProc */
incrblobWatch, /* watchProc (this is a no-op) */
incrblobHandle, /* getHandleProc (always returns error) */
- 0, /* close2Proc */
+ incrblobClose2, /* close2Proc */
0, /* blockModeProc */
0, /* flushProc */
0, /* handlerProc */
- 0, /* wideSeekProc */
+ incrblobWideSeek, /* wideSeekProc */
};
/*
@@ -438,8 +481,9 @@ static int createIncrblobChannel(
}
p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel));
- p->iSeek = 0;
+ memset(p, 0, sizeof(*p));
p->pBlob = pBlob;
+ if( (flags & TCL_WRITABLE)==0 ) p->isClosed |= TCL_CLOSE_WRITE;
sqlite3_snprintf(sizeof(zChannel), zChannel, "incrblob_%d", ++count);
p->channel = Tcl_CreateChannel(&IncrblobChannelType, zChannel, p, flags);
@@ -473,13 +517,13 @@ static int createIncrblobChannel(
** or {...} or ; to be seen anywhere. Most callback scripts consist
** of just a single procedure name and they meet this requirement.
*/
-static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){
+static int safeToUseEvalObjv(Tcl_Obj *pCmd){
/* We could try to do something with Tcl_Parse(). But we will instead
** just do a search for forbidden characters. If any of the forbidden
** characters appear in pCmd, we will report the string as unsafe.
*/
const char *z;
- int n;
+ Tcl_Size n;
z = Tcl_GetStringFromObj(pCmd, &n);
while( n-- > 0 ){
int c = *(z++);
@@ -986,7 +1030,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
** be preserved and reused on the next invocation.
*/
Tcl_Obj **aArg;
- int nArg;
+ Tcl_Size nArg;
if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
return;
@@ -1049,7 +1093,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
}else{
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
- int n;
+ Tcl_Size n;
u8 *data;
const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
char c = zType[0];
@@ -1060,7 +1104,8 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
/* Only return a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */
eType = SQLITE_BLOB;
- }else if( (c=='b' && strcmp(zType,"boolean")==0)
+ }else if( (c=='b' && pVar->bytes==0 && strcmp(zType,"boolean")==0 )
+ || (c=='b' && pVar->bytes==0 && strcmp(zType,"booleanString")==0 )
|| (c=='w' && strcmp(zType,"wideInt")==0)
|| (c=='i' && strcmp(zType,"int")==0)
){
@@ -1096,7 +1141,8 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
}
default: {
data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
- sqlite3_result_text(context, (char *)data, n, SQLITE_TRANSIENT);
+ sqlite3_result_text64(context, (char *)data, n, SQLITE_TRANSIENT,
+ SQLITE_UTF8);
break;
}
}
@@ -1118,9 +1164,6 @@ static int auth_callback(
const char *zArg2,
const char *zArg3,
const char *zArg4
-#ifdef SQLITE_USER_AUTHENTICATION
- ,const char *zArg5
-#endif
){
const char *zCode;
Tcl_DString str;
@@ -1180,9 +1223,6 @@ static int auth_callback(
Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
-#ifdef SQLITE_USER_AUTHENTICATION
- Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : "");
-#endif
rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
Tcl_DStringFree(&str);
zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
@@ -1199,6 +1239,7 @@ static int auth_callback(
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
+#if 0
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
@@ -1243,6 +1284,7 @@ static char *local_getline(char *zPrompt, FILE *in){
zLine = realloc( zLine, n+1 );
return zLine;
}
+#endif
/*
@@ -1460,7 +1502,7 @@ static int dbPrepareAndBind(
}
}
if( pVar ){
- int n;
+ Tcl_Size n;
u8 *data;
const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
c = zType[0];
@@ -1473,9 +1515,13 @@ static int dbPrepareAndBind(
sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC);
Tcl_IncrRefCount(pVar);
pPreStmt->apParm[iParm++] = pVar;
- }else if( c=='b' && strcmp(zType,"boolean")==0 ){
- Tcl_GetIntFromObj(interp, pVar, &n);
- sqlite3_bind_int(pStmt, i, n);
+ }else if( c=='b' && pVar->bytes==0
+ && (strcmp(zType,"booleanString")==0
+ || strcmp(zType,"boolean")==0)
+ ){
+ int nn;
+ Tcl_GetBooleanFromObj(interp, pVar, &nn);
+ sqlite3_bind_int(pStmt, i, nn);
}else if( c=='d' && strcmp(zType,"double")==0 ){
double r;
Tcl_GetDoubleFromObj(interp, pVar, &r);
@@ -1487,7 +1533,8 @@ static int dbPrepareAndBind(
sqlite3_bind_int64(pStmt, i, v);
}else{
data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
- sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC);
+ sqlite3_bind_text64(pStmt, i, (char *)data, n, SQLITE_STATIC,
+ SQLITE_UTF8);
Tcl_IncrRefCount(pVar);
pPreStmt->apParm[iParm++] = pVar;
}
@@ -1809,7 +1856,8 @@ static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){
** are 8.6 or newer, the code still tests the Tcl version at runtime.
** This allows stubs-enabled builds to be used with older Tcl libraries.
*/
-#if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6)
+#if TCL_MAJOR_VERSION>8 || !defined(TCL_MINOR_VERSION) \
+ || TCL_MINOR_VERSION>=6
# define SQLITE_TCL_NRE 1
static int DbUseNre(void){
int major, minor;
@@ -1925,7 +1973,7 @@ static void DbHookCmd(
}
if( pArg ){
assert( !(*ppHook) );
- if( Tcl_GetCharLength(pArg)>0 ){
+ if( Tcl_GetString(pArg)[0] ){
*ppHook = pArg;
Tcl_IncrRefCount(*ppHook);
}
@@ -2018,7 +2066,7 @@ static int SQLITE_TCLAPI DbObjCmd(
** (4) Name of the database (ex: "main", "temp")
** (5) Name of trigger that is doing the access
**
- ** The callback should return on of the following strings: SQLITE_OK,
+ ** The callback should return one of the following strings: SQLITE_OK,
** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error.
**
** If this method is invoked with no arguments, the current authorization
@@ -2039,7 +2087,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
}else{
char *zAuth;
- int len;
+ Tcl_Size len;
if( pDb->zAuth ){
Tcl_Free(pDb->zAuth);
}
@@ -2142,7 +2190,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
}else{
char *zCallback;
- int len;
+ Tcl_Size len;
if( pDb->zBindFallback ){
Tcl_Free(pDb->zBindFallback);
}
@@ -2172,7 +2220,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
}else{
char *zBusy;
- int len;
+ Tcl_Size len;
if( pDb->zBusy ){
Tcl_Free(pDb->zBusy);
}
@@ -2279,7 +2327,7 @@ static int SQLITE_TCLAPI DbObjCmd(
SqlCollate *pCollate;
char *zName;
char *zScript;
- int nScript;
+ Tcl_Size nScript;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
return TCL_ERROR;
@@ -2338,7 +2386,7 @@ static int SQLITE_TCLAPI DbObjCmd(
}
}else{
const char *zCommit;
- int len;
+ Tcl_Size len;
if( pDb->zCommit ){
Tcl_Free(pDb->zCommit);
}
@@ -2481,9 +2529,10 @@ static int SQLITE_TCLAPI DbObjCmd(
char *zLine; /* A single line of input from the file */
char **azCol; /* zLine[] broken up into columns */
const char *zCommit; /* How to commit changes */
- FILE *in; /* The input file */
+ Tcl_Channel in; /* The input file */
int lineno = 0; /* Line number of input file */
char zLineNum[80]; /* Line number print buffer */
+ Tcl_Obj *str;
Tcl_Obj *pResult; /* interp result */
const char *zSep;
@@ -2562,23 +2611,27 @@ static int SQLITE_TCLAPI DbObjCmd(
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
- in = fopen(zFile, "rb");
+ in = Tcl_OpenFileChannel(interp, zFile, "rb", 0666);
if( in==0 ){
- Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, (char*)0);
sqlite3_finalize(pStmt);
return TCL_ERROR;
}
+ Tcl_SetChannelOption(NULL, in, "-translation", "auto");
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
if( azCol==0 ) {
Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0);
- fclose(in);
+ Tcl_Close(interp, in);
return TCL_ERROR;
}
+ str = Tcl_NewObj();
+ Tcl_IncrRefCount(str);
(void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
zCommit = "COMMIT";
- while( (zLine = local_getline(0, in))!=0 ){
+ while( Tcl_GetsObj(in, str)>=0 ) {
char *z;
+ Tcl_Size byteLen;
lineno++;
+ zLine = (char *)Tcl_GetByteArrayFromObj(str, &byteLen);
azCol[0] = zLine;
for(i=0, z=zLine; *z; z++){
if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
@@ -2616,15 +2669,16 @@ static int SQLITE_TCLAPI DbObjCmd(
}
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
- free(zLine);
+ Tcl_SetObjLength(str, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), (char*)0);
zCommit = "ROLLBACK";
break;
}
}
+ Tcl_DecrRefCount(str);
free(azCol);
- fclose(in);
+ Tcl_Close(interp, in);
sqlite3_finalize(pStmt);
(void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
@@ -2658,7 +2712,8 @@ static int SQLITE_TCLAPI DbObjCmd(
Tcl_Obj *pValue = 0;
unsigned char *pBA;
unsigned char *pData;
- int len, xrc;
+ Tcl_Size len;
+ int xrc;
sqlite3_int64 mxSize = 0;
int i;
int isReadonly = 0;
@@ -2953,7 +3008,7 @@ deserialize_error:
}
pFunc->pScript = pScript;
Tcl_IncrRefCount(pScript);
- pFunc->useEvalObjv = safeToUseEvalObjv(interp, pScript);
+ pFunc->useEvalObjv = safeToUseEvalObjv(pScript);
pFunc->eType = eType;
rc = sqlite3_create_function(pDb->db, zName, nArg, flags,
pFunc, tclSqlFunc, 0, 0);
@@ -3029,7 +3084,7 @@ deserialize_error:
return TCL_ERROR;
}
if( objc==3 ){
- int len;
+ Tcl_Size len;
char *zNull = Tcl_GetStringFromObj(objv[2], &len);
if( pDb->zNull ){
Tcl_Free(pDb->zNull);
@@ -3083,7 +3138,7 @@ deserialize_error:
#endif
}else if( objc==4 ){
char *zProgress;
- int len;
+ Tcl_Size len;
int N;
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
return TCL_ERROR;
@@ -3129,7 +3184,7 @@ deserialize_error:
}
}else{
char *zProfile;
- int len;
+ Tcl_Size len;
if( pDb->zProfile ){
Tcl_Free(pDb->zProfile);
}
@@ -3340,7 +3395,7 @@ deserialize_error:
}
}else{
char *zTrace;
- int len;
+ Tcl_Size len;
if( pDb->zTrace ){
Tcl_Free(pDb->zTrace);
}
@@ -3380,7 +3435,7 @@ deserialize_error:
}
}else{
char *zTraceV2;
- int len;
+ Tcl_Size len;
Tcl_WideInt wMask = 0;
if( objc==4 ){
static const char *TTYPE_strs[] = {
@@ -3389,7 +3444,7 @@ deserialize_error:
enum TTYPE_enum {
TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE
};
- int i;
+ Tcl_Size i;
if( TCL_OK!=Tcl_ListObjLength(interp, objv[3], &len) ){
return TCL_ERROR;
}
@@ -3942,7 +3997,7 @@ static int SQLITE_TCLAPI DbMain(
** The EXTERN macros are required by TCL in order to work on windows.
*/
EXTERN int Sqlite3_Init(Tcl_Interp *interp){
- int rc = Tcl_InitStubs(interp, "8.4", 0) ? TCL_OK : TCL_ERROR;
+ int rc = Tcl_InitStubs(interp, "8.5-", 0) ? TCL_OK : TCL_ERROR;
if( rc==TCL_OK ){
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
#ifndef SQLITE_3_SUFFIX_ONLY
@@ -3966,14 +4021,27 @@ EXTERN int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}
+/*
+** Versions of all of the above entry points that omit the "3" at the end
+** of the name. Years ago (circa 2004) the "3" was necessary to distinguish
+** SQLite version 3 from Sqlite version 2. But two decades have elapsed.
+** SQLite2 is not longer a conflict. So it is ok to omit the "3".
+**
+** Omitting the "3" helps TCL find the entry point.
+*/
+EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
+EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
+EXTERN int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
+EXTERN int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
+EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_ERROR; }
+EXTERN int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){return TCL_ERROR;}
+/* Also variants with a lowercase "s". I'm told that these are
+** deprecated in Tcl9, but they continue to be included for backwards
+** compatibility. */
+EXTERN int sqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
+EXTERN int sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp);}
-#ifndef SQLITE_3_SUFFIX_ONLY
-int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
-int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
-int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
-int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
-#endif
/*
** If the TCLSH macro is defined, add code to make a stand-alone program.
@@ -3981,12 +4049,29 @@ int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
#if defined(TCLSH)
/* This is the main routine for an ordinary TCL shell. If there are
-** are arguments, run the first argument as a script. Otherwise,
-** read TCL commands from standard input
+** arguments, run the first argument as a script. Otherwise, read TCL
+** commands from standard input
*/
static const char *tclsh_main_loop(void){
static const char zMainloop[] =
"if {[llength $argv]>=1} {\n"
+#ifdef WIN32
+ "set new [list]\n"
+ "foreach arg $argv {\n"
+ "if {[string match -* $arg] || [file exists $arg]} {\n"
+ "lappend new $arg\n"
+ "} else {\n"
+ "set once 0\n"
+ "foreach match [lsort [glob -nocomplain $arg]] {\n"
+ "lappend new $match\n"
+ "set once 1\n"
+ "}\n"
+ "if {!$once} {lappend new $arg}\n"
+ "}\n"
+ "}\n"
+ "set argv $new\n"
+ "unset new\n"
+#endif
"set argv0 [lindex $argv 0]\n"
"set argv [lrange $argv 1 end]\n"
"source $argv0\n"
diff --git a/contrib/sqlite3/tea/pkgIndex.tcl.in b/contrib/sqlite3/tea/pkgIndex.tcl.in
index f95f7d3893dd..c93fcc6854e5 100644
--- a/contrib/sqlite3/tea/pkgIndex.tcl.in
+++ b/contrib/sqlite3/tea/pkgIndex.tcl.in
@@ -1,10 +1,40 @@
# -*- tcl -*-
-# Tcl package index file, version 1.1
+# Tcl package index file
#
+# Unless this file is named pkgIndex.tcl.in, you are probably looking
+# at an automatically generated/filtered copy and should probably not
+# edit it.
+#
+# Adapted from https://core.tcl-lang.org/tcltls
+@if TEAISH_VSATISFIES_CODE
+@TEAISH_VSATISFIES_CODE@
+@endif
if {[package vsatisfies [package provide Tcl] 9.0-]} {
- package ifneeded sqlite3 @PACKAGE_VERSION@ \
- [list load [file join $dir @PKG_LIB_FILE9@] sqlite3]
+ package ifneeded {@TEAISH_PKGNAME@} {@TEAISH_VERSION@} [list apply {{dir} {
+@if TEAISH_ENABLE_DLL
+ load [file join $dir {@TEAISH_DLL9@}] @TEAISH_LOAD_PREFIX@
+@endif
+@if TEAISH_PKGINIT_TCL_TAIL
+ set initScript [file join $dir {@TEAISH_PKGINIT_TCL_TAIL@}]
+ if {[file exists $initScript]} {
+ source -encoding utf-8 $initScript
+ }
+@endif
+ }} $dir]
} else {
- package ifneeded sqlite3 @PACKAGE_VERSION@ \
- [list load [file join $dir @PKG_LIB_FILE8@] sqlite3]
+ package ifneeded {@TEAISH_PKGNAME@} {@TEAISH_VERSION@} [list apply {{dir} {
+@if TEAISH_ENABLE_DLL
+ if {[string tolower [file extension {@TEAISH_DLL8@}]] in [list .dll .dylib .so]} {
+ load [file join $dir {@TEAISH_DLL8@}] @TEAISH_LOAD_PREFIX@
+ } else {
+ load {} @TEAISH_LOAD_PREFIX@
+ }
+@endif
+@if TEAISH_PKGINIT_TCL_TAIL
+ set initScript [file join $dir {@TEAISH_PKGINIT_TCL_TAIL@}]
+ if {[file exists $initScript]} {
+ source -encoding utf-8 $initScript
+ }
+@endif
+ }} $dir]
}
diff --git a/contrib/sqlite3/tea/tclconfig/install-sh b/contrib/sqlite3/tea/tclconfig/install-sh
deleted file mode 100644
index 7c34c3f92603..000000000000
--- a/contrib/sqlite3/tea/tclconfig/install-sh
+++ /dev/null
@@ -1,528 +0,0 @@
-#!/bin/sh
-# install - install a program, script, or datafile
-
-scriptversion=2011-04-20.01; # UTC
-
-# This originates from X11R5 (mit/util/scripts/install.sh), which was
-# later released in X11R6 (xc/config/util/install.sh) with the
-# following copyright and license.
-#
-# Copyright (C) 1994 X Consortium
-#
-# 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
-# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
-# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# Except as contained in this notice, the name of the X Consortium shall not
-# be used in advertising or otherwise to promote the sale, use or other deal-
-# ings in this Software without prior written authorization from the X Consor-
-# tium.
-#
-#
-# FSF changes to this file are in the public domain.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# `make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch.
-
-nl='
-'
-IFS=" "" $nl"
-
-# 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
-
-# Put in absolute file names if you don't have them in your path;
-# or use environment vars.
-
-chgrpprog=${CHGRPPROG-chgrp}
-chmodprog=${CHMODPROG-chmod}
-chownprog=${CHOWNPROG-chown}
-cmpprog=${CMPPROG-cmp}
-cpprog=${CPPROG-cp}
-mkdirprog=${MKDIRPROG-mkdir}
-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.
-mode=0755
-
-chgrpcmd=
-chmodcmd=$chmodprog
-chowncmd=
-mvcmd=$mvprog
-rmcmd="$rmprog -f"
-stripcmd=
-
-src=
-dst=
-dir_arg=
-dst_arg=
-
-copy_on_change=false
-no_target_directory=
-
-usage="\
-Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
- or: $0 [OPTION]... SRCFILES... DIRECTORY
- or: $0 [OPTION]... -t DIRECTORY SRCFILES...
- or: $0 [OPTION]... -d DIRECTORIES...
-
-In the 1st form, copy SRCFILE to DSTFILE.
-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-In the 4th, create DIRECTORIES.
-
-Options:
- --help display this help and exit.
- --version display version info and exit.
-
- -c (ignored)
- -C install only if different (preserve the last data modification time)
- -d create directories instead of installing files.
- -g GROUP $chgrpprog installed files to GROUP.
- -m MODE $chmodprog installed files to MODE.
- -o USER $chownprog installed files to USER.
- -s $stripprog installed files.
- -S $stripprog installed files.
- -t DIRECTORY install into DIRECTORY.
- -T report an error if DSTFILE is a directory.
-
-Environment variables override the default commands:
- CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
- RMPROG STRIPPROG
-"
-
-while test $# -ne 0; do
- case $1 in
- -c) ;;
-
- -C) copy_on_change=true;;
-
- -d) dir_arg=true;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift;;
-
- --help) echo "$usage"; exit $?;;
-
- -m) mode=$2
- case $mode in
- *' '* | *' '* | *'
-'* | *'*'* | *'?'* | *'['*)
- echo "$0: invalid mode: $mode" >&2
- exit 1;;
- esac
- shift;;
-
- -o) chowncmd="$chownprog $2"
- shift;;
-
- -s) stripcmd=$stripprog;;
-
- -S) stripcmd="$stripprog $2"
- shift;;
-
- -t) dst_arg=$2
- shift;;
-
- -T) no_target_directory=true;;
-
- --version) echo "$0 $scriptversion"; exit $?;;
-
- --) shift
- break;;
-
- -*) echo "$0: invalid option: $1" >&2
- exit 1;;
-
- *) break;;
- esac
- shift
-done
-
-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.
- # Otherwise, the last argument is the destination. Remove it from $@.
- for arg
- do
- if test -n "$dst_arg"; then
- # $@ is not empty: it contains at least $arg.
- set fnord "$@" "$dst_arg"
- shift # fnord
- fi
- shift # arg
- dst_arg=$arg
- done
-fi
-
-if test $# -eq 0; then
- if test -z "$dir_arg"; then
- echo "$0: no input file specified." >&2
- exit 1
- fi
- # It's OK to call `install-sh -d' without argument.
- # This can happen when creating conditional directories.
- exit 0
-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
- trap "ret=141; $do_exit" 13
- trap "ret=143; $do_exit" 15
-
- # Set umask so as not to create temps with too-generous modes.
- # However, 'strip' requires both read and write access to temps.
- case $mode in
- # Optimize common cases.
- *644) cp_umask=133;;
- *755) cp_umask=22;;
-
- *[0-7])
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw='% 200'
- fi
- cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
- *)
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw=,u+rw
- fi
- cp_umask=$mode$u_plus_rw;;
- esac
-fi
-
-for src
-do
- # Protect names starting with `-'.
- case $src in
- -*) src=./$src;;
- esac
-
- if test -n "$dir_arg"; then
- dst=$src
- dstdir=$dst
- test -d "$dstdir"
- dstdir_status=$?
- else
-
- # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
- # might cause directories to be created, which would be especially bad
- # if $src (and thus $dsttmp) contains '*'.
- if test ! -f "$src" && test ! -d "$src"; then
- echo "$0: $src does not exist." >&2
- exit 1
- fi
-
- if test -z "$dst_arg"; then
- echo "$0: no destination specified." >&2
- exit 1
- fi
-
- dst=$dst_arg
- # Protect names starting with `-'.
- case $dst in
- -*) dst=./$dst;;
- esac
-
- # If destination is a directory, append the input filename; won't work
- # if double slashes aren't ignored.
- if test -d "$dst"; then
- if test -n "$no_target_directory"; then
- echo "$0: $dst_arg: Is a directory" >&2
- exit 1
- fi
- dstdir=$dst
- dst=$dstdir/`basename "$src"`
- 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'
- `
-
- test -d "$dstdir"
- dstdir_status=$?
- fi
- fi
-
- 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-writeable 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;;
- esac
-
- if
- $posix_mkdir && (
- umask $mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
- )
- then :
- else
-
- # The umask is ridiculous, or mkdir does not conform to POSIX,
- # or it failed possibly due to a race condition. Create the
- # directory the slow way, step by step, checking for races as we go.
-
- case $dstdir in
- /*) prefix='/';;
- -*) prefix='./';;
- *) prefix='';;
- esac
-
- eval "$initialize_posix_glob"
-
- oIFS=$IFS
- IFS=/
- $posix_glob set -f
- set fnord $dstdir
- shift
- $posix_glob set +f
- IFS=$oIFS
-
- prefixes=
-
- for d
- do
- test -z "$d" && 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
- fi
- fi
- fi
-
- if test -n "$dir_arg"; then
- { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
- { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
- test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
- else
-
- # Make a couple of temp file names in the proper directory.
- dsttmp=$dstdir/_inst.$$_
- rmtmp=$dstdir/_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") &&
-
- # and set any options; do chmod last to preserve setuid bits.
- #
- # If any of these fail, we abort the whole thing. If we want to
- # ignore errors from any of these, just make sure not to ignore
- # errors from the above "$doit $cpprog $src $dsttmp" command.
- #
- { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
- { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
- { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
-
- # 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 &&
- set X $old && old=:$2:$4:$5:$6 &&
- set X $new && new=:$2:$4:$5:$6 &&
- $posix_glob set +f &&
-
- test "$old" = "$new" &&
- $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
- then
- rm -f "$dsttmp"
- else
- # Rename the file to the real destination.
- $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
-
- # The rename failed, perhaps because mv can't rename something else
- # 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"
- }
- fi || exit 1
-
- trap '' 0
- fi
-done
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/contrib/sqlite3/tea/tclconfig/tcl.m4 b/contrib/sqlite3/tea/tclconfig/tcl.m4
deleted file mode 100644
index c83d660e184a..000000000000
--- a/contrib/sqlite3/tea/tclconfig/tcl.m4
+++ /dev/null
@@ -1,4067 +0,0 @@
-# tcl.m4 --
-#
-# This file provides a set of autoconf macros to help TEA-enable
-# a Tcl extension.
-#
-# Copyright (c) 1999-2000 Ajuba Solutions.
-# Copyright (c) 2002-2005 ActiveState Corporation.
-#
-# See the file "license.terms" for information on usage and redistribution
-# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
-
-AC_PREREQ([2.69])
-
-# Possible values for key variables defined:
-#
-# TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem')
-# TEA_PLATFORM - windows unix
-# TEA_TK_EXTENSION - True if this is a Tk extension
-#
-
-#------------------------------------------------------------------------
-# TEA_PATH_TCLCONFIG --
-#
-# Locate the tclConfig.sh file and perform a sanity check on
-# the Tcl compile flags
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Adds the following arguments to configure:
-# --with-tcl=...
-#
-# Defines the following vars:
-# TCL_BIN_DIR Full path to the directory containing
-# the tclConfig.sh file
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_PATH_TCLCONFIG], [
- dnl TEA specific: Make sure we are initialized
- AC_REQUIRE([TEA_INIT])
- #
- # Ok, lets find the tcl configuration
- # First, look for one uninstalled.
- # the alternative search directory is invoked by --with-tcl
- #
-
- if test x"${no_tcl}" = x ; then
- # we reset no_tcl in case something fails here
- no_tcl=true
- AC_ARG_WITH(tcl,
- AS_HELP_STRING([--with-tcl],
- [directory containing tcl configuration (tclConfig.sh)]),
- [with_tclconfig="${withval}"])
- AC_MSG_CHECKING([for Tcl configuration])
- AC_CACHE_VAL(ac_cv_c_tclconfig,[
-
- # First check to see if --with-tcl was specified.
- if test x"${with_tclconfig}" != x ; then
- case "${with_tclconfig}" in
- */tclConfig.sh )
- if test -f "${with_tclconfig}"; then
- AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself])
- with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`"
- fi ;;
- esac
- if test -f "${with_tclconfig}/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`"
- else
- AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh])
- fi
- fi
-
- # then check for a private Tcl installation
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- ../tcl \
- `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
- ../../tcl \
- `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
- ../../../tcl \
- `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do
- if test "${TEA_PLATFORM}" = "windows" \
- -a -f "$i/win/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/win; pwd)`"
- break
- fi
- if test -f "$i/unix/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/unix; pwd)`"
- break
- fi
- done
- fi
-
- # on Darwin, check in Framework installation locations
- if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then
- for i in `ls -d ~/Library/Frameworks 2>/dev/null` \
- `ls -d /Library/Frameworks 2>/dev/null` \
- `ls -d /Network/Library/Frameworks 2>/dev/null` \
- `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \
- `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \
- `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \
- ; do
- if test -f "$i/Tcl.framework/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`"
- break
- fi
- done
- fi
-
- # TEA specific: on Windows, check in common installation locations
- if test "${TEA_PLATFORM}" = "windows" \
- -a x"${ac_cv_c_tclconfig}" = x ; then
- for i in `ls -d C:/Tcl/lib 2>/dev/null` \
- `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \
- ; do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i; pwd)`"
- break
- fi
- done
- fi
-
- # check in a few common install locations
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in `ls -d ${libdir} 2>/dev/null` \
- `ls -d ${exec_prefix}/lib 2>/dev/null` \
- `ls -d ${prefix}/lib 2>/dev/null` \
- `ls -d /usr/local/lib 2>/dev/null` \
- `ls -d /usr/contrib/lib 2>/dev/null` \
- `ls -d /usr/pkg/lib 2>/dev/null` \
- `ls -d /usr/lib 2>/dev/null` \
- `ls -d /usr/lib64 2>/dev/null` \
- `ls -d /usr/lib/tcl8.6 2>/dev/null` \
- `ls -d /usr/lib/tcl8.5 2>/dev/null` \
- `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \
- `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \
- `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \
- `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \
- ; do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i; pwd)`"
- break
- fi
- done
- fi
-
- # check in a few other private locations
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- ${srcdir}/../tcl \
- `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do
- if test "${TEA_PLATFORM}" = "windows" \
- -a -f "$i/win/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/win; pwd)`"
- break
- fi
- if test -f "$i/unix/tclConfig.sh" ; then
- ac_cv_c_tclconfig="`(cd $i/unix; pwd)`"
- break
- fi
- done
- fi
- ])
-
- if test x"${ac_cv_c_tclconfig}" = x ; then
- TCL_BIN_DIR="# no Tcl configs found"
- AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh])
- else
- no_tcl=
- TCL_BIN_DIR="${ac_cv_c_tclconfig}"
- AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh])
- fi
- fi
-])
-
-#------------------------------------------------------------------------
-# TEA_PATH_TKCONFIG --
-#
-# Locate the tkConfig.sh file
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Adds the following arguments to configure:
-# --with-tk=...
-#
-# Defines the following vars:
-# TK_BIN_DIR Full path to the directory containing
-# the tkConfig.sh file
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_PATH_TKCONFIG], [
- #
- # Ok, lets find the tk configuration
- # First, look for one uninstalled.
- # the alternative search directory is invoked by --with-tk
- #
-
- if test x"${no_tk}" = x ; then
- # we reset no_tk in case something fails here
- no_tk=true
- AC_ARG_WITH(tk,
- AS_HELP_STRING([--with-tk],
- [directory containing tk configuration (tkConfig.sh)]),
- [with_tkconfig="${withval}"])
- AC_MSG_CHECKING([for Tk configuration])
- AC_CACHE_VAL(ac_cv_c_tkconfig,[
-
- # First check to see if --with-tkconfig was specified.
- if test x"${with_tkconfig}" != x ; then
- case "${with_tkconfig}" in
- */tkConfig.sh )
- if test -f "${with_tkconfig}"; then
- AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself])
- with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`"
- fi ;;
- esac
- if test -f "${with_tkconfig}/tkConfig.sh" ; then
- ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`"
- else
- AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh])
- fi
- fi
-
- # then check for a private Tk library
- if test x"${ac_cv_c_tkconfig}" = x ; then
- for i in \
- ../tk \
- `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \
- ../../tk \
- `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \
- ../../../tk \
- `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do
- if test "${TEA_PLATFORM}" = "windows" \
- -a -f "$i/win/tkConfig.sh" ; then
- ac_cv_c_tkconfig="`(cd $i/win; pwd)`"
- break
- fi
- if test -f "$i/unix/tkConfig.sh" ; then
- ac_cv_c_tkconfig="`(cd $i/unix; pwd)`"
- break
- fi
- done
- fi
-
- # on Darwin, check in Framework installation locations
- if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then
- for i in `ls -d ~/Library/Frameworks 2>/dev/null` \
- `ls -d /Library/Frameworks 2>/dev/null` \
- `ls -d /Network/Library/Frameworks 2>/dev/null` \
- ; do
- if test -f "$i/Tk.framework/tkConfig.sh" ; then
- ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`"
- break
- fi
- done
- fi
-
- # check in a few common install locations
- if test x"${ac_cv_c_tkconfig}" = x ; then
- for i in `ls -d ${libdir} 2>/dev/null` \
- `ls -d ${exec_prefix}/lib 2>/dev/null` \
- `ls -d ${prefix}/lib 2>/dev/null` \
- `ls -d /usr/local/lib 2>/dev/null` \
- `ls -d /usr/contrib/lib 2>/dev/null` \
- `ls -d /usr/pkg/lib 2>/dev/null` \
- `ls -d /usr/lib/tk8.6 2>/dev/null` \
- `ls -d /usr/lib/tk8.5 2>/dev/null` \
- `ls -d /usr/lib 2>/dev/null` \
- `ls -d /usr/lib64 2>/dev/null` \
- `ls -d /usr/local/lib/tk8.6 2>/dev/null` \
- `ls -d /usr/local/lib/tk8.5 2>/dev/null` \
- `ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \
- `ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \
- ; do
- if test -f "$i/tkConfig.sh" ; then
- ac_cv_c_tkconfig="`(cd $i; pwd)`"
- break
- fi
- done
- fi
-
- # TEA specific: on Windows, check in common installation locations
- if test "${TEA_PLATFORM}" = "windows" \
- -a x"${ac_cv_c_tkconfig}" = x ; then
- for i in `ls -d C:/Tcl/lib 2>/dev/null` \
- `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \
- ; do
- if test -f "$i/tkConfig.sh" ; then
- ac_cv_c_tkconfig="`(cd $i; pwd)`"
- break
- fi
- done
- fi
-
- # check in a few other private locations
- if test x"${ac_cv_c_tkconfig}" = x ; then
- for i in \
- ${srcdir}/../tk \
- `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do
- if test "${TEA_PLATFORM}" = "windows" \
- -a -f "$i/win/tkConfig.sh" ; then
- ac_cv_c_tkconfig="`(cd $i/win; pwd)`"
- break
- fi
- if test -f "$i/unix/tkConfig.sh" ; then
- ac_cv_c_tkconfig="`(cd $i/unix; pwd)`"
- break
- fi
- done
- fi
- ])
-
- if test x"${ac_cv_c_tkconfig}" = x ; then
- TK_BIN_DIR="# no Tk configs found"
- AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh])
- else
- no_tk=
- TK_BIN_DIR="${ac_cv_c_tkconfig}"
- AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh])
- fi
- fi
-])
-
-#------------------------------------------------------------------------
-# TEA_LOAD_TCLCONFIG --
-#
-# Load the tclConfig.sh file
-#
-# Arguments:
-#
-# Requires the following vars to be set:
-# TCL_BIN_DIR
-#
-# Results:
-#
-# Substitutes the following vars:
-# TCL_BIN_DIR
-# TCL_SRC_DIR
-# TCL_LIB_FILE
-# TCL_ZIP_FILE
-# TCL_ZIPFS_SUPPORT
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_LOAD_TCLCONFIG], [
- AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh])
-
- if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then
- AC_MSG_RESULT([loading])
- . "${TCL_BIN_DIR}/tclConfig.sh"
- else
- AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh])
- fi
-
- # If the TCL_BIN_DIR is the build directory (not the install directory),
- # then set the common variable name to the value of the build variables.
- # For example, the variable TCL_LIB_SPEC will be set to the value
- # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
- # instead of TCL_BUILD_LIB_SPEC since it will work with both an
- # installed and uninstalled version of Tcl.
- if test -f "${TCL_BIN_DIR}/Makefile" ; then
- TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}"
- TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}"
- TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}"
- elif test "`uname -s`" = "Darwin"; then
- # If Tcl was built as a framework, attempt to use the libraries
- # from the framework at the given location so that linking works
- # against Tcl.framework installed in an arbitrary location.
- case ${TCL_DEFS} in
- *TCL_FRAMEWORK*)
- if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then
- for i in "`cd "${TCL_BIN_DIR}"; pwd`" \
- "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do
- if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then
- TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}"
- break
- fi
- done
- fi
- if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then
- TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}"
- TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"
- fi
- ;;
- esac
- fi
-
- AC_SUBST(TCL_VERSION)
- AC_SUBST(TCL_PATCH_LEVEL)
- AC_SUBST(TCL_BIN_DIR)
- AC_SUBST(TCL_SRC_DIR)
-
- AC_SUBST(TCL_LIB_FILE)
- AC_SUBST(TCL_LIB_FLAG)
- AC_SUBST(TCL_LIB_SPEC)
-
- AC_SUBST(TCL_STUB_LIB_FILE)
- AC_SUBST(TCL_STUB_LIB_FLAG)
- AC_SUBST(TCL_STUB_LIB_SPEC)
-
- AC_MSG_CHECKING([platform])
- hold_cc=$CC; CC="$TCL_CC"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
- #ifdef _WIN32
- #error win32
- #endif
- ]])],[
- # first test we've already retrieved platform (cross-compile), fallback to unix otherwise:
- TEA_PLATFORM="${TEA_PLATFORM-unix}"
- CYGPATH=echo
- ],[
- TEA_PLATFORM="windows"
- AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo)
- ])
- CC=$hold_cc
- AC_MSG_RESULT($TEA_PLATFORM)
-
- # The BUILD_$pkg is to define the correct extern storage class
- # handling when making this package
- AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [],
- [Building extension source?])
- # Do this here as we have fully defined TEA_PLATFORM now
- if test "${TEA_PLATFORM}" = "windows" ; then
- EXEEXT=".exe"
- CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp"
- fi
-
- # TEA specific:
- AC_SUBST(CLEANFILES)
- AC_SUBST(TCL_LIBS)
- AC_SUBST(TCL_DEFS)
- AC_SUBST(TCL_EXTRA_CFLAGS)
- AC_SUBST(TCL_LD_FLAGS)
- AC_SUBST(TCL_SHLIB_LD_LIBS)
-])
-
-#------------------------------------------------------------------------
-# TEA_LOAD_TKCONFIG --
-#
-# Load the tkConfig.sh file
-#
-# Arguments:
-#
-# Requires the following vars to be set:
-# TK_BIN_DIR
-#
-# Results:
-#
-# Sets the following vars that should be in tkConfig.sh:
-# TK_BIN_DIR
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_LOAD_TKCONFIG], [
- AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh])
-
- if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then
- AC_MSG_RESULT([loading])
- . "${TK_BIN_DIR}/tkConfig.sh"
- else
- AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh])
- fi
-
- # If the TK_BIN_DIR is the build directory (not the install directory),
- # then set the common variable name to the value of the build variables.
- # For example, the variable TK_LIB_SPEC will be set to the value
- # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC
- # instead of TK_BUILD_LIB_SPEC since it will work with both an
- # installed and uninstalled version of Tcl.
- if test -f "${TK_BIN_DIR}/Makefile" ; then
- TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}"
- TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}"
- TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}"
- elif test "`uname -s`" = "Darwin"; then
- # If Tk was built as a framework, attempt to use the libraries
- # from the framework at the given location so that linking works
- # against Tk.framework installed in an arbitrary location.
- case ${TK_DEFS} in
- *TK_FRAMEWORK*)
- if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then
- for i in "`cd "${TK_BIN_DIR}"; pwd`" \
- "`cd "${TK_BIN_DIR}"/../..; pwd`"; do
- if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then
- TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}"
- break
- fi
- done
- fi
- if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then
- TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}"
- TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"
- fi
- ;;
- esac
- fi
-
- # TEA specific: Ensure windowingsystem is defined
- if test "${TEA_PLATFORM}" = "unix" ; then
- case ${TK_DEFS} in
- *MAC_OSX_TK*)
- AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?])
- TEA_WINDOWINGSYSTEM="aqua"
- ;;
- *)
- TEA_WINDOWINGSYSTEM="x11"
- ;;
- esac
- elif test "${TEA_PLATFORM}" = "windows" ; then
- TEA_WINDOWINGSYSTEM="win32"
- fi
-
- AC_SUBST(TK_VERSION)
- AC_SUBST(TK_BIN_DIR)
- AC_SUBST(TK_SRC_DIR)
-
- AC_SUBST(TK_LIB_FILE)
- AC_SUBST(TK_LIB_FLAG)
- AC_SUBST(TK_LIB_SPEC)
-
- AC_SUBST(TK_STUB_LIB_FILE)
- AC_SUBST(TK_STUB_LIB_FLAG)
- AC_SUBST(TK_STUB_LIB_SPEC)
-
- # TEA specific:
- AC_SUBST(TK_LIBS)
- AC_SUBST(TK_XINCLUDES)
-])
-
-#------------------------------------------------------------------------
-# TEA_PROG_TCLSH
-# Determine the fully qualified path name of the tclsh executable
-# in the Tcl build directory or the tclsh installed in a bin
-# directory. This macro will correctly determine the name
-# of the tclsh executable even if tclsh has not yet been
-# built in the build directory. The tclsh found is always
-# associated with a tclConfig.sh file. This tclsh should be used
-# only for running extension test cases. It should never be
-# or generation of files (like pkgIndex.tcl) at build time.
-#
-# Arguments:
-# none
-#
-# Results:
-# Substitutes the following vars:
-# TCLSH_PROG
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_PROG_TCLSH], [
- AC_MSG_CHECKING([for tclsh])
- if test -f "${TCL_BIN_DIR}/Makefile" ; then
- # tclConfig.sh is in Tcl build directory
- if test "${TEA_PLATFORM}" = "windows"; then
- if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
- elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}"
- elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}"
- elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}"
- fi
- else
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh"
- fi
- else
- # tclConfig.sh is in install location
- if test "${TEA_PLATFORM}" = "windows"; then
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
- else
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}"
- fi
- list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \
- `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \
- `ls -d ${TCL_PREFIX}/bin 2>/dev/null`"
- for i in $list ; do
- if test -f "$i/${TCLSH_PROG}" ; then
- REAL_TCL_BIN_DIR="`cd "$i"; pwd`/"
- break
- fi
- done
- TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}"
- fi
- AC_MSG_RESULT([${TCLSH_PROG}])
- AC_SUBST(TCLSH_PROG)
-])
-
-#------------------------------------------------------------------------
-# TEA_PROG_WISH
-# Determine the fully qualified path name of the wish executable
-# in the Tk build directory or the wish installed in a bin
-# directory. This macro will correctly determine the name
-# of the wish executable even if wish has not yet been
-# built in the build directory. The wish found is always
-# associated with a tkConfig.sh file. This wish should be used
-# only for running extension test cases. It should never be
-# or generation of files (like pkgIndex.tcl) at build time.
-#
-# Arguments:
-# none
-#
-# Results:
-# Substitutes the following vars:
-# WISH_PROG
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_PROG_WISH], [
- AC_MSG_CHECKING([for wish])
- if test -f "${TK_BIN_DIR}/Makefile" ; then
- # tkConfig.sh is in Tk build directory
- if test "${TEA_PLATFORM}" = "windows"; then
- if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" ; then
- WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}"
- elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}s${EXEEXT}" ; then
- WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}$s{EXEEXT}"
- elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" ; then
- WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}"
- elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" ; then
- WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}"
- fi
- else
- WISH_PROG="${TK_BIN_DIR}/wish"
- fi
- else
- # tkConfig.sh is in install location
- if test "${TEA_PLATFORM}" = "windows"; then
- WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}"
- else
- WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}"
- fi
- list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \
- `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \
- `ls -d ${TK_PREFIX}/bin 2>/dev/null`"
- for i in $list ; do
- if test -f "$i/${WISH_PROG}" ; then
- REAL_TK_BIN_DIR="`cd "$i"; pwd`/"
- break
- fi
- done
- WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}"
- fi
- AC_MSG_RESULT([${WISH_PROG}])
- AC_SUBST(WISH_PROG)
-])
-
-#------------------------------------------------------------------------
-# TEA_ENABLE_SHARED --
-#
-# Allows the building of shared libraries
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Adds the following arguments to configure:
-# --enable-shared=yes|no
-# --enable-stubs=yes|no
-#
-# Defines the following vars:
-# STATIC_BUILD Used for building import/export libraries
-# on Windows.
-#
-# Sets the following vars:
-# SHARED_BUILD Value of 1 or 0
-# STUBS_BUILD Value if 1 or 0
-# USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs
-# USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs
-# USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs
-# AND TEA_WINDOWING_SYSTEM != ""
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_ENABLE_SHARED], [
- AC_MSG_CHECKING([how to build libraries])
- AC_ARG_ENABLE(shared,
- AS_HELP_STRING([--enable-shared],
- [build and link with shared libraries (default: on)]),
- [shared_ok=$enableval], [shared_ok=yes])
-
- if test "${enable_shared+set}" = set; then
- enableval="$enable_shared"
- shared_ok=$enableval
- else
- shared_ok=yes
- fi
-
- AC_ARG_ENABLE(stubs,
- AS_HELP_STRING([--enable-stubs],
- [build and link with stub libraries. Always true for shared builds (default: on)]),
- [stubs_ok=$enableval], [stubs_ok=yes])
-
- if test "${enable_stubs+set}" = set; then
- enableval="$enable_stubs"
- stubs_ok=$enableval
- else
- stubs_ok=yes
- fi
-
- # Stubs are always enabled for shared builds
- if test "$shared_ok" = "yes" ; then
- AC_MSG_RESULT([shared])
- SHARED_BUILD=1
- STUBS_BUILD=1
- else
- AC_MSG_RESULT([static])
- SHARED_BUILD=0
- AC_DEFINE(STATIC_BUILD, 1, [This a static build])
- if test "$stubs_ok" = "yes" ; then
- STUBS_BUILD=1
- else
- STUBS_BUILD=0
- fi
- fi
- if test "${STUBS_BUILD}" = "1" ; then
- AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs])
- AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs])
- if test "${TEA_WINDOWINGSYSTEM}" != ""; then
- AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs])
- fi
- fi
-
- AC_SUBST(SHARED_BUILD)
- AC_SUBST(STUBS_BUILD)
-])
-
-#------------------------------------------------------------------------
-# TEA_ENABLE_THREADS --
-#
-# Specify if thread support should be enabled. If "yes" is specified
-# as an arg (optional), threads are enabled by default, "no" means
-# threads are disabled. "yes" is the default.
-#
-# TCL_THREADS is checked so that if you are compiling an extension
-# against a threaded core, your extension must be compiled threaded
-# as well.
-#
-# Note that it is legal to have a thread enabled extension run in a
-# threaded or non-threaded Tcl core, but a non-threaded extension may
-# only run in a non-threaded Tcl core.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Adds the following arguments to configure:
-# --enable-threads
-#
-# Sets the following vars:
-# THREADS_LIBS Thread library(s)
-#
-# Defines the following vars:
-# TCL_THREADS
-# _REENTRANT
-# _THREAD_SAFE
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_ENABLE_THREADS], [
- AC_ARG_ENABLE(threads,
- AS_HELP_STRING([--enable-threads],
- [build with threads (default: on)]),
- [tcl_ok=$enableval], [tcl_ok=yes])
-
- if test "${enable_threads+set}" = set; then
- enableval="$enable_threads"
- tcl_ok=$enableval
- else
- tcl_ok=yes
- fi
-
- if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then
- TCL_THREADS=1
-
- if test "${TEA_PLATFORM}" != "windows" ; then
- # We are always OK on Windows, so check what this platform wants:
-
- # USE_THREAD_ALLOC tells us to try the special thread-based
- # allocator that significantly reduces lock contention
- AC_DEFINE(USE_THREAD_ALLOC, 1,
- [Do we want to use the threaded memory allocator?])
- AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?])
- if test "`uname -s`" = "SunOS" ; then
- AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1,
- [Do we really want to follow the standard? Yes we do!])
- fi
- AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?])
- AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no)
- if test "$tcl_ok" = "no"; then
- # Check a little harder for __pthread_mutex_init in the same
- # library, as some systems hide it there until pthread.h is
- # defined. We could alternatively do an AC_TRY_COMPILE with
- # pthread.h, but that will work with libpthread really doesn't
- # exist, like AIX 4.2. [Bug: 4359]
- AC_CHECK_LIB(pthread, __pthread_mutex_init,
- tcl_ok=yes, tcl_ok=no)
- fi
-
- if test "$tcl_ok" = "yes"; then
- # The space is needed
- THREADS_LIBS=" -lpthread"
- else
- AC_CHECK_LIB(pthreads, pthread_mutex_init,
- tcl_ok=yes, tcl_ok=no)
- if test "$tcl_ok" = "yes"; then
- # The space is needed
- THREADS_LIBS=" -lpthreads"
- else
- AC_CHECK_LIB(c, pthread_mutex_init,
- tcl_ok=yes, tcl_ok=no)
- if test "$tcl_ok" = "no"; then
- AC_CHECK_LIB(c_r, pthread_mutex_init,
- tcl_ok=yes, tcl_ok=no)
- if test "$tcl_ok" = "yes"; then
- # The space is needed
- THREADS_LIBS=" -pthread"
- else
- TCL_THREADS=0
- AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled])
- fi
- fi
- fi
- fi
- fi
- else
- TCL_THREADS=0
- fi
- # Do checking message here to not mess up interleaved configure output
- AC_MSG_CHECKING([for building with threads])
- if test "${TCL_THREADS}" = 1; then
- AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?])
- AC_MSG_RESULT([yes (default)])
- else
- AC_MSG_RESULT([no])
- fi
- # TCL_THREADS sanity checking. See if our request for building with
- # threads is the same as the way Tcl was built. If not, warn the user.
- case ${TCL_DEFS} in
- *THREADS=1*)
- if test "${TCL_THREADS}" = "0"; then
- AC_MSG_WARN([
- Building ${PACKAGE_NAME} without threads enabled, but building against Tcl
- that IS thread-enabled. It is recommended to use --enable-threads.])
- fi
- ;;
- esac
- AC_SUBST(TCL_THREADS)
-])
-
-#------------------------------------------------------------------------
-# TEA_ENABLE_SYMBOLS --
-#
-# Specify if debugging symbols should be used.
-# Memory (TCL_MEM_DEBUG) debugging can also be enabled.
-#
-# Arguments:
-# none
-#
-# TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives
-# the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted.
-# Requires the following vars to be set in the Makefile:
-# CFLAGS_DEFAULT
-# LDFLAGS_DEFAULT
-#
-# Results:
-#
-# Adds the following arguments to configure:
-# --enable-symbols
-#
-# Defines the following vars:
-# CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true
-# Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false
-# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true
-# Sets to $(LDFLAGS_OPTIMIZE) if false
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_ENABLE_SYMBOLS], [
- dnl TEA specific: Make sure we are initialized
- AC_REQUIRE([TEA_CONFIG_CFLAGS])
- AC_MSG_CHECKING([for build with symbols])
- AC_ARG_ENABLE(symbols,
- AS_HELP_STRING([--enable-symbols],
- [build with debugging symbols (default: off)]),
- [tcl_ok=$enableval], [tcl_ok=no])
- if test "$tcl_ok" = "no"; then
- CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG"
- LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}"
- AC_MSG_RESULT([no])
- AC_DEFINE(TCL_CFG_OPTIMIZED, 1, [Is this an optimized build?])
- else
- CFLAGS_DEFAULT="${CFLAGS_DEBUG}"
- LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}"
- if test "$tcl_ok" = "yes"; then
- AC_MSG_RESULT([yes (standard debugging)])
- fi
- fi
- AC_SUBST(CFLAGS_DEFAULT)
- AC_SUBST(LDFLAGS_DEFAULT)
-
- if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then
- AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?])
- fi
-
- if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then
- if test "$tcl_ok" = "all"; then
- AC_MSG_RESULT([enabled symbols mem debugging])
- else
- AC_MSG_RESULT([enabled $tcl_ok debugging])
- fi
- fi
-])
-
-#------------------------------------------------------------------------
-# TEA_ENABLE_LANGINFO --
-#
-# Allows use of modern nl_langinfo check for better l10n.
-# This is only relevant for Unix.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Adds the following arguments to configure:
-# --enable-langinfo=yes|no (default is yes)
-#
-# Defines the following vars:
-# HAVE_LANGINFO Triggers use of nl_langinfo if defined.
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_ENABLE_LANGINFO], [
- AC_ARG_ENABLE(langinfo,
- AS_HELP_STRING([--enable-langinfo],
- [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]),
- [langinfo_ok=$enableval], [langinfo_ok=yes])
-
- HAVE_LANGINFO=0
- if test "$langinfo_ok" = "yes"; then
- AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no])
- fi
- AC_MSG_CHECKING([whether to use nl_langinfo])
- if test "$langinfo_ok" = "yes"; then
- AC_CACHE_VAL(tcl_cv_langinfo_h, [
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <langinfo.h>]], [[nl_langinfo(CODESET);]])],
- [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])])
- AC_MSG_RESULT([$tcl_cv_langinfo_h])
- if test $tcl_cv_langinfo_h = yes; then
- AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?])
- fi
- else
- AC_MSG_RESULT([$langinfo_ok])
- fi
-])
-
-#--------------------------------------------------------------------
-# TEA_CONFIG_SYSTEM
-#
-# Determine what the system is (some things cannot be easily checked
-# on a feature-driven basis, alas). This can usually be done via the
-# "uname" command.
-#
-# Arguments:
-# none
-#
-# Results:
-# Defines the following var:
-#
-# system - System/platform/version identification code.
-#
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_CONFIG_SYSTEM], [
- AC_CACHE_CHECK([system version], tcl_cv_sys_version, [
- # TEA specific:
- if test "${TEA_PLATFORM}" = "windows" ; then
- tcl_cv_sys_version=windows
- else
- tcl_cv_sys_version=`uname -s`-`uname -r`
- if test "$?" -ne 0 ; then
- AC_MSG_WARN([can't find uname command])
- tcl_cv_sys_version=unknown
- else
- if test "`uname -s`" = "AIX" ; then
- tcl_cv_sys_version=AIX-`uname -v`.`uname -r`
- fi
- if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then
- tcl_cv_sys_version=NetBSD-Debian
- fi
- fi
- fi
- ])
- system=$tcl_cv_sys_version
-])
-
-#--------------------------------------------------------------------
-# TEA_CONFIG_CFLAGS
-#
-# Try to determine the proper flags to pass to the compiler
-# for building shared libraries and other such nonsense.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Defines and substitutes the following vars:
-#
-# DL_OBJS, DL_LIBS - removed for TEA, only needed by core.
-# LDFLAGS - Flags to pass to the compiler when linking object
-# files into an executable application binary such
-# as tclsh.
-# LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib",
-# that tell the run-time dynamic linker where to look
-# for shared libraries such as libtcl.so. Depends on
-# the variable LIB_RUNTIME_DIR in the Makefile. Could
-# be the same as CC_SEARCH_FLAGS if ${CC} is used to link.
-# CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib",
-# that tell the run-time dynamic linker where to look
-# for shared libraries such as libtcl.so. Depends on
-# the variable LIB_RUNTIME_DIR in the Makefile.
-# SHLIB_CFLAGS - Flags to pass to cc when compiling the components
-# of a shared library (may request position-independent
-# code, among other things).
-# SHLIB_LD - Base command to use for combining object files
-# into a shared library.
-# SHLIB_LD_LIBS - Dependent libraries for the linker to scan when
-# creating shared libraries. This symbol typically
-# goes at the end of the "ld" commands that build
-# shared libraries. The value of the symbol defaults to
-# "${LIBS}" if all of the dependent libraries should
-# be specified when creating a shared library. If
-# dependent libraries should not be specified (as on
-# SunOS 4.x, where they cause the link to fail, or in
-# general if Tcl and Tk aren't themselves shared
-# libraries), then this symbol has an empty string
-# as its value.
-# SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable
-# extensions. An empty string means we don't know how
-# to use shared libraries on this platform.
-# LIB_SUFFIX - Specifies everything that comes after the "libfoo"
-# in a static or shared library name, using the $PACKAGE_VERSION variable
-# to put the version in the right place. This is used
-# by platforms that need non-standard library names.
-# Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs
-# to have a version after the .so, and ${PACKAGE_VERSION}.a
-# on AIX, since a shared library needs to have
-# a .a extension whereas shared objects for loadable
-# extensions have a .so extension. Defaults to
-# ${PACKAGE_VERSION}${SHLIB_SUFFIX}.
-# CFLAGS_DEBUG -
-# Flags used when running the compiler in debug mode
-# CFLAGS_OPTIMIZE -
-# Flags used when running the compiler in optimize mode
-# CFLAGS - Additional CFLAGS added as necessary (usually 64-bit)
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_CONFIG_CFLAGS], [
- dnl TEA specific: Make sure we are initialized
- AC_REQUIRE([TEA_INIT])
-
- # Step 0.a: Enable 64 bit support?
-
- AC_MSG_CHECKING([if 64bit support is requested])
- AC_ARG_ENABLE(64bit,
- AS_HELP_STRING([--enable-64bit],
- [enable 64bit support (default: off)]),
- [do64bit=$enableval], [do64bit=no])
- AC_MSG_RESULT([$do64bit])
-
- # Step 0.b: Enable Solaris 64 bit VIS support?
-
- AC_MSG_CHECKING([if 64bit Sparc VIS support is requested])
- AC_ARG_ENABLE(64bit-vis,
- AS_HELP_STRING([--enable-64bit-vis],
- [enable 64bit Sparc VIS support (default: off)]),
- [do64bitVIS=$enableval], [do64bitVIS=no])
- AC_MSG_RESULT([$do64bitVIS])
- # Force 64bit on with VIS
- AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes])
-
- # Step 0.c: Check if visibility support is available. Do this here so
- # that platform specific alternatives can be used below if this fails.
-
- AC_CACHE_CHECK([if compiler supports visibility "hidden"],
- tcl_cv_cc_visibility_hidden, [
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[
- extern __attribute__((__visibility__("hidden"))) void f(void);
- void f(void) {}]], [[f();]])],[tcl_cv_cc_visibility_hidden=yes],
- [tcl_cv_cc_visibility_hidden=no])
- CFLAGS=$hold_cflags])
- AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [
- AC_DEFINE(MODULE_SCOPE,
- [extern __attribute__((__visibility__("hidden")))],
- [Compiler support for module scope symbols])
- AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols])
- ])
-
- # Step 0.d: Disable -rpath support?
-
- AC_MSG_CHECKING([if rpath support is requested])
- AC_ARG_ENABLE(rpath,
- AS_HELP_STRING([--disable-rpath],
- [disable rpath support (default: on)]),
- [doRpath=$enableval], [doRpath=yes])
- AC_MSG_RESULT([$doRpath])
-
- # Set the variable "system" to hold the name and version number
- # for the system.
-
- TEA_CONFIG_SYSTEM
-
- # Require ranlib early so we can override it in special cases below.
-
- AC_REQUIRE([AC_PROG_RANLIB])
-
- # Set configuration options based on system name and version.
- # This is similar to Tcl's unix/tcl.m4 except that we've added a
- # "windows" case and removed some core-only vars.
-
- do64bit_ok=no
- # default to '{$LIBS}' and set to "" on per-platform necessary basis
- SHLIB_LD_LIBS='${LIBS}'
- # When ld needs options to work in 64-bit mode, put them in
- # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load]
- # is disabled by the user. [Bug 1016796]
- LDFLAGS_ARCH=""
- UNSHARED_LIB_SUFFIX=""
- # TEA specific: use PACKAGE_VERSION instead of VERSION
- TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`'
- ECHO_VERSION='`echo ${PACKAGE_VERSION}`'
- TCL_LIB_VERSIONS_OK=ok
- CFLAGS_DEBUG=-g
- AS_IF([test "$GCC" = yes], [
- CFLAGS_OPTIMIZE=-O2
- CFLAGS_WARNING="-Wall"
- ], [
- CFLAGS_OPTIMIZE=-O
- CFLAGS_WARNING=""
- ])
- AC_CHECK_TOOL(AR, ar)
- STLIB_LD='${AR} cr'
- LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH"
- AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"])
- case $system in
- # TEA specific:
- windows)
- MACHINE="X86"
- if test "$do64bit" != "no" ; then
- case "$do64bit" in
- amd64|x64|yes)
- MACHINE="AMD64" ; # default to AMD64 64-bit build
- ;;
- arm64|aarch64)
- MACHINE="ARM64"
- ;;
- ia64)
- MACHINE="IA64"
- ;;
- esac
- fi
-
- if test "$GCC" != "yes" ; then
- if test "${SHARED_BUILD}" = "0" ; then
- runtime=-MT
- else
- runtime=-MD
- fi
- case "x`echo \${VisualStudioVersion}`" in
- x1[[4-9]]*)
- lflags="${lflags} -nodefaultlib:libucrt.lib"
- TEA_ADD_LIBS([ucrt.lib])
- ;;
- *)
- ;;
- esac
-
- if test "$do64bit" != "no" ; then
- CC="cl.exe"
- RC="rc.exe"
- lflags="${lflags} -nologo -MACHINE:${MACHINE} "
- LINKBIN="link.exe"
- CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d"
- CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
- # Avoid 'unresolved external symbol __security_cookie'
- # errors, c.f. http://support.microsoft.com/?id=894573
- TEA_ADD_LIBS([bufferoverflowU.lib])
- else
- RC="rc"
- lflags="${lflags} -nologo"
- LINKBIN="link"
- CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d"
- CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
- fi
- fi
-
- if test "$GCC" = "yes"; then
- # mingw gcc mode
- AC_CHECK_TOOL(RC, windres)
- CFLAGS_DEBUG="-g"
- CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
- SHLIB_LD='${CC} -shared'
- UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
- LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}"
- LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}"
-
- AC_CACHE_CHECK(for cross-compile version of gcc,
- ac_cv_cross,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- #ifdef _WIN32
- #error cross-compiler
- #endif
- ]], [[]])],
- [ac_cv_cross=yes],
- [ac_cv_cross=no])
- )
- if test "$ac_cv_cross" = "yes"; then
- case "$do64bit" in
- amd64|x64|yes)
- CC="x86_64-w64-mingw32-${CC}"
- LD="x86_64-w64-mingw32-ld"
- AR="x86_64-w64-mingw32-ar"
- RANLIB="x86_64-w64-mingw32-ranlib"
- RC="x86_64-w64-mingw32-windres"
- ;;
- arm64|aarch64)
- CC="aarch64-w64-mingw32-clang"
- LD="aarch64-w64-mingw32-ld"
- AR="aarch64-w64-mingw32-ar"
- RANLIB="aarch64-w64-mingw32-ranlib"
- RC="aarch64-w64-mingw32-windres"
- ;;
- *)
- CC="i686-w64-mingw32-${CC}"
- LD="i686-w64-mingw32-ld"
- AR="i686-w64-mingw32-ar"
- RANLIB="i686-w64-mingw32-ranlib"
- RC="i686-w64-mingw32-windres"
- ;;
- esac
- fi
-
- else
- SHLIB_LD="${LINKBIN} -dll ${lflags}"
- # link -lib only works when -lib is the first arg
- STLIB_LD="${LINKBIN} -lib ${lflags}"
- UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib'
- PATHTYPE=-w
- # For information on what debugtype is most useful, see:
- # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp
- # and also
- # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx
- # This essentially turns it all on.
- LDFLAGS_DEBUG="-debug -debugtype:cv"
- LDFLAGS_OPTIMIZE="-release"
- LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
- LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
- fi
-
- SHLIB_SUFFIX=".dll"
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll'
-
- TCL_LIB_VERSIONS_OK=nodots
- ;;
- AIX-*)
- AS_IF([test "$GCC" != "yes"], [
- # AIX requires the _r compiler when gcc isn't being used
- case "${CC}" in
- *_r|*_r\ *)
- # ok ...
- ;;
- *)
- # Make sure only first arg gets _r
- CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'`
- ;;
- esac
- AC_MSG_RESULT([Using $CC for compiling with threads])
- ])
- LIBS="$LIBS -lc"
- SHLIB_CFLAGS=""
- SHLIB_SUFFIX=".so"
-
- LD_LIBRARY_PATH_VAR="LIBPATH"
-
- # Check to enable 64-bit flags for compiler/linker
- AS_IF([test "$do64bit" = yes], [
- AS_IF([test "$GCC" = yes], [
- AC_MSG_WARN([64bit mode not supported with GCC on $system])
- ], [
- do64bit_ok=yes
- CFLAGS="$CFLAGS -q64"
- LDFLAGS_ARCH="-q64"
- RANLIB="${RANLIB} -X64"
- AR="${AR} -X64"
- SHLIB_LD_FLAGS="-b64"
- ])
- ])
-
- AS_IF([test "`uname -m`" = ia64], [
- # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC
- SHLIB_LD="/usr/ccs/bin/ld -G -z text"
- AS_IF([test "$GCC" = yes], [
- CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
- ], [
- CC_SEARCH_FLAGS='"-R${LIB_RUNTIME_DIR}"'
- ])
- LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
- ], [
- AS_IF([test "$GCC" = yes], [
- SHLIB_LD='${CC} -shared -Wl,-bexpall'
- ], [
- SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry"
- LDFLAGS="$LDFLAGS -brtl"
- ])
- SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}"
- CC_SEARCH_FLAGS='"-L${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- ])
- ;;
- BeOS*)
- SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} -nostart'
- SHLIB_SUFFIX=".so"
-
- #-----------------------------------------------------------
- # Check for inet_ntoa in -lbind, for BeOS (which also needs
- # -lsocket, even if the network functions are in -lnet which
- # is always linked to, for compatibility.
- #-----------------------------------------------------------
- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"])
- ;;
- BSD/OS-2.1*|BSD/OS-3*)
- SHLIB_CFLAGS=""
- SHLIB_LD="shlicc -r"
- SHLIB_SUFFIX=".so"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- BSD/OS-4.*)
- SHLIB_CFLAGS="-export-dynamic -fPIC"
- SHLIB_LD='${CC} -shared'
- SHLIB_SUFFIX=".so"
- LDFLAGS="$LDFLAGS -export-dynamic"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- CYGWIN_*)
- SHLIB_CFLAGS=""
- SHLIB_LD='${CC} -shared'
- SHLIB_SUFFIX=".dll"
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a"
- EXEEXT=".exe"
- do64bit_ok=yes
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- dgux*)
- SHLIB_CFLAGS="-K PIC"
- SHLIB_LD='${CC} -G'
- SHLIB_LD_LIBS=""
- SHLIB_SUFFIX=".so"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- Haiku*)
- LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
- SHLIB_CFLAGS="-fPIC"
- SHLIB_SUFFIX=".so"
- SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
- AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"])
- ;;
- HP-UX-*.11.*)
- # Use updated header definitions where possible
- AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?])
- # TEA specific: Needed by Tcl, but not most extensions
- #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?])
- #LIBS="$LIBS -lxnet" # Use the XOPEN network library
-
- AS_IF([test "`uname -m`" = ia64], [
- SHLIB_SUFFIX=".so"
- ], [
- SHLIB_SUFFIX=".sl"
- ])
- AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no)
- AS_IF([test "$tcl_ok" = yes], [
- SHLIB_CFLAGS="+z"
- SHLIB_LD="ld -b"
- LDFLAGS="$LDFLAGS -Wl,-E"
- CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."'
- LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."'
- LD_LIBRARY_PATH_VAR="SHLIB_PATH"
- ])
- AS_IF([test "$GCC" = yes], [
- SHLIB_LD='${CC} -shared'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- ], [
- CFLAGS="$CFLAGS -z"
- ])
-
- # Check to enable 64-bit flags for compiler/linker
- AS_IF([test "$do64bit" = "yes"], [
- AS_IF([test "$GCC" = yes], [
- case `${CC} -dumpmachine` in
- hppa64*)
- # 64-bit gcc in use. Fix flags for GNU ld.
- do64bit_ok=yes
- SHLIB_LD='${CC} -shared'
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- ;;
- *)
- AC_MSG_WARN([64bit mode not supported with GCC on $system])
- ;;
- esac
- ], [
- do64bit_ok=yes
- CFLAGS="$CFLAGS +DD64"
- LDFLAGS_ARCH="+DD64"
- ])
- ]) ;;
- HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*)
- SHLIB_SUFFIX=".sl"
- AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no)
- AS_IF([test "$tcl_ok" = yes], [
- SHLIB_CFLAGS="+z"
- SHLIB_LD="ld -b"
- SHLIB_LD_LIBS=""
- LDFLAGS="$LDFLAGS -Wl,-E"
- CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."'
- LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."'
- LD_LIBRARY_PATH_VAR="SHLIB_PATH"
- ]) ;;
- IRIX-5.*)
- SHLIB_CFLAGS=""
- SHLIB_LD="ld -shared -rdata_shared"
- SHLIB_SUFFIX=".so"
- AC_LIBOBJ(mkstemp)
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'])
- ;;
- IRIX-6.*)
- SHLIB_CFLAGS=""
- SHLIB_LD="ld -n32 -shared -rdata_shared"
- SHLIB_SUFFIX=".so"
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'])
- AS_IF([test "$GCC" = yes], [
- CFLAGS="$CFLAGS -mabi=n32"
- LDFLAGS="$LDFLAGS -mabi=n32"
- ], [
- case $system in
- IRIX-6.3)
- # Use to build 6.2 compatible binaries on 6.3.
- CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS"
- ;;
- *)
- CFLAGS="$CFLAGS -n32"
- ;;
- esac
- LDFLAGS="$LDFLAGS -n32"
- ])
- ;;
- IRIX64-6.*)
- SHLIB_CFLAGS=""
- SHLIB_LD="ld -n32 -shared -rdata_shared"
- SHLIB_SUFFIX=".so"
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'])
-
- # Check to enable 64-bit flags for compiler/linker
-
- AS_IF([test "$do64bit" = yes], [
- AS_IF([test "$GCC" = yes], [
- AC_MSG_WARN([64bit mode not supported by gcc])
- ], [
- do64bit_ok=yes
- SHLIB_LD="ld -64 -shared -rdata_shared"
- CFLAGS="$CFLAGS -64"
- LDFLAGS_ARCH="-64"
- ])
- ])
- ;;
- Linux*|GNU*|NetBSD-Debian|DragonFly-*|FreeBSD-*)
- SHLIB_CFLAGS="-fPIC"
- SHLIB_SUFFIX=".so"
-
- # TEA specific:
- CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
-
- # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS
- SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared'
- LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
-
- case $system in
- DragonFly-*|FreeBSD-*)
- AS_IF([test "${TCL_THREADS}" = "1"], [
- # The -pthread needs to go in the LDFLAGS, not LIBS
- LIBS=`echo $LIBS | sed s/-pthread//`
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- LDFLAGS="$LDFLAGS $PTHREAD_LIBS"])
- ;;
- esac
-
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"])
- AS_IF([test $do64bit = yes], [
- AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [
- hold_cflags=$CFLAGS
- CFLAGS="$CFLAGS -m64"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
- [tcl_cv_cc_m64=yes],[tcl_cv_cc_m64=no])
- CFLAGS=$hold_cflags])
- AS_IF([test $tcl_cv_cc_m64 = yes], [
- CFLAGS="$CFLAGS -m64"
- do64bit_ok=yes
- ])
- ])
-
- # The combo of gcc + glibc has a bug related to inlining of
- # functions like strtod(). The -fno-builtin flag should address
- # this problem but it does not work. The -fno-inline flag is kind
- # of overkill but it works. Disable inlining only when one of the
- # files in compat/*.c is being linked in.
-
- AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"])
- ;;
- Lynx*)
- SHLIB_CFLAGS="-fPIC"
- SHLIB_SUFFIX=".so"
- CFLAGS_OPTIMIZE=-02
- SHLIB_LD='${CC} -shared'
- LD_FLAGS="-Wl,--export-dynamic"
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
- ;;
- OpenBSD-*)
- arch=`arch -s`
- case "$arch" in
- alpha|sparc64)
- SHLIB_CFLAGS="-fPIC"
- ;;
- *)
- SHLIB_CFLAGS="-fpic"
- ;;
- esac
- SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
- SHLIB_SUFFIX=".so"
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
- LDFLAGS="$LDFLAGS -Wl,-export-dynamic"
- CFLAGS_OPTIMIZE="-O2"
- # On OpenBSD: Compile with -pthread
- # Don't link with -lpthread
- LIBS=`echo $LIBS | sed s/-lpthread//`
- CFLAGS="$CFLAGS -pthread"
- # OpenBSD doesn't do version numbers with dots.
- UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
- TCL_LIB_VERSIONS_OK=nodots
- ;;
- NetBSD-*)
- # NetBSD has ELF and can use 'cc -shared' to build shared libs
- SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
- SHLIB_SUFFIX=".so"
- LDFLAGS="$LDFLAGS -export-dynamic"
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- # The -pthread needs to go in the CFLAGS, not LIBS
- LIBS=`echo $LIBS | sed s/-pthread//`
- CFLAGS="$CFLAGS -pthread"
- LDFLAGS="$LDFLAGS -pthread"
- ;;
- Darwin-*)
- CFLAGS_OPTIMIZE="-Os"
- SHLIB_CFLAGS="-fno-common"
- # To avoid discrepancies between what headers configure sees during
- # preprocessing tests and compiling tests, move any -isysroot and
- # -mmacosx-version-min flags from CFLAGS to CPPFLAGS:
- CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \
- awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \
- if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`"
- CFLAGS="`echo " ${CFLAGS}" | \
- awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \
- if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`"
- AS_IF([test $do64bit = yes], [
- case `arch` in
- ppc)
- AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag],
- tcl_cv_cc_arch_ppc64, [
- hold_cflags=$CFLAGS
- CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
- [tcl_cv_cc_arch_ppc64=yes],[tcl_cv_cc_arch_ppc64=no])
- CFLAGS=$hold_cflags])
- AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [
- CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5"
- do64bit_ok=yes
- ]);;
- i386)
- AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag],
- tcl_cv_cc_arch_x86_64, [
- hold_cflags=$CFLAGS
- CFLAGS="$CFLAGS -arch x86_64"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
- [tcl_cv_cc_arch_x86_64=yes],[tcl_cv_cc_arch_x86_64=no])
- CFLAGS=$hold_cflags])
- AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [
- CFLAGS="$CFLAGS -arch x86_64"
- do64bit_ok=yes
- ]);;
- *)
- AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);;
- esac
- ], [
- # Check for combined 32-bit and 64-bit fat build
- AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \
- && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [
- fat_32_64=yes])
- ])
- # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS
- SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}'
- AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [
- hold_ldflags=$LDFLAGS
- LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])],
- [tcl_cv_ld_single_module=yes],[tcl_cv_ld_single_module=no])
- LDFLAGS=$hold_ldflags])
- AS_IF([test $tcl_cv_ld_single_module = yes], [
- SHLIB_LD="${SHLIB_LD} -Wl,-single_module"
- ])
- # TEA specific: link shlib with current and compatibility version flags
- vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d`
- SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}"
- SHLIB_SUFFIX=".dylib"
- LDFLAGS="$LDFLAGS -headerpad_max_install_names"
- AC_CACHE_CHECK([if ld accepts -search_paths_first flag],
- tcl_cv_ld_search_paths_first, [
- hold_ldflags=$LDFLAGS
- LDFLAGS="$LDFLAGS -Wl,-search_paths_first"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])],
- [tcl_cv_ld_search_paths_first=yes],[tcl_cv_ld_search_paths_first=no])
- LDFLAGS=$hold_ldflags])
- AS_IF([test $tcl_cv_ld_search_paths_first = yes], [
- LDFLAGS="$LDFLAGS -Wl,-search_paths_first"
- ])
- AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [
- AC_DEFINE(MODULE_SCOPE, [__private_extern__],
- [Compiler support for module scope symbols])
- tcl_cv_cc_visibility_hidden=yes
- ])
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH"
- # TEA specific: for combined 32 & 64 bit fat builds of Tk
- # extensions, verify that 64-bit build is possible.
- AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [
- AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [
- AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"'
- done
- CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include"
- LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <X11/Xlib.h>]], [[XrmInitialize();]])],
- [tcl_cv_lib_x11_64=yes],[tcl_cv_lib_x11_64=no])
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval $v'="$hold_'$v'"'
- done])
- ])
- AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [
- AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"'
- done
- CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}"
- LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <tk.h>]], [[Tk_InitStubs(NULL, "", 0);]])],
- [tcl_cv_lib_tk_64=yes],[tcl_cv_lib_tk_64=no])
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval $v'="$hold_'$v'"'
- done])
- ])
- # remove 64-bit arch flags from CFLAGS et al. if configuration
- # does not support 64-bit.
- AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [
- AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags])
- for v in CFLAGS CPPFLAGS LDFLAGS; do
- eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"'
- done])
- ])
- ;;
- OS/390-*)
- CFLAGS_OPTIMIZE="" # Optimizer is buggy
- AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h
- [Should OS/390 do the right thing with sockets?])
- ;;
- OSF1-V*)
- # Digital OSF/1
- SHLIB_CFLAGS=""
- AS_IF([test "$SHARED_BUILD" = 1], [
- SHLIB_LD='ld -shared -expect_unresolved "*"'
- ], [
- SHLIB_LD='ld -non_shared -expect_unresolved "*"'
- ])
- SHLIB_SUFFIX=".so"
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
- AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [
- CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"])
- # see pthread_intro(3) for pthread support on osf1, k.furukawa
- CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
- CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
- LIBS=`echo $LIBS | sed s/-lpthreads//`
- AS_IF([test "$GCC" = yes], [
- LIBS="$LIBS -lpthread -lmach -lexc"
- ], [
- CFLAGS="$CFLAGS -pthread"
- LDFLAGS="$LDFLAGS -pthread"
- ])
- ;;
- QNX-6*)
- # QNX RTP
- # This may work for all QNX, but it was only reported for v6.
- SHLIB_CFLAGS="-fPIC"
- SHLIB_LD="ld -Bshareable -x"
- SHLIB_LD_LIBS=""
- SHLIB_SUFFIX=".so"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- SCO_SV-3.2*)
- AS_IF([test "$GCC" = yes], [
- SHLIB_CFLAGS="-fPIC -melf"
- LDFLAGS="$LDFLAGS -melf -Wl,-Bexport"
- ], [
- SHLIB_CFLAGS="-Kpic -belf"
- LDFLAGS="$LDFLAGS -belf -Wl,-Bexport"
- ])
- SHLIB_LD="ld -G"
- SHLIB_LD_LIBS=""
- SHLIB_SUFFIX=".so"
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- SunOS-5.[[0-6]])
- # Careful to not let 5.10+ fall into this case
-
- # Note: If _REENTRANT isn't defined, then Solaris
- # won't define thread-safe library routines.
-
- AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?])
- AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1,
- [Do we really want to follow the standard? Yes we do!])
-
- SHLIB_CFLAGS="-KPIC"
- SHLIB_SUFFIX=".so"
- AS_IF([test "$GCC" = yes], [
- SHLIB_LD='${CC} -shared'
- CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- ], [
- SHLIB_LD="/usr/ccs/bin/ld -G -z text"
- CC_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- ])
- ;;
- SunOS-5*)
- # Note: If _REENTRANT isn't defined, then Solaris
- # won't define thread-safe library routines.
-
- AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?])
- AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1,
- [Do we really want to follow the standard? Yes we do!])
-
- SHLIB_CFLAGS="-KPIC"
-
- # Check to enable 64-bit flags for compiler/linker
- AS_IF([test "$do64bit" = yes], [
- arch=`isainfo`
- AS_IF([test "$arch" = "sparcv9 sparc"], [
- AS_IF([test "$GCC" = yes], [
- AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [
- AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system])
- ], [
- do64bit_ok=yes
- CFLAGS="$CFLAGS -m64 -mcpu=v9"
- LDFLAGS="$LDFLAGS -m64 -mcpu=v9"
- SHLIB_CFLAGS="-fPIC"
- ])
- ], [
- do64bit_ok=yes
- AS_IF([test "$do64bitVIS" = yes], [
- CFLAGS="$CFLAGS -xarch=v9a"
- LDFLAGS_ARCH="-xarch=v9a"
- ], [
- CFLAGS="$CFLAGS -xarch=v9"
- LDFLAGS_ARCH="-xarch=v9"
- ])
- # Solaris 64 uses this as well
- #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64"
- ])
- ], [AS_IF([test "$arch" = "amd64 i386"], [
- AS_IF([test "$GCC" = yes], [
- case $system in
- SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*)
- do64bit_ok=yes
- CFLAGS="$CFLAGS -m64"
- LDFLAGS="$LDFLAGS -m64";;
- *)
- AC_MSG_WARN([64bit mode not supported with GCC on $system]);;
- esac
- ], [
- do64bit_ok=yes
- case $system in
- SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*)
- CFLAGS="$CFLAGS -m64"
- LDFLAGS="$LDFLAGS -m64";;
- *)
- CFLAGS="$CFLAGS -xarch=amd64"
- LDFLAGS="$LDFLAGS -xarch=amd64";;
- esac
- ])
- ], [AC_MSG_WARN([64bit mode not supported for $arch])])])
- ])
-
- SHLIB_SUFFIX=".so"
- AS_IF([test "$GCC" = yes], [
- SHLIB_LD='${CC} -shared'
- CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- AS_IF([test "$do64bit_ok" = yes], [
- AS_IF([test "$arch" = "sparcv9 sparc"], [
- # We need to specify -static-libgcc or we need to
- # add the path to the sparv9 libgcc.
- # JH: static-libgcc is necessary for core Tcl, but may
- # not be necessary for extensions.
- SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc"
- # for finding sparcv9 libgcc, get the regular libgcc
- # path, remove so name and append 'sparcv9'
- #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..."
- #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir"
- ], [AS_IF([test "$arch" = "amd64 i386"], [
- # JH: static-libgcc is necessary for core Tcl, but may
- # not be necessary for extensions.
- SHLIB_LD="$SHLIB_LD -m64 -static-libgcc"
- ])])
- ])
- ], [
- case $system in
- SunOS-5.[[1-9]][[0-9]]*)
- # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS
- SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';;
- *)
- SHLIB_LD='/usr/ccs/bin/ld -G -z text';;
- esac
- CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
- LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
- ])
- ;;
- UNIX_SV* | UnixWare-5*)
- SHLIB_CFLAGS="-KPIC"
- SHLIB_LD='${CC} -G'
- SHLIB_LD_LIBS=""
- SHLIB_SUFFIX=".so"
- # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers
- # that don't grok the -Bexport option. Test that it does.
- AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [
- hold_ldflags=$LDFLAGS
- LDFLAGS="$LDFLAGS -Wl,-Bexport"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])],
- [tcl_cv_ld_Bexport=yes],[tcl_cv_ld_Bexport=no])
- LDFLAGS=$hold_ldflags])
- AS_IF([test $tcl_cv_ld_Bexport = yes], [
- LDFLAGS="$LDFLAGS -Wl,-Bexport"
- ])
- CC_SEARCH_FLAGS=""
- LD_SEARCH_FLAGS=""
- ;;
- esac
-
- AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [
- AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform])
- ])
-
-dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so
-dnl # until the end of configure, as configure's compile and link tests use
-dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's
-dnl # preprocessing tests use only CPPFLAGS.
- AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""])
-
- # Add in the arch flags late to ensure it wasn't removed.
- # Not necessary in TEA, but this is aligned with core
- LDFLAGS="$LDFLAGS $LDFLAGS_ARCH"
-
- # If we're running gcc, then change the C flags for compiling shared
- # libraries to the right flags for gcc, instead of those for the
- # standard manufacturer compiler.
-
- AS_IF([test "$GCC" = yes], [
- case $system in
- AIX-*) ;;
- BSD/OS*) ;;
- CYGWIN_*|MINGW32_*|MINGW64_*|MSYS_*) ;;
- IRIX*) ;;
- NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;;
- Darwin-*) ;;
- SCO_SV-3.2*) ;;
- windows) ;;
- *) SHLIB_CFLAGS="-fPIC" ;;
- esac])
-
- AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [
- AC_DEFINE(MODULE_SCOPE, [extern],
- [No Compiler support for module scope symbols])
- ])
-
- AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [
- # TEA specific: use PACKAGE_VERSION instead of VERSION
- SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}'])
- AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [
- # TEA specific: use PACKAGE_VERSION instead of VERSION
- UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a'])
-
- if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then
- AC_CACHE_CHECK(for SEH support in compiler,
- tcl_cv_seh,
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-
- int main(int argc, char** argv) {
- int a, b = 0;
- __try {
- a = 666 / b;
- }
- __except (EXCEPTION_EXECUTE_HANDLER) {
- return 0;
- }
- return 1;
- }
- ]])],
- [tcl_cv_seh=yes],
- [tcl_cv_seh=no],
- [tcl_cv_seh=no])
- )
- if test "$tcl_cv_seh" = "no" ; then
- AC_DEFINE(HAVE_NO_SEH, 1,
- [Defined when mingw does not support SEH])
- fi
-
- #
- # Check to see if the excpt.h include file provided contains the
- # definition for EXCEPTION_DISPOSITION; if not, which is the case
- # with Cygwin's version as of 2002-04-10, define it to be int,
- # sufficient for getting the current code to work.
- #
- AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files,
- tcl_cv_eh_disposition,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-# undef WIN32_LEAN_AND_MEAN
- ]], [[
- EXCEPTION_DISPOSITION x;
- ]])],
- [tcl_cv_eh_disposition=yes],
- [tcl_cv_eh_disposition=no])
- )
- if test "$tcl_cv_eh_disposition" = "no" ; then
- AC_DEFINE(EXCEPTION_DISPOSITION, int,
- [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION])
- fi
-
- # Check to see if winnt.h defines CHAR, SHORT, and LONG
- # even if VOID has already been #defined. The win32api
- # used by mingw and cygwin is known to do this.
-
- AC_CACHE_CHECK(for winnt.h that ignores VOID define,
- tcl_cv_winnt_ignore_void,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-#define VOID void
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
- ]], [[
- CHAR c;
- SHORT s;
- LONG l;
- ]])],
- [tcl_cv_winnt_ignore_void=yes],
- [tcl_cv_winnt_ignore_void=no])
- )
- if test "$tcl_cv_winnt_ignore_void" = "yes" ; then
- AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1,
- [Defined when cygwin/mingw ignores VOID define in winnt.h])
- fi
- fi
-
- # See if the compiler supports casting to a union type.
- # This is used to stop gcc from printing a compiler
- # warning when initializing a union member.
-
- AC_CACHE_CHECK(for cast to union support,
- tcl_cv_cast_to_union,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
- union foo { int i; double d; };
- union foo f = (union foo) (int) 0;
- ]])],
- [tcl_cv_cast_to_union=yes],
- [tcl_cv_cast_to_union=no])
- )
- if test "$tcl_cv_cast_to_union" = "yes"; then
- AC_DEFINE(HAVE_CAST_TO_UNION, 1,
- [Defined when compiler supports casting to union type.])
- fi
-
- AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have <stdbool.h>?])],)
-
- AC_SUBST(CFLAGS_DEBUG)
- AC_SUBST(CFLAGS_OPTIMIZE)
- AC_SUBST(CFLAGS_WARNING)
- AC_SUBST(LDFLAGS_DEBUG)
- AC_SUBST(LDFLAGS_OPTIMIZE)
-
- AC_SUBST(STLIB_LD)
- AC_SUBST(SHLIB_LD)
-
- AC_SUBST(SHLIB_LD_LIBS)
- AC_SUBST(SHLIB_CFLAGS)
-
- AC_SUBST(LD_LIBRARY_PATH_VAR)
-
- # These must be called after we do the basic CFLAGS checks and
- # verify any possible 64-bit or similar switches are necessary
- TEA_TCL_EARLY_FLAGS
- TEA_TCL_64BIT_FLAGS
-])
-
-#--------------------------------------------------------------------
-# TEA_SERIAL_PORT
-#
-# Determine which interface to use to talk to the serial port.
-# Note that #include lines must begin in leftmost column for
-# some compilers to recognize them as preprocessor directives,
-# and some build environments have stdin not pointing at a
-# pseudo-terminal (usually /dev/null instead.)
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Defines only one of the following vars:
-# HAVE_SYS_MODEM_H
-# USE_TERMIOS
-# USE_TERMIO
-# USE_SGTTY
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_SERIAL_PORT], [
- AC_CHECK_HEADERS(sys/modem.h)
- AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#include <termios.h>
-
-int main() {
- struct termios t;
- if (tcgetattr(0, &t) == 0) {
- cfsetospeed(&t, 0);
- t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB;
- return 0;
- }
- return 1;
-}]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
- if test $tcl_cv_api_serial = no ; then
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#include <termio.h>
-
-int main() {
- struct termio t;
- if (ioctl(0, TCGETA, &t) == 0) {
- t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB;
- return 0;
- }
- return 1;
-}]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
- fi
- if test $tcl_cv_api_serial = no ; then
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#include <sgtty.h>
-
-int main() {
- struct sgttyb t;
- if (ioctl(0, TIOCGETP, &t) == 0) {
- t.sg_ospeed = 0;
- t.sg_flags |= ODDP | EVENP | RAW;
- return 0;
- }
- return 1;
-}]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
- fi
- if test $tcl_cv_api_serial = no ; then
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#include <termios.h>
-#include <errno.h>
-
-int main() {
- struct termios t;
- if (tcgetattr(0, &t) == 0
- || errno == ENOTTY || errno == ENXIO || errno == EINVAL) {
- cfsetospeed(&t, 0);
- t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB;
- return 0;
- }
- return 1;
-}]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
- fi
- if test $tcl_cv_api_serial = no; then
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#include <termio.h>
-#include <errno.h>
-
-int main() {
- struct termio t;
- if (ioctl(0, TCGETA, &t) == 0
- || errno == ENOTTY || errno == ENXIO || errno == EINVAL) {
- t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB;
- return 0;
- }
- return 1;
- }]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
- fi
- if test $tcl_cv_api_serial = no; then
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#include <sgtty.h>
-#include <errno.h>
-
-int main() {
- struct sgttyb t;
- if (ioctl(0, TIOCGETP, &t) == 0
- || errno == ENOTTY || errno == ENXIO || errno == EINVAL) {
- t.sg_ospeed = 0;
- t.sg_flags |= ODDP | EVENP | RAW;
- return 0;
- }
- return 1;
-}]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=none],[tcl_cv_api_serial=none])
- fi])
- case $tcl_cv_api_serial in
- termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);;
- termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);;
- sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);;
- esac
-])
-
-#--------------------------------------------------------------------
-# TEA_PATH_X
-#
-# Locate the X11 header files and the X11 library archive. Try
-# the ac_path_x macro first, but if it doesn't find the X stuff
-# (e.g. because there's no xmkmf program) then check through
-# a list of possible directories. Under some conditions the
-# autoconf macro will return an include directory that contains
-# no include files, so double-check its result just to be safe.
-#
-# This should be called after TEA_CONFIG_CFLAGS as setting the
-# LIBS line can confuse some configure macro magic.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Sets the following vars:
-# XINCLUDES
-# XLIBSW
-# PKG_LIBS (appends to)
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_PATH_X], [
- if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then
- TEA_PATH_UNIX_X
- fi
-])
-
-AC_DEFUN([TEA_PATH_UNIX_X], [
- AC_PATH_X
- not_really_there=""
- if test "$no_x" = ""; then
- if test "$x_includes" = ""; then
- AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include <X11/Xlib.h>]])],[],[not_really_there="yes"])
- else
- if test ! -r $x_includes/X11/Xlib.h; then
- not_really_there="yes"
- fi
- fi
- fi
- if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then
- AC_MSG_CHECKING([for X11 header files])
- found_xincludes="no"
- AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include <X11/Xlib.h>]])],[found_xincludes="yes"],[found_xincludes="no"])
- if test "$found_xincludes" = "no"; then
- dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include"
- for i in $dirs ; do
- if test -r $i/X11/Xlib.h; then
- AC_MSG_RESULT([$i])
- XINCLUDES=" -I$i"
- found_xincludes="yes"
- break
- fi
- done
- fi
- else
- if test "$x_includes" != ""; then
- XINCLUDES="-I$x_includes"
- found_xincludes="yes"
- fi
- fi
- if test "$found_xincludes" = "no"; then
- AC_MSG_RESULT([couldn't find any!])
- fi
-
- if test "$no_x" = yes; then
- AC_MSG_CHECKING([for X11 libraries])
- XLIBSW=nope
- dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib"
- for i in $dirs ; do
- if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then
- AC_MSG_RESULT([$i])
- XLIBSW="-L$i -lX11"
- x_libraries="$i"
- break
- fi
- done
- else
- if test "$x_libraries" = ""; then
- XLIBSW=-lX11
- else
- XLIBSW="-L$x_libraries -lX11"
- fi
- fi
- if test "$XLIBSW" = nope ; then
- AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow)
- fi
- if test "$XLIBSW" = nope ; then
- AC_MSG_RESULT([could not find any! Using -lX11.])
- XLIBSW=-lX11
- fi
- # TEA specific:
- if test x"${XLIBSW}" != x ; then
- PKG_LIBS="${PKG_LIBS} ${XLIBSW}"
- fi
-])
-
-#--------------------------------------------------------------------
-# TEA_BLOCKING_STYLE
-#
-# The statements below check for systems where POSIX-style
-# non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented.
-# On these systems (mostly older ones), use the old BSD-style
-# FIONBIO approach instead.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Defines some of the following vars:
-# HAVE_SYS_IOCTL_H
-# HAVE_SYS_FILIO_H
-# USE_FIONBIO
-# O_NONBLOCK
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_BLOCKING_STYLE], [
- AC_CHECK_HEADERS(sys/ioctl.h)
- AC_CHECK_HEADERS(sys/filio.h)
- TEA_CONFIG_SYSTEM
- AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O])
- case $system in
- OSF*)
- AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?])
- AC_MSG_RESULT([FIONBIO])
- ;;
- *)
- AC_MSG_RESULT([O_NONBLOCK])
- ;;
- esac
-])
-
-#--------------------------------------------------------------------
-# TEA_TIME_HANDLER
-#
-# Checks how the system deals with time.h, what time structures
-# are used on the system, and what fields the structures have.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Defines some of the following vars:
-# USE_DELTA_FOR_TZ
-# HAVE_TM_GMTOFF
-# HAVE_TM_TZADJ
-# HAVE_TIMEZONE_VAR
-#
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_TIME_HANDLER], [
- AC_CHECK_HEADERS(sys/time.h)
- AC_HEADER_TIME
- AC_STRUCT_TIMEZONE
-
- AC_CHECK_FUNCS(gmtime_r localtime_r mktime)
-
- AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[struct tm tm; (void)tm.tm_tzadj;]])],
- [tcl_cv_member_tm_tzadj=yes],
- [tcl_cv_member_tm_tzadj=no])])
- if test $tcl_cv_member_tm_tzadj = yes ; then
- AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?])
- fi
-
- AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[struct tm tm; (void)tm.tm_gmtoff;]])],
- [tcl_cv_member_tm_gmtoff=yes],
- [tcl_cv_member_tm_gmtoff=no])])
- if test $tcl_cv_member_tm_gmtoff = yes ; then
- AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?])
- fi
-
- #
- # Its important to include time.h in this check, as some systems
- # (like convex) have timezone functions, etc.
- #
- AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>
-#include <stdlib.h>]],
- [[extern long timezone;
- timezone += 1;
- exit (0);]])],
- [tcl_cv_timezone_long=yes], [tcl_cv_timezone_long=no])])
- if test $tcl_cv_timezone_long = yes ; then
- AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?])
- else
- #
- # On some systems (eg IRIX 6.2), timezone is a time_t and not a long.
- #
- AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>
-#include <stdlib.h>]],
- [[extern time_t timezone;
- timezone += 1;
- exit (0);]])],
- [tcl_cv_timezone_time=yes], [tcl_cv_timezone_time=no])])
- if test $tcl_cv_timezone_time = yes ; then
- AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?])
- fi
- fi
-])
-
-#--------------------------------------------------------------------
-# TEA_BUGGY_STRTOD
-#
-# Under Solaris 2.4, strtod returns the wrong value for the
-# terminating character under some conditions. Check for this
-# and if the problem exists use a substitute procedure
-# "fixstrtod" (provided by Tcl) that corrects the error.
-# Also, on Compaq's Tru64 Unix 5.0,
-# strtod(" ") returns 0.0 instead of a failure to convert.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Might defines some of the following vars:
-# strtod (=fixstrtod)
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_BUGGY_STRTOD], [
- AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0)
- if test "$tcl_strtod" = 1; then
- AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
- #include <stdlib.h>
- extern double strtod();
- int main() {
- char *infString="Inf", *nanString="NaN", *spaceString=" ";
- char *term;
- double value;
- value = strtod(infString, &term);
- if ((term != infString) && (term[-1] == 0)) {
- exit(1);
- }
- value = strtod(nanString, &term);
- if ((term != nanString) && (term[-1] == 0)) {
- exit(1);
- }
- value = strtod(spaceString, &term);
- if (term == (spaceString+1)) {
- exit(1);
- }
- exit(0);
- }]])], [tcl_cv_strtod_buggy=ok], [tcl_cv_strtod_buggy=buggy],
- [tcl_cv_strtod_buggy=buggy])])
- if test "$tcl_cv_strtod_buggy" = buggy; then
- AC_LIBOBJ([fixstrtod])
- USE_COMPAT=1
- AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?])
- fi
- fi
-])
-
-#--------------------------------------------------------------------
-# TEA_TCL_LINK_LIBS
-#
-# Search for the libraries needed to link the Tcl shell.
-# Things like the math library (-lm), socket stuff (-lsocket vs.
-# -lnsl), zlib (-lz) and libtommath (-ltommath) are dealt with here.
-#
-# Arguments:
-# None.
-#
-# Results:
-#
-# Might append to the following vars:
-# LIBS
-# MATH_LIBS
-#
-# Might define the following vars:
-# HAVE_NET_ERRNO_H
-#
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_TCL_LINK_LIBS], [
- #--------------------------------------------------------------------
- # On a few very rare systems, all of the libm.a stuff is
- # already in libc.a. Set compiler flags accordingly.
- #--------------------------------------------------------------------
-
- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm")
-
- #--------------------------------------------------------------------
- # Interactive UNIX requires -linet instead of -lsocket, plus it
- # needs net/errno.h to define the socket-related error codes.
- #--------------------------------------------------------------------
-
- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"])
- AC_CHECK_HEADER(net/errno.h, [
- AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have <net/errno.h>?])])
-
- #--------------------------------------------------------------------
- # Check for the existence of the -lsocket and -lnsl libraries.
- # The order here is important, so that they end up in the right
- # order in the command line generated by make. Here are some
- # special considerations:
- # 1. Use "connect" and "accept" to check for -lsocket, and
- # "gethostbyname" to check for -lnsl.
- # 2. Use each function name only once: can't redo a check because
- # autoconf caches the results of the last check and won't redo it.
- # 3. Use -lnsl and -lsocket only if they supply procedures that
- # aren't already present in the normal libraries. This is because
- # IRIX 5.2 has libraries, but they aren't needed and they're
- # bogus: they goof up name resolution if used.
- # 4. On some SVR4 systems, can't use -lsocket without -lnsl too.
- # To get around this problem, check for both libraries together
- # if -lsocket doesn't work by itself.
- #--------------------------------------------------------------------
-
- tcl_checkBoth=0
- AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1)
- if test "$tcl_checkSocket" = 1; then
- AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt,
- LIBS="$LIBS -lsocket", tcl_checkBoth=1)])
- fi
- if test "$tcl_checkBoth" = 1; then
- tk_oldLibs=$LIBS
- LIBS="$LIBS -lsocket -lnsl"
- AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs])
- fi
- AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname,
- [LIBS="$LIBS -lnsl"])])
- AC_CHECK_FUNC(mp_log_u32, , [AC_CHECK_LIB(tommath, mp_log_u32,
- [LIBS="$LIBS -ltommath"])])
- AC_CHECK_FUNC(deflateSetHeader, , [AC_CHECK_LIB(z, deflateSetHeader,
- [LIBS="$LIBS -lz"])])
-])
-
-#--------------------------------------------------------------------
-# TEA_TCL_EARLY_FLAGS
-#
-# Check for what flags are needed to be passed so the correct OS
-# features are available.
-#
-# Arguments:
-# None
-#
-# Results:
-#
-# Might define the following vars:
-# _ISOC99_SOURCE
-# _LARGEFILE64_SOURCE
-# _LARGEFILE_SOURCE64
-#
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_TCL_EARLY_FLAG],[
- AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]),
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$2]], [[$3]])],
- [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[[#define ]$1[ 1
-]$2]], [[$3]])],
- [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes,
- [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no)]))
- if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then
- AC_DEFINE($1, 1, [Add the ]$1[ flag when building])
- tcl_flags="$tcl_flags $1"
- fi
-])
-
-AC_DEFUN([TEA_TCL_EARLY_FLAGS],[
- AC_MSG_CHECKING([for required early compiler flags])
- tcl_flags=""
- TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include <stdlib.h>],
- [char *p = (char *)strtoll; char *q = (char *)strtoull;])
- TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include <sys/stat.h>],
- [struct stat64 buf; int i = stat64("/", &buf);])
- TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include <sys/stat.h>],
- [char *p = (char *)open64;])
- if test "x${tcl_flags}" = "x" ; then
- AC_MSG_RESULT([none])
- else
- AC_MSG_RESULT([${tcl_flags}])
- fi
-])
-
-#--------------------------------------------------------------------
-# TEA_TCL_64BIT_FLAGS
-#
-# Check for what is defined in the way of 64-bit features.
-#
-# Arguments:
-# None
-#
-# Results:
-#
-# Might define the following vars:
-# TCL_WIDE_INT_IS_LONG
-# TCL_WIDE_INT_TYPE
-# HAVE_STRUCT_DIRENT64, HAVE_DIR64
-# HAVE_STRUCT_STAT64
-# HAVE_TYPE_OFF64_T
-#
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
- AC_MSG_CHECKING([for 64-bit integer type])
- AC_CACHE_VAL(tcl_cv_type_64bit,[
- tcl_cv_type_64bit=none
- # See if the compiler knows natively about __int64
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[__int64 value = (__int64) 0;]])],
- [tcl_type_64bit=__int64],[tcl_type_64bit="long long"])
- # See if we could use long anyway Note that we substitute in the
- # type that is our current guess for a 64-bit type inside this check
- # program, so it should be modified only carefully...
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[switch (0) {
- case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ;
- }]])],[tcl_cv_type_64bit=${tcl_type_64bit}],[])])
- if test "${tcl_cv_type_64bit}" = none ; then
- AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Do 'long' and 'long long' have the same size (64-bit)?])
- AC_MSG_RESULT([yes])
- elif test "${tcl_cv_type_64bit}" = "__int64" \
- -a "${TEA_PLATFORM}" = "windows" ; then
- # TEA specific: We actually want to use the default tcl.h checks in
- # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER*
- AC_MSG_RESULT([using Tcl header defaults])
- else
- AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit},
- [What type should be used to define wide integers?])
- AC_MSG_RESULT([${tcl_cv_type_64bit}])
-
- # Now check for auxiliary declarations
- AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
-#include <dirent.h>]], [[struct dirent64 p;]])],
- [tcl_cv_struct_dirent64=yes],[tcl_cv_struct_dirent64=no])])
- if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then
- AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in <sys/types.h>?])
- fi
-
- AC_CACHE_CHECK([for DIR64], tcl_cv_DIR64,[
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
-#include <dirent.h>]], [[struct dirent64 *p; DIR64 d = opendir64(".");
- p = readdir64(d); rewinddir64(d); closedir64(d);]])],
- [tcl_cv_DIR64=yes], [tcl_cv_DIR64=no])])
- if test "x${tcl_cv_DIR64}" = "xyes" ; then
- AC_DEFINE(HAVE_DIR64, 1, [Is 'DIR64' in <sys/types.h>?])
- fi
-
- AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/stat.h>]], [[struct stat64 p;
-]])],
- [tcl_cv_struct_stat64=yes], [tcl_cv_struct_stat64=no])])
- if test "x${tcl_cv_struct_stat64}" = "xyes" ; then
- AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in <sys/stat.h>?])
- fi
-
- AC_CHECK_FUNCS(open64 lseek64)
- AC_MSG_CHECKING([for off64_t])
- AC_CACHE_VAL(tcl_cv_type_off64_t,[
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>]], [[off64_t offset;
-]])],
- [tcl_cv_type_off64_t=yes], [tcl_cv_type_off64_t=no])])
- dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the
- dnl functions lseek64 and open64 are defined.
- if test "x${tcl_cv_type_off64_t}" = "xyes" && \
- test "x${ac_cv_func_lseek64}" = "xyes" && \
- test "x${ac_cv_func_open64}" = "xyes" ; then
- AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in <sys/types.h>?])
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- fi
-])
-
-##
-## Here ends the standard Tcl configuration bits and starts the
-## TEA specific functions
-##
-
-#------------------------------------------------------------------------
-# TEA_INIT --
-#
-# Init various Tcl Extension Architecture (TEA) variables.
-# This should be the first called TEA_* macro.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Defines and substs the following vars:
-# CYGPATH
-# EXEEXT
-# Defines only:
-# TEA_VERSION
-# TEA_INITED
-# TEA_PLATFORM (windows or unix)
-#
-# "cygpath" is used on windows to generate native path names for include
-# files. These variables should only be used with the compiler and linker
-# since they generate native path names.
-#
-# EXEEXT
-# Select the executable extension based on the host type. This
-# is a lightweight replacement for AC_EXEEXT that doesn't require
-# a compiler.
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_INIT], [
- TEA_VERSION="3.13"
-
- AC_MSG_CHECKING([TEA configuration])
- if test x"${PACKAGE_NAME}" = x ; then
- AC_MSG_ERROR([
-The PACKAGE_NAME variable must be defined by your TEA configure.ac])
- fi
- AC_MSG_RESULT([ok (TEA ${TEA_VERSION})])
-
- # If the user did not set CFLAGS, set it now to keep macros
- # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2".
- if test "${CFLAGS+set}" != "set" ; then
- CFLAGS=""
- fi
-
- case "`uname -s`" in
- *win32*|*WIN32*|*MINGW32_*|*MINGW64_*|*MSYS_*)
- AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo)
- EXEEXT=".exe"
- TEA_PLATFORM="windows"
- ;;
- *CYGWIN_*)
- EXEEXT=".exe"
- # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG
- ;;
- *)
- CYGPATH=echo
- # Maybe we are cross-compiling....
- case ${host_alias} in
- *mingw32*)
- EXEEXT=".exe"
- TEA_PLATFORM="windows"
- ;;
- *)
- EXEEXT=""
- TEA_PLATFORM="unix"
- ;;
- esac
- ;;
- esac
-
- # Check if exec_prefix is set. If not use fall back to prefix.
- # Note when adjusted, so that TEA_PREFIX can correct for this.
- # This is needed for recursive configures, since autoconf propagates
- # $prefix, but not $exec_prefix (doh!).
- if test x$exec_prefix = xNONE ; then
- exec_prefix_default=yes
- exec_prefix=$prefix
- fi
-
- AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}])
-
- AC_SUBST(EXEEXT)
- AC_SUBST(CYGPATH)
-
- # This package name must be replaced statically for AC_SUBST to work
- AC_SUBST(PKG_LIB_FILE)
- AC_SUBST(PKG_LIB_FILE8)
- AC_SUBST(PKG_LIB_FILE9)
- # Substitute STUB_LIB_FILE in case package creates a stub library too.
- AC_SUBST(PKG_STUB_LIB_FILE)
-
- # We AC_SUBST these here to ensure they are subst'ed,
- # in case the user doesn't call TEA_ADD_...
- AC_SUBST(PKG_STUB_SOURCES)
- AC_SUBST(PKG_STUB_OBJECTS)
- AC_SUBST(PKG_TCL_SOURCES)
- AC_SUBST(PKG_HEADERS)
- AC_SUBST(PKG_INCLUDES)
- AC_SUBST(PKG_LIBS)
- AC_SUBST(PKG_CFLAGS)
-
- # Configure the installer.
- TEA_INSTALLER
-])
-
-#------------------------------------------------------------------------
-# TEA_ADD_SOURCES --
-#
-# Specify one or more source files. Users should check for
-# the right platform before adding to their list.
-# It is not important to specify the directory, as long as it is
-# in the generic, win or unix subdirectory of $(srcdir).
-#
-# Arguments:
-# one or more file names
-#
-# Results:
-#
-# Defines and substs the following vars:
-# PKG_SOURCES
-# PKG_OBJECTS
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_ADD_SOURCES], [
- vars="$@"
- for i in $vars; do
- case $i in
- [\$]*)
- # allow $-var names
- PKG_SOURCES="$PKG_SOURCES $i"
- PKG_OBJECTS="$PKG_OBJECTS $i"
- ;;
- *)
- # check for existence - allows for generic/win/unix VPATH
- # To add more dirs here (like 'src'), you have to update VPATH
- # in Makefile.in as well
- if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \
- -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \
- -a ! -f "${srcdir}/macosx/$i" \
- ; then
- AC_MSG_ERROR([could not find source file '$i'])
- fi
- PKG_SOURCES="$PKG_SOURCES $i"
- # this assumes it is in a VPATH dir
- i=`basename $i`
- # handle user calling this before or after TEA_SETUP_COMPILER
- if test x"${OBJEXT}" != x ; then
- j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}"
- else
- j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}"
- fi
- PKG_OBJECTS="$PKG_OBJECTS $j"
- ;;
- esac
- done
- AC_SUBST(PKG_SOURCES)
- AC_SUBST(PKG_OBJECTS)
-])
-
-#------------------------------------------------------------------------
-# TEA_ADD_STUB_SOURCES --
-#
-# Specify one or more source files. Users should check for
-# the right platform before adding to their list.
-# It is not important to specify the directory, as long as it is
-# in the generic, win or unix subdirectory of $(srcdir).
-#
-# Arguments:
-# one or more file names
-#
-# Results:
-#
-# Defines and substs the following vars:
-# PKG_STUB_SOURCES
-# PKG_STUB_OBJECTS
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_ADD_STUB_SOURCES], [
- vars="$@"
- for i in $vars; do
- # check for existence - allows for generic/win/unix VPATH
- if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \
- -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \
- -a ! -f "${srcdir}/macosx/$i" \
- ; then
- AC_MSG_ERROR([could not find stub source file '$i'])
- fi
- PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i"
- # this assumes it is in a VPATH dir
- i=`basename $i`
- # handle user calling this before or after TEA_SETUP_COMPILER
- if test x"${OBJEXT}" != x ; then
- j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}"
- else
- j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}"
- fi
- PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j"
- done
- AC_SUBST(PKG_STUB_SOURCES)
- AC_SUBST(PKG_STUB_OBJECTS)
-])
-
-#------------------------------------------------------------------------
-# TEA_ADD_TCL_SOURCES --
-#
-# Specify one or more Tcl source files. These should be platform
-# independent runtime files.
-#
-# Arguments:
-# one or more file names
-#
-# Results:
-#
-# Defines and substs the following vars:
-# PKG_TCL_SOURCES
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_ADD_TCL_SOURCES], [
- vars="$@"
- for i in $vars; do
- # check for existence, be strict because it is installed
- if test ! -f "${srcdir}/$i" ; then
- AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i'])
- fi
- PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i"
- done
- AC_SUBST(PKG_TCL_SOURCES)
-])
-
-#------------------------------------------------------------------------
-# TEA_ADD_HEADERS --
-#
-# Specify one or more source headers. Users should check for
-# the right platform before adding to their list.
-#
-# Arguments:
-# one or more file names
-#
-# Results:
-#
-# Defines and substs the following vars:
-# PKG_HEADERS
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_ADD_HEADERS], [
- vars="$@"
- for i in $vars; do
- # check for existence, be strict because it is installed
- if test ! -f "${srcdir}/$i" ; then
- AC_MSG_ERROR([could not find header file '${srcdir}/$i'])
- fi
- PKG_HEADERS="$PKG_HEADERS $i"
- done
- AC_SUBST(PKG_HEADERS)
-])
-
-#------------------------------------------------------------------------
-# TEA_ADD_INCLUDES --
-#
-# Specify one or more include dirs. Users should check for
-# the right platform before adding to their list.
-#
-# Arguments:
-# one or more file names
-#
-# Results:
-#
-# Defines and substs the following vars:
-# PKG_INCLUDES
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_ADD_INCLUDES], [
- vars="$@"
- for i in $vars; do
- PKG_INCLUDES="$PKG_INCLUDES $i"
- done
- AC_SUBST(PKG_INCLUDES)
-])
-
-#------------------------------------------------------------------------
-# TEA_ADD_LIBS --
-#
-# Specify one or more libraries. Users should check for
-# the right platform before adding to their list. For Windows,
-# libraries provided in "foo.lib" format will be converted to
-# "-lfoo" when using GCC (mingw).
-#
-# Arguments:
-# one or more file names
-#
-# Results:
-#
-# Defines and substs the following vars:
-# PKG_LIBS
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_ADD_LIBS], [
- vars="$@"
- for i in $vars; do
- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
- # Convert foo.lib to -lfoo for GCC. No-op if not *.lib
- i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.[[lL]][[iI]][[bB]][$]/-l\1/'`
- fi
- PKG_LIBS="$PKG_LIBS $i"
- done
- AC_SUBST(PKG_LIBS)
-])
-
-#------------------------------------------------------------------------
-# TEA_ADD_CFLAGS --
-#
-# Specify one or more CFLAGS. Users should check for
-# the right platform before adding to their list.
-#
-# Arguments:
-# one or more file names
-#
-# Results:
-#
-# Defines and substs the following vars:
-# PKG_CFLAGS
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_ADD_CFLAGS], [
- PKG_CFLAGS="$PKG_CFLAGS $@"
- AC_SUBST(PKG_CFLAGS)
-])
-
-#------------------------------------------------------------------------
-# TEA_ADD_CLEANFILES --
-#
-# Specify one or more CLEANFILES.
-#
-# Arguments:
-# one or more file names to clean target
-#
-# Results:
-#
-# Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_ADD_CLEANFILES], [
- CLEANFILES="$CLEANFILES $@"
-])
-
-#------------------------------------------------------------------------
-# TEA_PREFIX --
-#
-# Handle the --prefix=... option by defaulting to what Tcl gave
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# If --prefix or --exec-prefix was not specified, $prefix and
-# $exec_prefix will be set to the values given to Tcl when it was
-# configured.
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_PREFIX], [
- if test "${prefix}" = "NONE"; then
- prefix_default=yes
- if test x"${TCL_PREFIX}" != x; then
- AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}])
- prefix=${TCL_PREFIX}
- else
- AC_MSG_NOTICE([--prefix defaulting to /usr/local])
- prefix=/usr/local
- fi
- fi
- if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \
- -o x"${exec_prefix_default}" = x"yes" ; then
- if test x"${TCL_EXEC_PREFIX}" != x; then
- AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}])
- exec_prefix=${TCL_EXEC_PREFIX}
- else
- AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}])
- exec_prefix=$prefix
- fi
- fi
-])
-
-#------------------------------------------------------------------------
-# TEA_SETUP_COMPILER_CC --
-#
-# Do compiler checks the way we want. This is just a replacement
-# for AC_PROG_CC in TEA configure.ac files to make them cleaner.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Sets up CC var and other standard bits we need to make executables.
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_SETUP_COMPILER_CC], [
- # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE)
- # in this macro, they need to go into TEA_SETUP_COMPILER instead.
-
- AC_PROG_CC
- AC_PROG_CPP
-
- #--------------------------------------------------------------------
- # Checks to see if the make program sets the $MAKE variable.
- #--------------------------------------------------------------------
-
- AC_PROG_MAKE_SET
-
- #--------------------------------------------------------------------
- # Find ranlib
- #--------------------------------------------------------------------
-
- AC_CHECK_TOOL(RANLIB, ranlib)
-
- #--------------------------------------------------------------------
- # Determines the correct binary file extension (.o, .obj, .exe etc.)
- #--------------------------------------------------------------------
-
- AC_OBJEXT
- AC_EXEEXT
-])
-
-#------------------------------------------------------------------------
-# TEA_SETUP_COMPILER --
-#
-# Do compiler checks that use the compiler. This must go after
-# TEA_SETUP_COMPILER_CC, which does the actual compiler check.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Sets up CC var and other standard bits we need to make executables.
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_SETUP_COMPILER], [
- # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here.
- AC_REQUIRE([TEA_SETUP_COMPILER_CC])
-
- #------------------------------------------------------------------------
- # If we're using GCC, see if the compiler understands -pipe. If so, use it.
- # It makes compiling go faster. (This is only a performance feature.)
- #------------------------------------------------------------------------
-
- if test -z "$no_pipe" -a -n "$GCC"; then
- AC_CACHE_CHECK([if the compiler understands -pipe],
- tcl_cv_cc_pipe, [
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[tcl_cv_cc_pipe=yes],[tcl_cv_cc_pipe=no])
- CFLAGS=$hold_cflags])
- if test $tcl_cv_cc_pipe = yes; then
- CFLAGS="$CFLAGS -pipe"
- fi
- fi
-
- #--------------------------------------------------------------------
- # Common compiler flag setup
- #--------------------------------------------------------------------
-
- AC_C_BIGENDIAN
-])
-
-#------------------------------------------------------------------------
-# TEA_MAKE_LIB --
-#
-# Generate a line that can be used to build a shared/unshared library
-# in a platform independent manner.
-#
-# Arguments:
-# none
-#
-# Requires:
-#
-# Results:
-#
-# Defines the following vars:
-# CFLAGS - Done late here to note disturb other AC macros
-# MAKE_LIB - Command to execute to build the Tcl library;
-# differs depending on whether or not Tcl is being
-# compiled as a shared library.
-# MAKE_SHARED_LIB Makefile rule for building a shared library
-# MAKE_STATIC_LIB Makefile rule for building a static library
-# MAKE_STUB_LIB Makefile rule for building a stub library
-# VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL
-# VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_MAKE_LIB], [
- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then
- MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)"
- MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
- AC_EGREP_CPP([manifest needed], [
-#if defined(_MSC_VER) && _MSC_VER >= 1400
-print("manifest needed")
-#endif
- ], [
- # Could do a CHECK_PROG for mt, but should always be with MSVC8+
- VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi"
- VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi"
- MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}"
- TEA_ADD_CLEANFILES([*.manifest])
- ])
- MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)"
- else
- MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)"
- MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
- MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)"
- fi
-
- if test "${SHARED_BUILD}" = "1" ; then
- MAKE_LIB="${MAKE_SHARED_LIB} "
- else
- MAKE_LIB="${MAKE_STATIC_LIB} "
- fi
-
- #--------------------------------------------------------------------
- # Shared libraries and static libraries have different names.
- # Use the double eval to make sure any variables in the suffix is
- # substituted. (@@@ Might not be necessary anymore)
- #--------------------------------------------------------------------
-
- PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}"
- PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9"
- if test "${TCL_MAJOR_VERSION}" -gt 8 ; then
- PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}"
- else
- PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}"
- fi
- if test "${TEA_PLATFORM}" = "windows" ; then
- if test "${SHARED_BUILD}" = "1" ; then
- # We force the unresolved linking of symbols that are really in
- # the private libraries of Tcl and Tk.
- if test x"${TK_BIN_DIR}" != x ; then
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\""
- fi
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\""
- if test "$GCC" = "yes"; then
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc"
- fi
- eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- else
- if test "$GCC" = "yes"; then
- PACKAGE_LIB_PREFIX=lib${PACKAGE_LIB_PREFIX}
- fi
- eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- fi
- # Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
- if test "$GCC" = "yes"; then
- PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE}
- fi
- # These aren't needed on Windows (either MSVC or gcc)
- RANLIB=:
- RANLIB_STUB=:
- else
- RANLIB_STUB="${RANLIB}"
- if test "${SHARED_BUILD}" = "1" ; then
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}"
- if test x"${TK_BIN_DIR}" != x ; then
- SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}"
- fi
- eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
- RANLIB=:
- else
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- fi
- # Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
- fi
-
- # These are escaped so that only CFLAGS is picked up at configure time.
- # The other values will be substituted at make time.
- CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}"
- if test "${SHARED_BUILD}" = "1" ; then
- CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}"
- fi
-
- AC_SUBST(MAKE_LIB)
- AC_SUBST(MAKE_SHARED_LIB)
- AC_SUBST(MAKE_STATIC_LIB)
- AC_SUBST(MAKE_STUB_LIB)
- AC_SUBST(RANLIB_STUB)
- AC_SUBST(VC_MANIFEST_EMBED_DLL)
- AC_SUBST(VC_MANIFEST_EMBED_EXE)
-])
-
-#------------------------------------------------------------------------
-# TEA_LIB_SPEC --
-#
-# Compute the name of an existing object library located in libdir
-# from the given base name and produce the appropriate linker flags.
-#
-# Arguments:
-# basename The base name of the library without version
-# numbers, extensions, or "lib" prefixes.
-# extra_dir Extra directory in which to search for the
-# library. This location is used first, then
-# $prefix/$exec-prefix, then some defaults.
-#
-# Requires:
-# TEA_INIT and TEA_PREFIX must be called first.
-#
-# Results:
-#
-# Defines the following vars:
-# ${basename}_LIB_NAME The computed library name.
-# ${basename}_LIB_SPEC The computed linker flags.
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_LIB_SPEC], [
- AC_MSG_CHECKING([for $1 library])
-
- # Look in exec-prefix for the library (defined by TEA_PREFIX).
-
- tea_lib_name_dir="${exec_prefix}/lib"
-
- # Or in a user-specified location.
-
- if test x"$2" != x ; then
- tea_extra_lib_dir=$2
- else
- tea_extra_lib_dir=NONE
- fi
-
- for i in \
- `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \
- `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \
- `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \
- `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \
- `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \
- `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \
- `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \
- `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \
- `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \
- `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do
- if test -f "$i" ; then
- tea_lib_name_dir=`dirname $i`
- $1_LIB_NAME=`basename $i`
- $1_LIB_PATH_NAME=$i
- break
- fi
- done
-
- if test "${TEA_PLATFORM}" = "windows"; then
- $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\"
- else
- # Strip off the leading "lib" and trailing ".a" or ".so"
-
- tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'`
- $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}"
- fi
-
- if test "x${$1_LIB_NAME}" = x ; then
- AC_MSG_ERROR([not found])
- else
- AC_MSG_RESULT([${$1_LIB_SPEC}])
- fi
-])
-
-#------------------------------------------------------------------------
-# TEA_PRIVATE_TCL_HEADERS --
-#
-# Locate the private Tcl include files
-#
-# Arguments:
-#
-# Requires:
-# TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has
-# already been called.
-#
-# Results:
-#
-# Substitutes the following vars:
-# TCL_TOP_DIR_NATIVE
-# TCL_INCLUDES
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [
- # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh}
- AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS])
- AC_MSG_CHECKING([for Tcl private include files])
-
- TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}`
- TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\"
-
- # Check to see if tcl<Plat>Port.h isn't already with the public headers
- # Don't look for tclInt.h because that resides with tcl.h in the core
- # sources, but the <plat>Port headers are in a different directory
- if test "${TEA_PLATFORM}" = "windows" -a \
- -f "${ac_cv_c_tclh}/tclWinPort.h"; then
- result="private headers found with public headers"
- elif test "${TEA_PLATFORM}" = "unix" -a \
- -f "${ac_cv_c_tclh}/tclUnixPort.h"; then
- result="private headers found with public headers"
- else
- TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\"
- if test "${TEA_PLATFORM}" = "windows"; then
- TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\"
- else
- TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\"
- fi
- # Overwrite the previous TCL_INCLUDES as this should capture both
- # public and private headers in the same set.
- # We want to ensure these are substituted so as not to require
- # any *_NATIVE vars be defined in the Makefile
- TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}"
- if test "`uname -s`" = "Darwin"; then
- # If Tcl was built as a framework, attempt to use
- # the framework's Headers and PrivateHeaders directories
- case ${TCL_DEFS} in
- *TCL_FRAMEWORK*)
- if test -d "${TCL_BIN_DIR}/Headers" -a \
- -d "${TCL_BIN_DIR}/PrivateHeaders"; then
- TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}"
- else
- TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`"
- fi
- ;;
- esac
- result="Using ${TCL_INCLUDES}"
- else
- if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then
- AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}])
- fi
- result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}"
- fi
- fi
-
- AC_SUBST(TCL_TOP_DIR_NATIVE)
-
- AC_SUBST(TCL_INCLUDES)
- AC_MSG_RESULT([${result}])
-])
-
-#------------------------------------------------------------------------
-# TEA_PUBLIC_TCL_HEADERS --
-#
-# Locate the installed public Tcl header files
-#
-# Arguments:
-# None.
-#
-# Requires:
-# CYGPATH must be set
-#
-# Results:
-#
-# Adds a --with-tclinclude switch to configure.
-# Result is cached.
-#
-# Substitutes the following vars:
-# TCL_INCLUDES
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [
- AC_MSG_CHECKING([for Tcl public headers])
-
- AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval})
-
- AC_CACHE_VAL(ac_cv_c_tclh, [
- # Use the value from --with-tclinclude, if it was given
-
- if test x"${with_tclinclude}" != x ; then
- if test -f "${with_tclinclude}/tcl.h" ; then
- ac_cv_c_tclh=${with_tclinclude}
- else
- AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h])
- fi
- else
- list=""
- if test "`uname -s`" = "Darwin"; then
- # If Tcl was built as a framework, attempt to use
- # the framework's Headers directory
- case ${TCL_DEFS} in
- *TCL_FRAMEWORK*)
- list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`"
- ;;
- esac
- fi
-
- # Look in the source dir only if Tcl is not installed,
- # and in that situation, look there before installed locations.
- if test -f "${TCL_BIN_DIR}/Makefile" ; then
- list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`"
- fi
-
- # Check order: pkg --prefix location, Tcl's --prefix location,
- # relative to directory of tclConfig.sh.
-
- eval "temp_includedir=${includedir}"
- list="$list \
- `ls -d ${temp_includedir} 2>/dev/null` \
- `ls -d ${TCL_PREFIX}/include 2>/dev/null` \
- `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`"
- if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then
- list="$list /usr/local/include /usr/include"
- if test x"${TCL_INCLUDE_SPEC}" != x ; then
- d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'`
- list="$list `ls -d ${d} 2>/dev/null`"
- fi
- fi
- for i in $list ; do
- if test -f "$i/tcl.h" ; then
- ac_cv_c_tclh=$i
- break
- fi
- done
- fi
- ])
-
- # Print a message based on how we determined the include path
-
- if test x"${ac_cv_c_tclh}" = x ; then
- AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude])
- else
- AC_MSG_RESULT([${ac_cv_c_tclh}])
- fi
-
- # Convert to a native path and substitute into the output files.
-
- INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}`
-
- TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\"
-
- AC_SUBST(TCL_INCLUDES)
-])
-
-#------------------------------------------------------------------------
-# TEA_PRIVATE_TK_HEADERS --
-#
-# Locate the private Tk include files
-#
-# Arguments:
-#
-# Requires:
-# TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has
-# already been called.
-#
-# Results:
-#
-# Substitutes the following vars:
-# TK_INCLUDES
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [
- # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh}
- AC_REQUIRE([TEA_PUBLIC_TK_HEADERS])
- AC_MSG_CHECKING([for Tk private include files])
-
- TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}`
- TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\"
-
- # Check to see if tk<Plat>Port.h isn't already with the public headers
- # Don't look for tkInt.h because that resides with tk.h in the core
- # sources, but the <plat>Port headers are in a different directory
- if test "${TEA_PLATFORM}" = "windows" -a \
- -f "${ac_cv_c_tkh}/tkWinPort.h"; then
- result="private headers found with public headers"
- elif test "${TEA_PLATFORM}" = "unix" -a \
- -f "${ac_cv_c_tkh}/tkUnixPort.h"; then
- result="private headers found with public headers"
- else
- TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\"
- TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\"
- if test "${TEA_PLATFORM}" = "windows"; then
- TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\"
- else
- TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\"
- fi
- # Overwrite the previous TK_INCLUDES as this should capture both
- # public and private headers in the same set.
- # We want to ensure these are substituted so as not to require
- # any *_NATIVE vars be defined in the Makefile
- TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}"
- # Detect and add ttk subdir
- if test -d "${TK_SRC_DIR}/generic/ttk"; then
- TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\""
- fi
- if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then
- TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\""
- fi
- if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then
- TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\""
- fi
- if test "`uname -s`" = "Darwin"; then
- # If Tk was built as a framework, attempt to use
- # the framework's Headers and PrivateHeaders directories
- case ${TK_DEFS} in
- *TK_FRAMEWORK*)
- if test -d "${TK_BIN_DIR}/Headers" -a \
- -d "${TK_BIN_DIR}/PrivateHeaders"; then
- TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}"
- else
- TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`"
- fi
- ;;
- esac
- result="Using ${TK_INCLUDES}"
- else
- if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then
- AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}])
- fi
- result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}"
- fi
- fi
-
- AC_SUBST(TK_TOP_DIR_NATIVE)
- AC_SUBST(TK_XLIB_DIR_NATIVE)
-
- AC_SUBST(TK_INCLUDES)
- AC_MSG_RESULT([${result}])
-])
-
-#------------------------------------------------------------------------
-# TEA_PUBLIC_TK_HEADERS --
-#
-# Locate the installed public Tk header files
-#
-# Arguments:
-# None.
-#
-# Requires:
-# CYGPATH must be set
-#
-# Results:
-#
-# Adds a --with-tkinclude switch to configure.
-# Result is cached.
-#
-# Substitutes the following vars:
-# TK_INCLUDES
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [
- AC_MSG_CHECKING([for Tk public headers])
-
- AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval})
-
- AC_CACHE_VAL(ac_cv_c_tkh, [
- # Use the value from --with-tkinclude, if it was given
-
- if test x"${with_tkinclude}" != x ; then
- if test -f "${with_tkinclude}/tk.h" ; then
- ac_cv_c_tkh=${with_tkinclude}
- else
- AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h])
- fi
- else
- list=""
- if test "`uname -s`" = "Darwin"; then
- # If Tk was built as a framework, attempt to use
- # the framework's Headers directory.
- case ${TK_DEFS} in
- *TK_FRAMEWORK*)
- list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`"
- ;;
- esac
- fi
-
- # Look in the source dir only if Tk is not installed,
- # and in that situation, look there before installed locations.
- if test -f "${TK_BIN_DIR}/Makefile" ; then
- list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`"
- fi
-
- # Check order: pkg --prefix location, Tk's --prefix location,
- # relative to directory of tkConfig.sh, Tcl's --prefix location,
- # relative to directory of tclConfig.sh.
-
- eval "temp_includedir=${includedir}"
- list="$list \
- `ls -d ${temp_includedir} 2>/dev/null` \
- `ls -d ${TK_PREFIX}/include 2>/dev/null` \
- `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \
- `ls -d ${TCL_PREFIX}/include 2>/dev/null` \
- `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`"
- if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then
- list="$list /usr/local/include /usr/include"
- if test x"${TK_INCLUDE_SPEC}" != x ; then
- d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'`
- list="$list `ls -d ${d} 2>/dev/null`"
- fi
- fi
- for i in $list ; do
- if test -f "$i/tk.h" ; then
- ac_cv_c_tkh=$i
- break
- fi
- done
- fi
- ])
-
- # Print a message based on how we determined the include path
-
- if test x"${ac_cv_c_tkh}" = x ; then
- AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude])
- else
- AC_MSG_RESULT([${ac_cv_c_tkh}])
- fi
-
- # Convert to a native path and substitute into the output files.
-
- INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}`
-
- TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\"
-
- AC_SUBST(TK_INCLUDES)
-
- if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then
- # On Windows and Aqua, we need the X compat headers
- AC_MSG_CHECKING([for X11 header files])
- if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then
- INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`"
- TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\"
- AC_SUBST(TK_XINCLUDES)
- fi
- AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}])
- fi
-])
-
-#------------------------------------------------------------------------
-# TEA_PATH_CONFIG --
-#
-# Locate the ${1}Config.sh file and perform a sanity check on
-# the ${1} compile flags. These are used by packages like
-# [incr Tk] that load *Config.sh files from more than Tcl and Tk.
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Adds the following arguments to configure:
-# --with-$1=...
-#
-# Defines the following vars:
-# $1_BIN_DIR Full path to the directory containing
-# the $1Config.sh file
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_PATH_CONFIG], [
- #
- # Ok, lets find the $1 configuration
- # First, look for one uninstalled.
- # the alternative search directory is invoked by --with-$1
- #
-
- if test x"${no_$1}" = x ; then
- # we reset no_$1 in case something fails here
- no_$1=true
- AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval})
- AC_MSG_CHECKING([for $1 configuration])
- AC_CACHE_VAL(ac_cv_c_$1config,[
-
- # First check to see if --with-$1 was specified.
- if test x"${with_$1config}" != x ; then
- case ${with_$1config} in
- */$1Config.sh )
- if test -f ${with_$1config}; then
- AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself])
- with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'`
- fi;;
- esac
- if test -f "${with_$1config}/$1Config.sh" ; then
- ac_cv_c_$1config=`(cd ${with_$1config}; pwd)`
- else
- AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh])
- fi
- fi
-
- # then check for a private $1 installation
- if test x"${ac_cv_c_$1config}" = x ; then
- for i in \
- ../$1 \
- `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \
- `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \
- `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \
- ../../$1 \
- `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \
- `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \
- `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \
- ../../../$1 \
- `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \
- `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \
- `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \
- ${srcdir}/../$1 \
- `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \
- `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \
- `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \
- ; do
- if test -f "$i/$1Config.sh" ; then
- ac_cv_c_$1config=`(cd $i; pwd)`
- break
- fi
- if test -f "$i/unix/$1Config.sh" ; then
- ac_cv_c_$1config=`(cd $i/unix; pwd)`
- break
- fi
- done
- fi
-
- # check in a few common install locations
- if test x"${ac_cv_c_$1config}" = x ; then
- for i in `ls -d ${libdir} 2>/dev/null` \
- `ls -d ${exec_prefix}/lib 2>/dev/null` \
- `ls -d ${prefix}/lib 2>/dev/null` \
- `ls -d /usr/local/lib 2>/dev/null` \
- `ls -d /usr/contrib/lib 2>/dev/null` \
- `ls -d /usr/pkg/lib 2>/dev/null` \
- `ls -d /usr/lib 2>/dev/null` \
- `ls -d /usr/lib64 2>/dev/null` \
- ; do
- if test -f "$i/$1Config.sh" ; then
- ac_cv_c_$1config=`(cd $i; pwd)`
- break
- fi
- done
- fi
- ])
-
- if test x"${ac_cv_c_$1config}" = x ; then
- $1_BIN_DIR="# no $1 configs found"
- AC_MSG_WARN([Cannot find $1 configuration definitions])
- exit 0
- else
- no_$1=
- $1_BIN_DIR=${ac_cv_c_$1config}
- AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh])
- fi
- fi
-])
-
-#------------------------------------------------------------------------
-# TEA_LOAD_CONFIG --
-#
-# Load the $1Config.sh file
-#
-# Arguments:
-#
-# Requires the following vars to be set:
-# $1_BIN_DIR
-#
-# Results:
-#
-# Substitutes the following vars:
-# $1_SRC_DIR
-# $1_LIB_FILE
-# $1_LIB_SPEC
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_LOAD_CONFIG], [
- AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh])
-
- if test -f "${$1_BIN_DIR}/$1Config.sh" ; then
- AC_MSG_RESULT([loading])
- . "${$1_BIN_DIR}/$1Config.sh"
- else
- AC_MSG_RESULT([file not found])
- fi
-
- #
- # If the $1_BIN_DIR is the build directory (not the install directory),
- # then set the common variable name to the value of the build variables.
- # For example, the variable $1_LIB_SPEC will be set to the value
- # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC
- # instead of $1_BUILD_LIB_SPEC since it will work with both an
- # installed and uninstalled version of Tcl.
- #
-
- if test -f "${$1_BIN_DIR}/Makefile" ; then
- AC_MSG_WARN([Found Makefile - using build library specs for $1])
- $1_LIB_SPEC=${$1_BUILD_LIB_SPEC}
- $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC}
- $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH}
- $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC}
- $1_LIBRARY_PATH=${$1_LIBRARY_PATH}
- fi
-
- AC_SUBST($1_VERSION)
- AC_SUBST($1_BIN_DIR)
- AC_SUBST($1_SRC_DIR)
-
- AC_SUBST($1_LIB_FILE)
- AC_SUBST($1_LIB_SPEC)
-
- AC_SUBST($1_STUB_LIB_FILE)
- AC_SUBST($1_STUB_LIB_SPEC)
- AC_SUBST($1_STUB_LIB_PATH)
-
- # Allow the caller to prevent this auto-check by specifying any 2nd arg
- AS_IF([test "x$2" = x], [
- # Check both upper and lower-case variants
- # If a dev wanted non-stubs libs, this function could take an option
- # to not use _STUB in the paths below
- AS_IF([test "x${$1_STUB_LIB_SPEC}" = x],
- [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)],
- [TEA_LOAD_CONFIG_LIB($1_STUB)])
- ])
-])
-
-#------------------------------------------------------------------------
-# TEA_LOAD_CONFIG_LIB --
-#
-# Helper function to load correct library from another extension's
-# ${PACKAGE}Config.sh.
-#
-# Results:
-# Adds to LIBS the appropriate extension library
-#------------------------------------------------------------------------
-AC_DEFUN([TEA_LOAD_CONFIG_LIB], [
- AC_MSG_CHECKING([For $1 library for LIBS])
- # This simplifies the use of stub libraries by automatically adding
- # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS,
- # but this is called before CONFIG_CFLAGS. More importantly, this adds
- # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD.
- if test "x${$1_LIB_SPEC}" != "x" ; then
- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then
- TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"])
- AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}])
- else
- TEA_ADD_LIBS([${$1_LIB_SPEC}])
- AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}])
- fi
- else
- AC_MSG_RESULT([file not found])
- fi
-])
-
-#------------------------------------------------------------------------
-# TEA_EXPORT_CONFIG --
-#
-# Define the data to insert into the ${PACKAGE}Config.sh file
-#
-# Arguments:
-#
-# Requires the following vars to be set:
-# $1
-#
-# Results:
-# Substitutes the following vars:
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_EXPORT_CONFIG], [
- #--------------------------------------------------------------------
- # These are for $1Config.sh
- #--------------------------------------------------------------------
-
- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib)
- eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}"
- if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then
- eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}"
- eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}"
- else
- eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`"
- eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`"
- fi
- $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}"
- $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}"
- $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}"
- $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}"
- $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}"
- $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}"
-
- AC_SUBST($1_BUILD_LIB_SPEC)
- AC_SUBST($1_LIB_SPEC)
- AC_SUBST($1_BUILD_STUB_LIB_SPEC)
- AC_SUBST($1_STUB_LIB_SPEC)
- AC_SUBST($1_BUILD_STUB_LIB_PATH)
- AC_SUBST($1_STUB_LIB_PATH)
-
- AC_SUBST(MAJOR_VERSION)
- AC_SUBST(MINOR_VERSION)
- AC_SUBST(PATCHLEVEL)
-])
-
-
-#------------------------------------------------------------------------
-# TEA_INSTALLER --
-#
-# Configure the installer.
-#
-# Arguments:
-# none
-#
-# Results:
-# Substitutes the following vars:
-# INSTALL
-# INSTALL_DATA_DIR
-# INSTALL_DATA
-# INSTALL_PROGRAM
-# INSTALL_SCRIPT
-# INSTALL_LIBRARY
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_INSTALLER], [
- INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c'
- INSTALL_DATA_DIR='${INSTALL} -d -m 755'
- INSTALL_DATA='${INSTALL} -m 644'
- INSTALL_PROGRAM='${INSTALL} -m 755'
- INSTALL_SCRIPT='${INSTALL} -m 755'
-
- TEA_CONFIG_SYSTEM
- case $system in
- HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;;
- *) INSTALL_LIBRARY='${INSTALL} -m 644' ;;
- esac
-
- AC_SUBST(INSTALL)
- AC_SUBST(INSTALL_DATA_DIR)
- AC_SUBST(INSTALL_DATA)
- AC_SUBST(INSTALL_PROGRAM)
- AC_SUBST(INSTALL_SCRIPT)
- AC_SUBST(INSTALL_LIBRARY)
-])
-
-###
-# Tip 430 - ZipFS Modifications
-###
-#------------------------------------------------------------------------
-# TEA_ZIPFS_SUPPORT
-# Locate a zip encoder installed on the system path, or none.
-#
-# Arguments:
-# none
-#
-# Results:
-# Substitutes the following vars:
-# MACHER_PROG
-# ZIP_PROG
-# ZIP_PROG_OPTIONS
-# ZIP_PROG_VFSSEARCH
-# ZIP_INSTALL_OBJS
-#------------------------------------------------------------------------
-
-AC_DEFUN([TEA_ZIPFS_SUPPORT], [
- MACHER_PROG=""
- ZIP_PROG=""
- ZIP_PROG_OPTIONS=""
- ZIP_PROG_VFSSEARCH=""
- ZIP_INSTALL_OBJS=""
-
- AC_MSG_CHECKING([for macher])
- AC_CACHE_VAL(ac_cv_path_macher, [
- search_path=`echo ${PATH} | sed -e 's/:/ /g'`
- for dir in $search_path ; do
- for j in `ls -r $dir/macher 2> /dev/null` \
- `ls -r $dir/macher 2> /dev/null` ; do
- if test x"$ac_cv_path_macher" = x ; then
- if test -f "$j" ; then
- ac_cv_path_macher=$j
- break
- fi
- fi
- done
- done
- ])
- if test -f "$ac_cv_path_macher" ; then
- MACHER_PROG="$ac_cv_path_macher"
- AC_MSG_RESULT([$MACHER_PROG])
- AC_MSG_RESULT([Found macher in environment])
- fi
- AC_MSG_CHECKING([for zip])
- AC_CACHE_VAL(ac_cv_path_zip, [
- search_path=`echo ${PATH} | sed -e 's/:/ /g'`
- for dir in $search_path ; do
- for j in `ls -r $dir/zip 2> /dev/null` \
- `ls -r $dir/zip 2> /dev/null` ; do
- if test x"$ac_cv_path_zip" = x ; then
- if test -f "$j" ; then
- ac_cv_path_zip=$j
- break
- fi
- fi
- done
- done
- ])
- if test -f "$ac_cv_path_zip" ; then
- ZIP_PROG="$ac_cv_path_zip"
- AC_MSG_RESULT([$ZIP_PROG])
- ZIP_PROG_OPTIONS="-rq"
- ZIP_PROG_VFSSEARCH="*"
- AC_MSG_RESULT([Found INFO Zip in environment])
- # Use standard arguments for zip
- else
- # It is not an error if an installed version of Zip can't be located.
- # We can use the locally distributed minizip instead
- ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}"
- ZIP_PROG_OPTIONS="-o -r"
- ZIP_PROG_VFSSEARCH="*"
- ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}"
- AC_MSG_RESULT([No zip found on PATH. Building minizip])
- fi
- AC_SUBST(MACHER_PROG)
- AC_SUBST(ZIP_PROG)
- AC_SUBST(ZIP_PROG_OPTIONS)
- AC_SUBST(ZIP_PROG_VFSSEARCH)
- AC_SUBST(ZIP_INSTALL_OBJS)
-])
-
-# Local Variables:
-# mode: autoconf
-# End: \ No newline at end of file
diff --git a/contrib/sqlite3/tea/teaish.tcl b/contrib/sqlite3/tea/teaish.tcl
new file mode 100644
index 000000000000..9333495aa3da
--- /dev/null
+++ b/contrib/sqlite3/tea/teaish.tcl
@@ -0,0 +1,565 @@
+# Teaish configure script for the SQLite Tcl extension
+
+#
+# State for disparate config-time pieces.
+#
+array set sqlite__Config [proj-strip-hash-comments {
+ #
+ # The list of feature --flags which the --all flag implies. This
+ # requires special handling in a few places.
+ #
+ all-flag-enables {fts3 fts4 fts5 rtree geopoly}
+
+ # >0 if building in the canonical tree. -1=undetermined
+ is-canonical -1
+}]
+
+#
+# Set up the package info for teaish...
+#
+apply {{dir} {
+ # Figure out the version number...
+ set version ""
+ if {[file exists $dir/../VERSION]} {
+ # The canonical SQLite TEA(ish) build
+ set version [proj-file-content -trim $dir/../VERSION]
+ set ::sqlite__Config(is-canonical) 1
+ set distname sqlite-tcl
+ } elseif {[file exists $dir/generic/tclsqlite3.c]} {
+ # The copy from the teaish tree, used as a dev/test bed before
+ # updating SQLite's tree.
+ set ::sqlite__Config(is-canonical) 0
+ set fd [open $dir/generic/tclsqlite3.c rb]
+ while {[gets $fd line] >=0} {
+ if {[regexp {^#define[ ]+SQLITE_VERSION[ ]+"(3.+)"} \
+ $line - version]} {
+ set distname sqlite-teaish
+ break
+ }
+ }
+ close $fd
+ }
+
+ if {"" eq $version} {
+ proj-fatal "Cannot determine the SQLite version number"
+ }
+
+ proj-assert {$::sqlite__Config(is-canonical) > -1}
+ proj-assert {[string match 3.*.* $version]} \
+ "Unexpected SQLite version: $version"
+
+ set pragmas {}
+ if {$::sqlite__Config(is-canonical)} {
+ # Disable "make dist" in the canonical tree. That tree is
+ # generated from several pieces and creating/testing working
+ # "dist" rules for that sub-build currently feels unnecessary. The
+ # copy in the teaish tree, though, should be able to "make dist".
+ lappend pragmas no-dist
+ } else {
+ lappend pragmas full-dist
+ }
+
+ teaish-pkginfo-set -vars {
+ -name sqlite
+ -name.pkg sqlite3
+ -version $version
+ -name.dist $distname
+ -vsatisfies 8.6-
+ -libDir sqlite$version
+ -pragmas $pragmas
+ }
+}} [teaish-get -dir]
+
+#
+# Must return either an empty string or a list in the form accepted by
+# autosetup's [options] function.
+#
+proc teaish-options {} {
+ # These flags and defaults mostly derive from the historical TEA
+ # build. Some, like ICU, are taken from the canonical SQLite tree.
+ return [subst -nocommands -nobackslashes {
+ with-system-sqlite=0
+ => {Use the system-level SQLite instead of the copy in this tree.
+ Also requires use of --override-sqlite-version so that the build
+ knows what version number to associate with the system-level SQLite.}
+ override-sqlite-version:VERSION
+ => {For use with --with-system-sqlite to set the version number.}
+ threadsafe=1 => {Disable mutexing}
+ with-tempstore:=no => {Use an in-RAM database for temporary tables: never,no,yes,always}
+ load-extension=0 => {Enable loading of external extensions}
+ math=1 => {Disable math functions}
+ json=1 => {Disable JSON functions}
+ fts3 => {Enable the FTS3 extension}
+ fts4 => {Enable the FTS4 extension}
+ fts5 => {Enable the FTS5 extension}
+ update-limit => {Enable the UPDATE/DELETE LIMIT clause}
+ geopoly => {Enable the GEOPOLY extension}
+ rtree => {Enable the RTREE extension}
+ session => {Enable the SESSION extension}
+ all=1 => {Disable $::sqlite__Config(all-flag-enables)}
+ with-icu-ldflags:LDFLAGS
+ => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the
+ ICU libraries. e.g. on Ubuntu systems, try '-licui18n -licuuc -licudata'.}
+ with-icu-cflags:CFLAGS
+ => {Apply extra CFLAGS/CPPFLAGS necessary for building with ICU.
+ e.g. -I/usr/local/include}
+ with-icu-config:=auto
+ => {Enable SQLITE_ENABLE_ICU. Value must be one of: auto, pkg-config,
+ /path/to/icu-config}
+ icu-collations=0
+ => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=...
+ or --with-icu-config}
+ }]
+}
+
+#
+# Gets called by tea-configure-core. Must perform any configuration
+# work needed for this extension.
+#
+proc teaish-configure {} {
+ use teaish/feature
+
+ teaish-src-add -dist -dir generic/tclsqlite3.c
+
+ if {[proj-opt-was-provided override-sqlite-version]} {
+ teaish-pkginfo-set -version [opt-val override-sqlite-version]
+ proj-warn "overriding sqlite version number:" [teaish-pkginfo-get -version]
+ } elseif {[proj-opt-was-provided with-system-sqlite]
+ && [opt-val with-system-sqlite] ne "0"} {
+ proj-fatal "when using --with-system-sqlite also use" \
+ "--override-sqlite-version to specify a library version number."
+ }
+
+ define CFLAGS [proj-get-env CFLAGS {-O2}]
+ sqlite-munge-cflags
+
+ #
+ # Add feature flags from legacy configure.ac which are not covered by
+ # --flags.
+ #
+ sqlite-add-feature-flag {
+ -DSQLITE_3_SUFFIX_ONLY=1
+ -DSQLITE_ENABLE_DESERIALIZE=1
+ -DSQLITE_ENABLE_DBPAGE_VTAB=1
+ -DSQLITE_ENABLE_BYTECODE_VTAB=1
+ -DSQLITE_ENABLE_DBSTAT_VTAB=1
+ }
+
+ if {[opt-bool with-system-sqlite]} {
+ msg-result "Using system-level sqlite3."
+ teaish-cflags-add -DUSE_SYSTEM_SQLITE
+ teaish-ldflags-add -lsqlite3
+ } elseif {$::sqlite__Config(is-canonical)} {
+ teaish-cflags-add -I[teaish-get -dir]/..
+ }
+
+ teaish-check-librt
+ teaish-check-libz
+ sqlite-handle-threadsafe
+ sqlite-handle-tempstore
+ sqlite-handle-load-extension
+ sqlite-handle-math
+ sqlite-handle-icu
+
+ sqlite-handle-common-feature-flags; # must be late in the process
+}; # teaish-configure
+
+define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
+#
+# Adds $args, if not empty, to OPT_FEATURE_FLAGS. This is intended only for holding
+# -DSQLITE_ENABLE/OMIT/... flags, but that is not enforced here.
+proc sqlite-add-feature-flag {args} {
+ if {"" ne $args} {
+ define-append OPT_FEATURE_FLAGS {*}$args
+ }
+}
+
+#
+# Check for log(3) in libm and die with an error if it is not
+# found. $featureName should be the feature name which requires that
+# function (it's used only in error messages). defines LDFLAGS_MATH to
+# the required linker flags (which may be empty even if the math APIs
+# are found, depending on the OS).
+proc sqlite-affirm-have-math {featureName} {
+ if {"" eq [get-define LDFLAGS_MATH ""]} {
+ if {![msg-quiet proj-check-function-in-lib log m]} {
+ user-error "Missing math APIs for $featureName"
+ }
+ set lfl [get-define lib_log ""]
+ undefine lib_log
+ if {"" ne $lfl} {
+ user-notice "Forcing requirement of $lfl for $featureName"
+ }
+ define LDFLAGS_MATH $lfl
+ teaish-ldflags-prepend $lfl
+ }
+}
+
+#
+# Handle various SQLITE_ENABLE/OMIT_... feature flags.
+proc sqlite-handle-common-feature-flags {} {
+ msg-result "Feature flags..."
+ if {![opt-bool all]} {
+ # Special handling for --disable-all
+ foreach flag $::sqlite__Config(all-flag-enables) {
+ if {![proj-opt-was-provided $flag]} {
+ proj-opt-set $flag 0
+ }
+ }
+ }
+ foreach {boolFlag featureFlag ifSetEvalThis} [proj-strip-hash-comments {
+ all {} {
+ # The 'all' option must be first in this list. This impl makes
+ # an effort to only apply flags which the user did not already
+ # apply, so that combinations like (--all --disable-geopoly)
+ # will indeed disable geopoly. There are corner cases where
+ # flags which depend on each other will behave in non-intuitive
+ # ways:
+ #
+ # --all --disable-rtree
+ #
+ # Will NOT disable geopoly, though geopoly depends on rtree.
+ # The --geopoly flag, though, will automatically re-enable
+ # --rtree, so --disable-rtree won't actually disable anything in
+ # that case.
+ foreach k $::sqlite__Config(all-flag-enables) {
+ if {![proj-opt-was-provided $k]} {
+ proj-opt-set $k 1
+ }
+ }
+ }
+ fts3 -DSQLITE_ENABLE_FTS3 {sqlite-affirm-have-math fts3}
+ fts4 -DSQLITE_ENABLE_FTS4 {sqlite-affirm-have-math fts4}
+ fts5 -DSQLITE_ENABLE_FTS5 {sqlite-affirm-have-math fts5}
+ geopoly -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree}
+ rtree -DSQLITE_ENABLE_RTREE {}
+ session {-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK} {}
+ update-limit -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT {}
+ scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
+ }] {
+ if {$boolFlag ni $::autosetup(options)} {
+ # Skip flags which are in the canonical build but not
+ # the autoconf bundle.
+ continue
+ }
+ proj-if-opt-truthy $boolFlag {
+ sqlite-add-feature-flag $featureFlag
+ if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} {
+ msg-result " + $boolFlag"
+ }
+ } {
+ if {"all" ne $boolFlag} {
+ msg-result " - $boolFlag"
+ }
+ }
+ }
+ #
+ # Invert the above loop's logic for some SQLITE_OMIT_... cases. If
+ # config option $boolFlag is false, [sqlite-add-feature-flag
+ # $featureFlag], where $featureFlag is intended to be
+ # -DSQLITE_OMIT_...
+ foreach {boolFlag featureFlag} {
+ json -DSQLITE_OMIT_JSON
+ } {
+ if {[proj-opt-truthy $boolFlag]} {
+ msg-result " + $boolFlag"
+ } else {
+ sqlite-add-feature-flag $featureFlag
+ msg-result " - $boolFlag"
+ }
+ }
+
+ ##
+ # Remove duplicates from the final feature flag sets and show them
+ # to the user.
+ set oFF [get-define OPT_FEATURE_FLAGS]
+ if {"" ne $oFF} {
+ define OPT_FEATURE_FLAGS [lsort -unique $oFF]
+ msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
+ }
+ if {[lsearch [get-define TARGET_DEBUG ""] -DSQLITE_DEBUG=1] > -1} {
+ msg-result "Note: this is a debug build, so performance will suffer."
+ }
+ teaish-cflags-add -define OPT_FEATURE_FLAGS
+}; # sqlite-handle-common-feature-flags
+
+#
+# If --enable-threadsafe is set, this adds -DSQLITE_THREADSAFE=1 to
+# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to the linker flags
+# needed for linking pthread (possibly an empty string). If
+# --enable-threadsafe is not set, adds -DSQLITE_THREADSAFE=0 to
+# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to an empty string.
+#
+# It prepends the flags to the global LDFLAGS.
+proc sqlite-handle-threadsafe {} {
+ msg-checking "Support threadsafe operation? "
+ define LDFLAGS_PTHREAD ""
+ set enable 0
+ if {[proj-opt-was-provided threadsafe]} {
+ proj-if-opt-truthy threadsafe {
+ if {[proj-check-function-in-lib pthread_create pthread]
+ && [proj-check-function-in-lib pthread_mutexattr_init pthread]} {
+ incr enable
+ set ldf [get-define lib_pthread_create]
+ define LDFLAGS_PTHREAD $ldf
+ teaish-ldflags-prepend $ldf
+ undefine lib_pthread_create
+ undefine lib_pthread_mutexattr_init
+ } else {
+ user-error "Missing required pthread libraries. Use --disable-threadsafe to disable this check."
+ }
+ # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if
+ # found because it's in -lc on some platforms.
+ } {
+ msg-result "Disabled using --disable-threadsafe"
+ }
+ } else {
+ #
+ # If user does not specify --[disable-]threadsafe then select a
+ # default based on whether it looks like Tcl has threading
+ # support.
+ #
+ catch {
+ scan [exec echo {puts [tcl::pkgconfig get threaded]} | [get-define TCLSH_CMD]] \
+ %d enable
+ }
+ if {$enable} {
+ set flagName "--threadsafe"
+ set lblAbled "enabled"
+ msg-result yes
+ } else {
+ set flagName "--disable-threadsafe"
+ set lblAbled "disabled"
+ msg-result no
+ }
+ msg-result "Defaulting to ${flagName} because Tcl has threading ${lblAbled}."
+ # ^^^ We (probably) don't need to link against -lpthread in the
+ # is-enabled case. We might in the case of static linking. Unsure.
+ }
+ sqlite-add-feature-flag -DSQLITE_THREADSAFE=${enable}
+ return $enable
+}
+
+#
+# Handles the --enable-load-extension flag. Returns 1 if the support
+# is enabled, else 0. If support for that feature is not found, a
+# fatal error is triggered if --enable-load-extension is explicitly
+# provided, else a loud warning is instead emitted. If
+# --disable-load-extension is used, no check is performed.
+#
+# Makes the following environment changes:
+#
+# - defines LDFLAGS_DLOPEN to any linker flags needed for this
+# feature. It may legally be empty on some systems where dlopen()
+# is in libc.
+#
+# - If the feature is not available, adds
+# -DSQLITE_OMIT_LOAD_EXTENSION=1 to the feature flags list.
+proc sqlite-handle-load-extension {} {
+ define LDFLAGS_DLOPEN ""
+ set found 0
+ proj-if-opt-truthy load-extension {
+ set found [proj-check-function-in-lib dlopen dl]
+ if {$found} {
+ set ldf [get-define lib_dlopen]
+ define LDFLAGS_DLOPEN $ldf
+ teaish-ldflags-prepend $ldf
+ undefine lib_dlopen
+ } else {
+ if {[proj-opt-was-provided load-extension]} {
+ # Explicit --enable-load-extension: fail if not found
+ proj-indented-notice -error {
+ --enable-load-extension was provided but dlopen()
+ not found. Use --disable-load-extension to bypass this
+ check.
+ }
+ } else {
+ # It was implicitly enabled: warn if not found
+ proj-indented-notice {
+ WARNING: dlopen() not found, so loadable module support will
+ be disabled. Use --disable-load-extension to bypass this
+ check.
+ }
+ }
+ }
+ }
+ if {$found} {
+ msg-result "Loadable extension support enabled."
+ } else {
+ msg-result "Disabling loadable extension support. Use --enable-load-extension to enable them."
+ sqlite-add-feature-flag -DSQLITE_OMIT_LOAD_EXTENSION=1
+ }
+ return $found
+}
+
+#
+# ICU - International Components for Unicode
+#
+# Handles these flags:
+#
+# --with-icu-ldflags=LDFLAGS
+# --with-icu-cflags=CFLAGS
+# --with-icu-config[=auto | pkg-config | /path/to/icu-config]
+# --enable-icu-collations
+#
+# --with-icu-config values:
+#
+# - auto: use the first one of (pkg-config, icu-config) found on the
+# system.
+# - pkg-config: use only pkg-config to determine flags
+# - /path/to/icu-config: use that to determine flags
+#
+# If --with-icu-config is used as neither pkg-config nor icu-config
+# are found, fail fatally.
+#
+# If both --with-icu-ldflags and --with-icu-config are provided, they
+# are cumulative. If neither are provided, icu-collations is not
+# honored and a warning is emitted if it is provided.
+#
+# Design note: though we could automatically enable ICU if the
+# icu-config binary or (pkg-config icu-io) are found, we specifically
+# do not. ICU is always an opt-in feature.
+proc sqlite-handle-icu {} {
+ define LDFLAGS_LIBICU [join [opt-val with-icu-ldflags ""]]
+ define CFLAGS_LIBICU [join [opt-val with-icu-cflags ""]]
+ if {[proj-opt-was-provided with-icu-config]} {
+ msg-result "Checking for ICU support..."
+ set icuConfigBin [opt-val with-icu-config]
+ set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config
+ if {$icuConfigBin in {auto pkg-config}} {
+ uplevel 3 { use pkg-config }
+ if {[pkg-config-init 0] && [pkg-config icu-io]} {
+ # Maintenance reminder: historical docs say to use both of
+ # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has
+ # all of them on tested OSes.
+ set tryIcuConfigBin 0
+ define LDFLAGS_LIBICU [get-define PKG_ICU_IO_LDFLAGS]
+ define-append LDFLAGS_LIBICU [get-define PKG_ICU_IO_LIBS]
+ define CFLAGS_LIBICU [get-define PKG_ICU_IO_CFLAGS]
+ } elseif {"pkg-config" eq $icuConfigBin} {
+ proj-fatal "pkg-config cannot find package icu-io"
+ } else {
+ proj-assert {"auto" eq $icuConfigBin}
+ }
+ }
+ if {$tryIcuConfigBin} {
+ if {"auto" eq $icuConfigBin} {
+ set icuConfigBin [proj-first-bin-of \
+ /usr/local/bin/icu-config \
+ /usr/bin/icu-config]
+ if {"" eq $icuConfigBin} {
+ proj-indented-notice -error {
+ --with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary.
+ On Ubuntu-like systems try:
+ --with-icu-ldflags='-licui18n -licuuc -licudata'
+ }
+ }
+ }
+ if {[file-isexec $icuConfigBin]} {
+ set x [exec $icuConfigBin --ldflags]
+ if {"" eq $x} {
+ proj-indented-notice -error \
+ [subst {
+ $icuConfigBin --ldflags returned no data.
+ On Ubuntu-like systems try:
+ --with-icu-ldflags='-licui18n -licuuc -licudata'
+ }]
+ }
+ define-append LDFLAGS_LIBICU $x
+ set x [exec $icuConfigBin --cppflags]
+ define-append CFLAGS_LIBICU $x
+ } else {
+ proj-fatal "--with-icu-config=$icuConfigBin does not refer to an executable"
+ }
+ }
+ }
+ set ldflags [define LDFLAGS_LIBICU [string trim [get-define LDFLAGS_LIBICU]]]
+ set cflags [define CFLAGS_LIBICU [string trim [get-define CFLAGS_LIBICU]]]
+ if {"" ne $ldflags} {
+ sqlite-add-feature-flag -DSQLITE_ENABLE_ICU
+ msg-result "Enabling ICU support with flags: $ldflags $cflags"
+ if {[opt-bool icu-collations]} {
+ msg-result "Enabling ICU collations."
+ sqlite-add-feature-flag -DSQLITE_ENABLE_ICU_COLLATIONS
+ }
+ teaish-ldflags-prepend $ldflags
+ teaish-cflags-add $cflags
+ } elseif {[opt-bool icu-collations]} {
+ proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
+ } else {
+ msg-result "ICU support is disabled."
+ }
+}; # sqlite-handle-icu
+
+
+#
+# Handles the --with-tempstore flag.
+#
+# The test fixture likes to set SQLITE_TEMP_STORE on its own, so do
+# not set that feature flag unless it was explicitly provided to the
+# configure script.
+proc sqlite-handle-tempstore {} {
+ if {[proj-opt-was-provided with-tempstore]} {
+ set ts [opt-val with-tempstore no]
+ set tsn 1
+ msg-checking "Use an in-RAM database for temporary tables? "
+ switch -exact -- $ts {
+ never { set tsn 0 }
+ no { set tsn 1 }
+ yes { set tsn 2 }
+ always { set tsn 3 }
+ default {
+ user-error "Invalid --with-tempstore value '$ts'. Use one of: never, no, yes, always"
+ }
+ }
+ msg-result $ts
+ sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn
+ }
+}
+
+#
+# Handles the --enable-math flag.
+proc sqlite-handle-math {} {
+ proj-if-opt-truthy math {
+ if {![proj-check-function-in-lib ceil m]} {
+ user-error "Cannot find libm functions. Use --disable-math to bypass this."
+ }
+ set lfl [get-define lib_ceil]
+ undefine lib_ceil
+ define LDFLAGS_MATH $lfl
+ teaish-ldflags-prepend $lfl
+ sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS
+ msg-result "Enabling math SQL functions"
+ } {
+ define LDFLAGS_MATH ""
+ msg-result "Disabling math SQL functions"
+ }
+}
+
+#
+# Move -DSQLITE_OMIT... and -DSQLITE_ENABLE... flags from CFLAGS and
+# CPPFLAGS to OPT_FEATURE_FLAGS and remove them from BUILD_CFLAGS.
+proc sqlite-munge-cflags {} {
+ # Move CFLAGS and CPPFLAGS entries matching -DSQLITE_OMIT* and
+ # -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived
+ # from the pre-3.48 build.
+ #
+ # If any configure flags for features are in conflict with
+ # CFLAGS/CPPFLAGS-specified feature flags, all bets are off. There
+ # are no guarantees about which one will take precedence.
+ foreach flagDef {CFLAGS CPPFLAGS} {
+ set tmp ""
+ foreach cf [get-define $flagDef ""] {
+ switch -glob -- $cf {
+ -DSQLITE_OMIT* -
+ -DSQLITE_ENABLE* {
+ sqlite-add-feature-flag $cf
+ }
+ default {
+ lappend tmp $cf
+ }
+ }
+ }
+ define $flagDef $tmp
+ }
+}
diff --git a/contrib/sqlite3/tea/teaish.test.tcl b/contrib/sqlite3/tea/teaish.test.tcl
new file mode 100644
index 000000000000..b63c9426e395
--- /dev/null
+++ b/contrib/sqlite3/tea/teaish.test.tcl
@@ -0,0 +1,14 @@
+test-expect 1.0-open {
+ sqlite3 db :memory:
+} {}
+
+test-assert 1.1-version-3.x {
+ [string match 3.* [db eval {select sqlite_version()}]]
+}
+
+test-expect 1.2-select {
+ db eval {select 'hi, world',1,2,3}
+} {{hi, world} 1 2 3}
+
+
+test-expect 99.0-db-close {db close} {}
diff --git a/contrib/sqlite3/tea/win/makefile.vc b/contrib/sqlite3/tea/win/makefile.vc
deleted file mode 100644
index da56e811fcd0..000000000000
--- a/contrib/sqlite3/tea/win/makefile.vc
+++ /dev/null
@@ -1,430 +0,0 @@
-# makefile.vc -- -*- Makefile -*-
-#
-# Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+)
-#
-# This makefile is based upon the Tcl 8.4 Makefile.vc and modified to
-# make it suitable as a general package makefile. Look for the word EDIT
-# which marks sections that may need modification. As a minumum you will
-# need to change the PROJECT, DOTVERSION and DLLOBJS variables to values
-# relevant to your package.
-#
-# See the file "license.terms" for information on usage and redistribution
-# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
-#
-# Copyright (c) 1995-1996 Sun Microsystems, Inc.
-# Copyright (c) 1998-2000 Ajuba Solutions.
-# Copyright (c) 2001 ActiveState Corporation.
-# Copyright (c) 2001-2002 David Gravereaux.
-# Copyright (c) 2003 Pat Thoyts
-#
-#-------------------------------------------------------------------------
-# RCS: @(#)$Id: makefile.vc,v 1.4 2004/07/26 08:22:05 patthoyts Exp $
-#-------------------------------------------------------------------------
-
-!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR)
-MSG = ^
-You will need to run vcvars32.bat from Developer Studio, first, to setup^
-the environment. Jump to this line to read the new instructions.
-!error $(MSG)
-!endif
-
-#------------------------------------------------------------------------------
-# HOW TO USE this makefile:
-#
-# 1) It is now necessary to have %MSVCDir% set in the environment. This is
-# used as a check to see if vcvars32.bat had been run prior to running
-# nmake or during the installation of Microsoft Visual C++, MSVCDir had
-# been set globally and the PATH adjusted. Either way is valid.
-#
-# You'll need to run vcvars32.bat contained in the MsDev's vc(98)/bin
-# directory to setup the proper environment, if needed, for your current
-# setup. This is a needed bootstrap requirement and allows the swapping of
-# different environments to be easier.
-#
-# 2) To use the Platform SDK (not expressly needed), run setenv.bat after
-# vcvars32.bat according to the instructions for it. This can also turn on
-# the 64-bit compiler, if your SDK has it.
-#
-# 3) Targets are:
-# all -- Builds everything.
-# <project> -- Builds the project (eg: nmake sample)
-# test -- Builds and runs the test suite.
-# install -- Installs the built binaries and libraries to $(INSTALLDIR)
-# in an appropriate subdirectory.
-# clean/realclean/distclean -- varying levels of cleaning.
-#
-# 4) Macros usable on the commandline:
-# INSTALLDIR=<path>
-# Sets where to install Tcl from the built binaries.
-# C:\Progra~1\Tcl is assumed when not specified.
-#
-# OPTS=static,msvcrt,staticpkg,threads,symbols,profile,loimpact,none
-# Sets special options for the core. The default is for none.
-# Any combination of the above may be used (comma separated).
-# 'none' will over-ride everything to nothing.
-#
-# static = Builds a static library of the core instead of a
-# dll. The shell will be static (and large), as well.
-# msvcrt = Effects the static option only to switch it from
-# using libcmt(d) as the C runtime [by default] to
-# msvcrt(d). This is useful for static embedding
-# support.
-# staticpkg = Effects the static option only to switch
-# tclshXX.exe to have the dde and reg extension linked
-# inside it.
-# threads = Turns on full multithreading support.
-# thrdalloc = Use the thread allocator (shared global free pool).
-# symbols = Adds symbols for step debugging.
-# profile = Adds profiling hooks. Map file is assumed.
-# loimpact = Adds a flag for how NT treats the heap to keep memory
-# in use, low. This is said to impact alloc performance.
-#
-# STATS=memdbg,compdbg,none
-# Sets optional memory and bytecode compiler debugging code added
-# to the core. The default is for none. Any combination of the
-# above may be used (comma separated). 'none' will over-ride
-# everything to nothing.
-#
-# memdbg = Enables the debugging memory allocator.
-# compdbg = Enables byte compilation logging.
-#
-# MACHINE=(IX86|IA64|ALPHA)
-# Set the machine type used for the compiler, linker, and
-# resource compiler. This hook is needed to tell the tools
-# when alternate platforms are requested. IX86 is the default
-# when not specified.
-#
-# TMP_DIR=<path>
-# OUT_DIR=<path>
-# Hooks to allow the intermediate and output directories to be
-# changed. $(OUT_DIR) is assumed to be
-# $(BINROOT)\(Release|Debug) based on if symbols are requested.
-# $(TMP_DIR) will de $(OUT_DIR)\<buildtype> by default.
-#
-# TESTPAT=<file>
-# Reads the tests requested to be run from this file.
-#
-# CFG_ENCODING=encoding
-# name of encoding for configuration information. Defaults
-# to cp1252
-#
-# 5) Examples:
-#
-# Basic syntax of calling nmake looks like this:
-# nmake [-nologo] -f makefile.vc [target|macrodef [target|macrodef] [...]]
-#
-# Standard (no frills)
-# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat
-# Setting environment for using Microsoft Visual C++ tools.
-# c:\tcl_src\win\>nmake -f makefile.vc all
-# c:\tcl_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl
-#
-# Building for Win64
-# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat
-# Setting environment for using Microsoft Visual C++ tools.
-# c:\tcl_src\win\>c:\progra~1\platfo~1\setenv.bat /pre64 /RETAIL
-# Targeting Windows pre64 RETAIL
-# c:\tcl_src\win\>nmake -f makefile.vc MACHINE=IA64
-#
-#------------------------------------------------------------------------------
-#==============================================================================
-###############################################################################
-#------------------------------------------------------------------------------
-
-!if !exist("makefile.vc")
-MSG = ^
-You must run this makefile only from the directory it is in.^
-Please `cd` to its location first.
-!error $(MSG)
-!endif
-
-#-------------------------------------------------------------------------
-# Project specific information (EDIT)
-#
-# You should edit this with the name and version of your project. This
-# information is used to generate the name of the package library and
-# it's install location.
-#
-# For example, the sample extension is going to build sample04.dll and
-# would install it into $(INSTALLDIR)\lib\sample04
-#
-# You need to specify the object files that need to be linked into your
-# binary here.
-#
-#-------------------------------------------------------------------------
-
-PROJECT = sqlite3
-!include "rules.vc"
-
-# nmakehelp -V <file> <tag> will search the file for tag, skips until a
-# number and returns all character until a character not in [0-9.ab]
-# is read.
-
-!if [echo REM = This file is generated from Makefile.vc > versions.vc]
-!endif
-# get project version from row "AC_INIT([sqlite], [3.x.y])"
-!if [echo DOTVERSION = \>> versions.vc] \
- && [nmakehlp -V ..\configure.ac AC_INIT >> versions.vc]
-!endif
-!include "versions.vc"
-
-VERSION = $(DOTVERSION:.=)
-STUBPREFIX = $(PROJECT)stub
-
-#-------------------------------------------------------------------------
-# Target names and paths ( shouldn't need changing )
-#-------------------------------------------------------------------------
-
-BINROOT = .
-ROOT = ..
-
-PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
-PRJLIBNAME = $(PROJECT).$(EXT)
-PRJLIB = $(OUT_DIR)\$(PRJLIBNAME)
-
-PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib
-PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME)
-
-### Make sure we use backslash only.
-PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION)
-LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-INCLUDE_INSTALL_DIR = $(_TCLDIR)\include
-
-### The following paths CANNOT have spaces in them.
-GENERICDIR = $(ROOT)\generic
-WINDIR = $(ROOT)\win
-LIBDIR = $(ROOT)\library
-DOCDIR = $(ROOT)\doc
-TOOLSDIR = $(ROOT)\tools
-COMPATDIR = $(ROOT)\compat
-
-### Figure out where the primary source code file(s) is/are.
-!if exist("$(ROOT)\..\..\sqlite3.c") && exist("$(ROOT)\..\..\src\tclsqlite.c")
-SQL_INCLUDES = -I"$(ROOT)\..\.."
-SQLITE_SRCDIR = $(ROOT)\..\..
-TCLSQLITE_SRCDIR = $(ROOT)\..\..\src
-DLLOBJS = $(TMP_DIR)\sqlite3.obj $(TMP_DIR)\tclsqlite.obj
-!else
-TCLSQLITE_SRCDIR = $(ROOT)\generic
-DLLOBJS = $(TMP_DIR)\tclsqlite3.obj
-!endif
-
-#---------------------------------------------------------------------
-# Compile flags
-#---------------------------------------------------------------------
-
-!if !$(DEBUG)
-!if $(OPTIMIZING)
-### This cranks the optimization level to maximize speed
-cdebug = -O2 -Op -Gs
-!else
-cdebug =
-!endif
-!else if "$(MACHINE)" == "IA64"
-### Warnings are too many, can't support warnings into errors.
-cdebug = -Z7 -Od -GZ
-!else
-cdebug = -Z7 -WX -Od -GZ
-!endif
-
-### Declarations common to all compiler options
-cflags = -nologo -c -W3 -D_CRT_SECURE_NO_WARNINGS -YX -Fp$(TMP_DIR)^\
-
-!if $(MSVCRT)
-!if $(DEBUG)
-crt = -MDd
-!else
-crt = -MD
-!endif
-!else
-!if $(DEBUG)
-crt = -MTd
-!else
-crt = -MT
-!endif
-!endif
-
-INCLUDES = $(SQL_INCLUDES) $(TCL_INCLUDES) -I"$(WINDIR)" \
- -I"$(GENERICDIR)" -I"$(ROOT)\.."
-BASE_CLFAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) \
- -DSQLITE_3_SUFFIX_ONLY=1 -DSQLITE_ENABLE_RTREE=1 \
- -DSQLITE_ENABLE_FTS3=1 -DSQLITE_OMIT_DEPRECATED=1 \
- -DSQLITE_ENABLE_FTS4=1 \
- -DSQLITE_ENABLE_FTS5=1 \
- -DSQLITE_3_SUFFIX_ONLY=1 \
- -DSQLITE_ENABLE_RTREE=1 \
- -DSQLITE_ENABLE_GEOPOLY=1 \
- -DSQLITE_ENABLE_MATH_FUNCTIONS=1 \
- -DSQLITE_ENABLE_DESERIALIZE=1 \
- -DSQLITE_ENABLE_DBPAGE_VTAB=1 \
- -DSQLITE_ENABLE_BYTECODE_VTAB=1 \
- -DSQLITE_ENABLE_DBSTAT_VTAB=1
-
-CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE -DSQLITE_ENABLE_FTS3=1
-TCL_CFLAGS = -DBUILD_sqlite -DUSE_TCL_STUBS \
- -DPACKAGE_VERSION="\"$(DOTVERSION)\"" $(BASE_CLFAGS) \
- $(OPTDEFINES)
-
-#---------------------------------------------------------------------
-# Link flags
-#---------------------------------------------------------------------
-
-!if $(DEBUG)
-ldebug = -debug:full -debugtype:cv
-!else
-ldebug = -release -opt:ref -opt:icf,3
-!endif
-
-### Declarations common to all linker options
-lflags = -nologo -machine:$(MACHINE) $(ldebug)
-
-!if $(PROFILE)
-lflags = $(lflags) -profile
-!endif
-
-!if $(ALIGN98_HACK) && !$(STATIC_BUILD)
-### Align sections for PE size savings.
-lflags = $(lflags) -opt:nowin98
-!else if !$(ALIGN98_HACK) && $(STATIC_BUILD)
-### Align sections for speed in loading by choosing the virtual page size.
-lflags = $(lflags) -align:4096
-!endif
-
-!if $(LOIMPACT)
-lflags = $(lflags) -ws:aggressive
-!endif
-
-dlllflags = $(lflags) -dll
-conlflags = $(lflags) -subsystem:console
-guilflags = $(lflags) -subsystem:windows
-baselibs = $(TCLSTUBLIB)
-
-#---------------------------------------------------------------------
-# TclTest flags
-#---------------------------------------------------------------------
-
-!IF "$(TESTPAT)" != ""
-TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT)
-!ENDIF
-
-#---------------------------------------------------------------------
-# Project specific targets (EDIT)
-#---------------------------------------------------------------------
-
-all: setup $(PROJECT)
-$(PROJECT): setup $(PRJLIB)
-install: install-binaries install-libraries install-docs
-
-# Tests need to ensure we load the right dll file we
-# have to handle the output differently on Win9x.
-#
-!if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE"
-test: setup $(PROJECT)
- set TCL_LIBRARY=$(ROOT)/library
- $(TCLSH) <<
-load $(PRJLIB:\=/)
-cd "$(ROOT)/tests"
-set argv "$(TESTFLAGS)"
-source all.tcl
-<<
-!else
-test: setup $(PROJECT)
- echo Please wait while the test results are collected
- set TCL_LIBRARY=$(ROOT)/library
- $(TCLSH) << >tests.log
-load $(PRJLIB:\=/)
-cd "$(ROOT)/tests"
-set argv "$(TESTFLAGS)"
-source all.tcl
-<<
- type tests.log | more
-!endif
-
-setup:
- @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR)
- @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR)
-
-$(PRJLIB): $(DLLOBJS)
- $(link32) $(dlllflags) -out:$@ $(baselibs) @<<
-$**
-<<
- -@del $*.exp
-
-$(PRJSTUBLIB): $(PRJSTUBOBJS)
- $(lib32) -nologo -out:$@ $(PRJSTUBOBJS)
-
-#---------------------------------------------------------------------
-# Implicit rules
-#---------------------------------------------------------------------
-
-$(TMP_DIR)\sqlite3.obj: $(SQLITE_SRCDIR)\sqlite3.c
- $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
- -c $(SQLITE_SRCDIR)\sqlite3.c
-
-$(TMP_DIR)\tclsqlite.obj: $(TCLSQLITE_SRCDIR)\tclsqlite.c
- $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
- -c $(TCLSQLITE_SRCDIR)\tclsqlite.c
-
-$(TMP_DIR)\tclsqlite3.obj: $(TCLSQLITE_SRCDIR)\tclsqlite3.c
- $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
- -c $(TCLSQLITE_SRCDIR)\tclsqlite3.c
-
-{$(WINDIR)}.rc{$(TMP_DIR)}.res:
- $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \
-!if $(DEBUG)
- -d DEBUG \
-!endif
-!if $(TCL_THREADS)
- -d TCL_THREADS \
-!endif
-!if $(STATIC_BUILD)
- -d STATIC_BUILD \
-!endif
- $<
-
-.SUFFIXES:
-.SUFFIXES:.c .rc
-
-#---------------------------------------------------------------------
-# Installation. (EDIT)
-#
-# You may need to modify this section to reflect the final distribution
-# of your files and possibly to generate documentation.
-#
-#---------------------------------------------------------------------
-
-install-binaries:
- @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)'
- @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
- @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL
-
-install-libraries:
- @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)'
- @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)"
- @echo Installing package index in '$(SCRIPT_INSTALL_DIR)'
- @type << >"$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
-package ifneeded $(PROJECT) $(DOTVERSION) \
- [list load [file join $$dir $(PRJLIBNAME)] sqlite3]
-<<
-
-install-docs:
- @echo Installing documentation files to '$(DOC_INSTALL_DIR)'
- @if exist $(DOCDIR) $(CPY) $(DOCDIR)\*.n "$(DOC_INSTALL_DIR)"
-
-#---------------------------------------------------------------------
-# Clean up
-#---------------------------------------------------------------------
-
-clean:
- @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR)
- @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc
-
-realclean: clean
- @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR)
-
-distclean: realclean
- @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe
- @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj
diff --git a/contrib/sqlite3/tea/win/nmakehlp.c b/contrib/sqlite3/tea/win/nmakehlp.c
deleted file mode 100644
index 2dc33cc657b4..000000000000
--- a/contrib/sqlite3/tea/win/nmakehlp.c
+++ /dev/null
@@ -1,815 +0,0 @@
-/*
- * ----------------------------------------------------------------------------
- * nmakehlp.c --
- *
- * This is used to fix limitations within nmake and the environment.
- *
- * Copyright (c) 2002 by David Gravereaux.
- * Copyright (c) 2006 by Pat Thoyts
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- * ----------------------------------------------------------------------------
- */
-
-#define _CRT_SECURE_NO_DEPRECATE
-#include <windows.h>
-#ifdef _MSC_VER
-#pragma comment (lib, "user32.lib")
-#pragma comment (lib, "kernel32.lib")
-#endif
-#include <stdio.h>
-#include <math.h>
-
-/*
- * This library is required for x64 builds with _some_ versions of MSVC
- */
-#if defined(_M_IA64) || defined(_M_AMD64)
-#if _MSC_VER >= 1400 && _MSC_VER < 1500
-#pragma comment(lib, "bufferoverflowU")
-#endif
-#endif
-
-/* ISO hack for dumb VC++ */
-#ifdef _MSC_VER
-#define snprintf _snprintf
-#endif
-
-
-/* protos */
-
-static int CheckForCompilerFeature(const char *option);
-static int CheckForLinkerFeature(char **options, int count);
-static int IsIn(const char *string, const char *substring);
-static int SubstituteFile(const char *substs, const char *filename);
-static int QualifyPath(const char *path);
-static int LocateDependency(const char *keyfile);
-static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
-static DWORD WINAPI ReadFromPipe(LPVOID args);
-
-/* globals */
-
-#define CHUNK 25
-#define STATICBUFFERSIZE 1000
-typedef struct {
- HANDLE pipe;
- char buffer[STATICBUFFERSIZE];
-} pipeinfo;
-
-pipeinfo Out = {INVALID_HANDLE_VALUE, ""};
-pipeinfo Err = {INVALID_HANDLE_VALUE, ""};
-
-/*
- * exitcodes: 0 == no, 1 == yes, 2 == error
- */
-
-int
-main(
- int argc,
- char *argv[])
-{
- char msg[300];
- DWORD dwWritten;
- int chars;
- const char *s;
-
- /*
- * Make sure children (cl.exe and link.exe) are kept quiet.
- */
-
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
-
- /*
- * Make sure the compiler and linker aren't effected by the outside world.
- */
-
- SetEnvironmentVariable("CL", "");
- SetEnvironmentVariable("LINK", "");
-
- if (argc > 1 && *argv[1] == '-') {
- switch (*(argv[1]+1)) {
- case 'c':
- if (argc != 3) {
- chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -c <compiler option>\n"
- "Tests for whether cl.exe supports an option\n"
- "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
- &dwWritten, NULL);
- return 2;
- }
- return CheckForCompilerFeature(argv[2]);
- case 'l':
- if (argc < 3) {
- chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -l <linker option> ?<mandatory option> ...?\n"
- "Tests for whether link.exe supports an option\n"
- "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
- &dwWritten, NULL);
- return 2;
- }
- return CheckForLinkerFeature(&argv[2], argc-2);
- case 'f':
- if (argc == 2) {
- chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -f <string> <substring>\n"
- "Find a substring within another\n"
- "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
- &dwWritten, NULL);
- return 2;
- } else if (argc == 3) {
- /*
- * If the string is blank, there is no match.
- */
-
- return 0;
- } else {
- return IsIn(argv[2], argv[3]);
- }
- case 's':
- if (argc == 2) {
- chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -s <substitutions file> <file>\n"
- "Perform a set of string map type substutitions on a file\n"
- "exitcodes: 0\n",
- argv[0]);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
- &dwWritten, NULL);
- return 2;
- }
- return SubstituteFile(argv[2], argv[3]);
- case 'V':
- if (argc != 4) {
- chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -V filename matchstring\n"
- "Extract a version from a file:\n"
- "eg: pkgIndex.tcl \"package ifneeded http\"",
- argv[0]);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
- &dwWritten, NULL);
- return 0;
- }
- s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0');
- if (s && *s) {
- printf("%s\n", s);
- return 0;
- } else
- return 1; /* Version not found. Return non-0 exit code */
-
- case 'Q':
- if (argc != 3) {
- chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -Q path\n"
- "Emit the fully qualified path\n"
- "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
- &dwWritten, NULL);
- return 2;
- }
- return QualifyPath(argv[2]);
-
- case 'L':
- if (argc != 3) {
- chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -L keypath\n"
- "Emit the fully qualified path of directory containing keypath\n"
- "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
- &dwWritten, NULL);
- return 2;
- }
- return LocateDependency(argv[2]);
- }
- }
- chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -c|-f|-l|-Q|-s|-V ...\n"
- "This is a little helper app to equalize shell differences between WinNT and\n"
- "Win9x and get nmake.exe to accomplish its job.\n",
- argv[0]);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
- return 2;
-}
-
-static int
-CheckForCompilerFeature(
- const char *option)
-{
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- SECURITY_ATTRIBUTES sa;
- DWORD threadID;
- char msg[300];
- BOOL ok;
- HANDLE hProcess, h, pipeThreads[2];
- char cmdline[100];
-
- hProcess = GetCurrentProcess();
-
- ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
- ZeroMemory(&si, sizeof(STARTUPINFO));
- si.cb = sizeof(STARTUPINFO);
- si.dwFlags = STARTF_USESTDHANDLES;
- si.hStdInput = INVALID_HANDLE_VALUE;
-
- ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = FALSE;
-
- /*
- * Create a non-inheritible pipe.
- */
-
- CreatePipe(&Out.pipe, &h, &sa, 0);
-
- /*
- * Dupe the write side, make it inheritible, and close the original.
- */
-
- DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
- DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
-
- /*
- * Same as above, but for the error side.
- */
-
- CreatePipe(&Err.pipe, &h, &sa, 0);
- DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
- DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
-
- /*
- * Base command line.
- */
-
- lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch ");
-
- /*
- * Append our option for testing
- */
-
- lstrcat(cmdline, option);
-
- /*
- * Filename to compile, which exists, but is nothing and empty.
- */
-
- lstrcat(cmdline, " .\\nul");
-
- ok = CreateProcess(
- NULL, /* Module name. */
- cmdline, /* Command line. */
- NULL, /* Process handle not inheritable. */
- NULL, /* Thread handle not inheritable. */
- TRUE, /* yes, inherit handles. */
- DETACHED_PROCESS, /* No console for you. */
- NULL, /* Use parent's environment block. */
- NULL, /* Use parent's starting directory. */
- &si, /* Pointer to STARTUPINFO structure. */
- &pi); /* Pointer to PROCESS_INFORMATION structure. */
-
- if (!ok) {
- DWORD err = GetLastError();
- int chars = snprintf(msg, sizeof(msg) - 1,
- "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
-
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
- FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
- (300-chars), 0);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
- return 2;
- }
-
- /*
- * Close our references to the write handles that have now been inherited.
- */
-
- CloseHandle(si.hStdOutput);
- CloseHandle(si.hStdError);
-
- WaitForInputIdle(pi.hProcess, 5000);
- CloseHandle(pi.hThread);
-
- /*
- * Start the pipe reader threads.
- */
-
- pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
- pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
-
- /*
- * Block waiting for the process to end.
- */
-
- WaitForSingleObject(pi.hProcess, INFINITE);
- CloseHandle(pi.hProcess);
-
- /*
- * Wait for our pipe to get done reading, should it be a little slow.
- */
-
- WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
- CloseHandle(pipeThreads[0]);
- CloseHandle(pipeThreads[1]);
-
- /*
- * Look for the commandline warning code in both streams.
- * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
- */
-
- return !(strstr(Out.buffer, "D4002") != NULL
- || strstr(Err.buffer, "D4002") != NULL
- || strstr(Out.buffer, "D9002") != NULL
- || strstr(Err.buffer, "D9002") != NULL
- || strstr(Out.buffer, "D2021") != NULL
- || strstr(Err.buffer, "D2021") != NULL);
-}
-
-static int
-CheckForLinkerFeature(
- char **options,
- int count)
-{
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- SECURITY_ATTRIBUTES sa;
- DWORD threadID;
- char msg[300];
- BOOL ok;
- HANDLE hProcess, h, pipeThreads[2];
- int i;
- char cmdline[255];
-
- hProcess = GetCurrentProcess();
-
- ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
- ZeroMemory(&si, sizeof(STARTUPINFO));
- si.cb = sizeof(STARTUPINFO);
- si.dwFlags = STARTF_USESTDHANDLES;
- si.hStdInput = INVALID_HANDLE_VALUE;
-
- ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
-
- /*
- * Create a non-inheritible pipe.
- */
-
- CreatePipe(&Out.pipe, &h, &sa, 0);
-
- /*
- * Dupe the write side, make it inheritible, and close the original.
- */
-
- DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
- DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
-
- /*
- * Same as above, but for the error side.
- */
-
- CreatePipe(&Err.pipe, &h, &sa, 0);
- DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
- DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
-
- /*
- * Base command line.
- */
-
- lstrcpy(cmdline, "link.exe -nologo ");
-
- /*
- * Append our option for testing.
- */
-
- for (i = 0; i < count; i++) {
- lstrcat(cmdline, " \"");
- lstrcat(cmdline, options[i]);
- lstrcat(cmdline, "\"");
- }
-
- ok = CreateProcess(
- NULL, /* Module name. */
- cmdline, /* Command line. */
- NULL, /* Process handle not inheritable. */
- NULL, /* Thread handle not inheritable. */
- TRUE, /* yes, inherit handles. */
- DETACHED_PROCESS, /* No console for you. */
- NULL, /* Use parent's environment block. */
- NULL, /* Use parent's starting directory. */
- &si, /* Pointer to STARTUPINFO structure. */
- &pi); /* Pointer to PROCESS_INFORMATION structure. */
-
- if (!ok) {
- DWORD err = GetLastError();
- int chars = snprintf(msg, sizeof(msg) - 1,
- "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
-
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
- FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
- (300-chars), 0);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
- return 2;
- }
-
- /*
- * Close our references to the write handles that have now been inherited.
- */
-
- CloseHandle(si.hStdOutput);
- CloseHandle(si.hStdError);
-
- WaitForInputIdle(pi.hProcess, 5000);
- CloseHandle(pi.hThread);
-
- /*
- * Start the pipe reader threads.
- */
-
- pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
- pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
-
- /*
- * Block waiting for the process to end.
- */
-
- WaitForSingleObject(pi.hProcess, INFINITE);
- CloseHandle(pi.hProcess);
-
- /*
- * Wait for our pipe to get done reading, should it be a little slow.
- */
-
- WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
- CloseHandle(pipeThreads[0]);
- CloseHandle(pipeThreads[1]);
-
- /*
- * Look for the commandline warning code in the stderr stream.
- */
-
- return !(strstr(Out.buffer, "LNK1117") != NULL ||
- strstr(Err.buffer, "LNK1117") != NULL ||
- strstr(Out.buffer, "LNK4044") != NULL ||
- strstr(Err.buffer, "LNK4044") != NULL ||
- strstr(Out.buffer, "LNK4224") != NULL ||
- strstr(Err.buffer, "LNK4224") != NULL);
-}
-
-static DWORD WINAPI
-ReadFromPipe(
- LPVOID args)
-{
- pipeinfo *pi = (pipeinfo *) args;
- char *lastBuf = pi->buffer;
- DWORD dwRead;
- BOOL ok;
-
- again:
- if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
- CloseHandle(pi->pipe);
- return (DWORD)-1;
- }
- ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
- if (!ok || dwRead == 0) {
- CloseHandle(pi->pipe);
- return 0;
- }
- lastBuf += dwRead;
- goto again;
-
- return 0; /* makes the compiler happy */
-}
-
-static int
-IsIn(
- const char *string,
- const char *substring)
-{
- return (strstr(string, substring) != NULL);
-}
-
-/*
- * GetVersionFromFile --
- * Looks for a match string in a file and then returns the version
- * following the match where a version is anything acceptable to
- * package provide or package ifneeded.
- */
-
-static const char *
-GetVersionFromFile(
- const char *filename,
- const char *match,
- int numdots)
-{
- static char szBuffer[100];
- char *szResult = NULL;
- FILE *fp = fopen(filename, "rt");
-
- if (fp != NULL) {
- /*
- * Read data until we see our match string.
- */
-
- while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
- LPSTR p, q;
-
- p = strstr(szBuffer, match);
- if (p != NULL) {
- /*
- * Skip to first digit after the match.
- */
-
- p += strlen(match);
- while (*p && !isdigit((unsigned char)*p)) {
- ++p;
- }
-
- /*
- * Find ending whitespace.
- */
-
- q = p;
- while (*q && (strchr("0123456789.ab", *q)) && (((!strchr(".ab", *q)
- && !strchr("ab", q[-1])) || --numdots))) {
- ++q;
- }
-
- *q = 0;
- szResult = p;
- break;
- }
- }
- fclose(fp);
- }
- return szResult;
-}
-
-/*
- * List helpers for the SubstituteFile function
- */
-
-typedef struct list_item_t {
- struct list_item_t *nextPtr;
- char * key;
- char * value;
-} list_item_t;
-
-/* insert a list item into the list (list may be null) */
-static list_item_t *
-list_insert(list_item_t **listPtrPtr, const char *key, const char *value)
-{
- list_item_t *itemPtr = (list_item_t *)malloc(sizeof(list_item_t));
- if (itemPtr) {
- itemPtr->key = strdup(key);
- itemPtr->value = strdup(value);
- itemPtr->nextPtr = NULL;
-
- while(*listPtrPtr) {
- listPtrPtr = &(*listPtrPtr)->nextPtr;
- }
- *listPtrPtr = itemPtr;
- }
- return itemPtr;
-}
-
-static void
-list_free(list_item_t **listPtrPtr)
-{
- list_item_t *tmpPtr, *listPtr = *listPtrPtr;
- while (listPtr) {
- tmpPtr = listPtr;
- listPtr = listPtr->nextPtr;
- free(tmpPtr->key);
- free(tmpPtr->value);
- free(tmpPtr);
- }
-}
-
-/*
- * SubstituteFile --
- * As windows doesn't provide anything useful like sed and it's unreliable
- * to use the tclsh you are building against (consider x-platform builds -
- * eg compiling AMD64 target from IX86) we provide a simple substitution
- * option here to handle autoconf style substitutions.
- * The substitution file is whitespace and line delimited. The file should
- * consist of lines matching the regular expression:
- * \s*\S+\s+\S*$
- *
- * Usage is something like:
- * nmakehlp -S << $** > $@
- * @PACKAGE_NAME@ $(PACKAGE_NAME)
- * @PACKAGE_VERSION@ $(PACKAGE_VERSION)
- * <<
- */
-
-static int
-SubstituteFile(
- const char *substitutions,
- const char *filename)
-{
- static char szBuffer[1024], szCopy[1024];
- list_item_t *substPtr = NULL;
- FILE *fp, *sp;
-
- fp = fopen(filename, "rt");
- if (fp != NULL) {
-
- /*
- * Build a list of substutitions from the first filename
- */
-
- sp = fopen(substitutions, "rt");
- if (sp != NULL) {
- while (fgets(szBuffer, sizeof(szBuffer), sp) != NULL) {
- unsigned char *ks, *ke, *vs, *ve;
- ks = (unsigned char*)szBuffer;
- while (ks && *ks && isspace(*ks)) ++ks;
- ke = ks;
- while (ke && *ke && !isspace(*ke)) ++ke;
- vs = ke;
- while (vs && *vs && isspace(*vs)) ++vs;
- ve = vs;
- while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve;
- *ke = 0, *ve = 0;
- list_insert(&substPtr, (char*)ks, (char*)vs);
- }
- fclose(sp);
- }
-
- /* debug: dump the list */
-#ifndef NDEBUG
- {
- int n = 0;
- list_item_t *p = NULL;
- for (p = substPtr; p != NULL; p = p->nextPtr, ++n) {
- fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value);
- }
- }
-#endif
-
- /*
- * Run the substitutions over each line of the input
- */
-
- while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
- list_item_t *p = NULL;
- for (p = substPtr; p != NULL; p = p->nextPtr) {
- char *m = strstr(szBuffer, p->key);
- if (m) {
- char *cp, *op, *sp;
- cp = szCopy;
- op = szBuffer;
- while (op != m) *cp++ = *op++;
- sp = p->value;
- while (sp && *sp) *cp++ = *sp++;
- op += strlen(p->key);
- while (*op) *cp++ = *op++;
- *cp = 0;
- memcpy(szBuffer, szCopy, sizeof(szCopy));
- }
- }
- printf("%s", szBuffer);
- }
-
- list_free(&substPtr);
- }
- fclose(fp);
- return 0;
-}
-
-BOOL FileExists(LPCTSTR szPath)
-{
-#ifndef INVALID_FILE_ATTRIBUTES
- #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
-#endif
- DWORD pathAttr = GetFileAttributes(szPath);
- return (pathAttr != INVALID_FILE_ATTRIBUTES &&
- !(pathAttr & FILE_ATTRIBUTE_DIRECTORY));
-}
-
-
-/*
- * QualifyPath --
- *
- * This composes the current working directory with a provided path
- * and returns the fully qualified and normalized path.
- * Mostly needed to setup paths for testing.
- */
-
-static int
-QualifyPath(
- const char *szPath)
-{
- char szCwd[MAX_PATH + 1];
-
- GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL);
- printf("%s\n", szCwd);
- return 0;
-}
-
-/*
- * Implements LocateDependency for a single directory. See that command
- * for an explanation.
- * Returns 0 if found after printing the directory.
- * Returns 1 if not found but no errors.
- * Returns 2 on any kind of error
- * Basically, these are used as exit codes for the process.
- */
-static int LocateDependencyHelper(const char *dir, const char *keypath)
-{
- HANDLE hSearch;
- char path[MAX_PATH+1];
- size_t dirlen;
- int keylen, ret;
- WIN32_FIND_DATA finfo;
-
- if (dir == NULL || keypath == NULL)
- return 2; /* Have no real error reporting mechanism into nmake */
- dirlen = strlen(dir);
- if ((dirlen + 3) > sizeof(path))
- return 2;
- strncpy(path, dir, dirlen);
- strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */
- keylen = strlen(keypath);
-
-#if 0 /* This function is not available in Visual C++ 6 */
- /*
- * Use numerics 0 -> FindExInfoStandard,
- * 1 -> FindExSearchLimitToDirectories,
- * as these are not defined in Visual C++ 6
- */
- hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
-#else
- hSearch = FindFirstFile(path, &finfo);
-#endif
- if (hSearch == INVALID_HANDLE_VALUE)
- return 1; /* Not found */
-
- /* Loop through all subdirs checking if the keypath is under there */
- ret = 1; /* Assume not found */
- do {
- int sublen;
- /*
- * We need to check it is a directory despite the
- * FindExSearchLimitToDirectories in the above call. See SDK docs
- */
- if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
- continue;
- sublen = strlen(finfo.cFileName);
- if ((dirlen+1+sublen+1+keylen+1) > sizeof(path))
- continue; /* Path does not fit, assume not matched */
- strncpy(path+dirlen+1, finfo.cFileName, sublen);
- path[dirlen+1+sublen] = '\\';
- strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
- if (FileExists(path)) {
- /* Found a match, print to stdout */
- path[dirlen+1+sublen] = '\0';
- QualifyPath(path);
- ret = 0;
- break;
- }
- } while (FindNextFile(hSearch, &finfo));
- FindClose(hSearch);
- return ret;
-}
-
-/*
- * LocateDependency --
- *
- * Locates a dependency for a package.
- * keypath - a relative path within the package directory
- * that is used to confirm it is the correct directory.
- * The search path for the package directory is currently only
- * the parent and grandparent of the current working directory.
- * If found, the command prints
- * name_DIRPATH=<full path of located directory>
- * and returns 0. If not found, does not print anything and returns 1.
- */
-static int LocateDependency(const char *keypath)
-{
- size_t i;
- int ret;
- static const char *paths[] = {"..", "..\\..", "..\\..\\.."};
-
- for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) {
- ret = LocateDependencyHelper(paths[i], keypath);
- if (ret == 0)
- return ret;
- }
- return ret;
-}
-
-
-/*
- * Local variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * indent-tabs-mode: t
- * tab-width: 8
- * End:
- */
diff --git a/contrib/sqlite3/tea/win/rules.vc b/contrib/sqlite3/tea/win/rules.vc
deleted file mode 100644
index 99471053c8c0..000000000000
--- a/contrib/sqlite3/tea/win/rules.vc
+++ /dev/null
@@ -1,711 +0,0 @@
-#------------------------------------------------------------------------------
-# rules.vc --
-#
-# Microsoft Visual C++ makefile include for decoding the commandline
-# macros. This file does not need editing to build Tcl.
-#
-# See the file "license.terms" for information on usage and redistribution
-# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
-#
-# Copyright (c) 2001-2003 David Gravereaux.
-# Copyright (c) 2003-2008 Patrick Thoyts
-#------------------------------------------------------------------------------
-
-!ifndef _RULES_VC
-_RULES_VC = 1
-
-cc32 = $(CC) # built-in default.
-link32 = link
-lib32 = lib
-rc32 = $(RC) # built-in default.
-
-!ifndef INSTALLDIR
-### Assume the normal default.
-_INSTALLDIR = C:\Program Files\Tcl
-!else
-### Fix the path separators.
-_INSTALLDIR = $(INSTALLDIR:/=\)
-!endif
-
-#----------------------------------------------------------
-# Set the proper copy method to avoid overwrite questions
-# to the user when copying files and selecting the right
-# "delete all" method.
-#----------------------------------------------------------
-
-!if "$(OS)" == "Windows_NT"
-RMDIR = rmdir /S /Q
-ERRNULL = 2>NUL
-!if ![ver | find "4.0" > nul]
-CPY = echo y | xcopy /i >NUL
-COPY = copy >NUL
-!else
-CPY = xcopy /i /y >NUL
-COPY = copy /y >NUL
-!endif
-!else # "$(OS)" != "Windows_NT"
-CPY = xcopy /i >_JUNK.OUT # On Win98 NUL does not work here.
-COPY = copy >_JUNK.OUT # On Win98 NUL does not work here.
-RMDIR = deltree /Y
-NULL = \NUL # Used in testing directory existence
-ERRNULL = >NUL # Win9x shell cannot redirect stderr
-!endif
-MKDIR = mkdir
-
-#------------------------------------------------------------------------------
-# Determine the host and target architectures and compiler version.
-#------------------------------------------------------------------------------
-
-_HASH=^#
-_VC_MANIFEST_EMBED_EXE=
-_VC_MANIFEST_EMBED_DLL=
-VCVER=0
-!if ![echo VCVERSION=_MSC_VER > vercl.x] \
- && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \
- && ![echo ARCH=IX86 >> vercl.x] \
- && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \
- && ![echo ARCH=AMD64 >> vercl.x] \
- && ![echo $(_HASH)endif >> vercl.x] \
- && ![cl -nologo -TC -P vercl.x $(ERRNULL)]
-!include vercl.i
-!if ![echo VCVER= ^\> vercl.vc] \
- && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc]
-!include vercl.vc
-!endif
-!endif
-!if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc]
-!endif
-
-!if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86]
-NATIVE_ARCH=IX86
-!else
-NATIVE_ARCH=AMD64
-!endif
-
-# Since MSVC8 we must deal with manifest resources.
-!if $(VCVERSION) >= 1400
-_VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1
-_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2
-!endif
-
-!ifndef MACHINE
-MACHINE=$(ARCH)
-!endif
-
-!ifndef CFG_ENCODING
-CFG_ENCODING = \"cp1252\"
-!endif
-
-!message ===============================================================================
-
-#----------------------------------------------------------
-# build the helper app we need to overcome nmake's limiting
-# environment.
-#----------------------------------------------------------
-
-!if !exist(nmakehlp.exe)
-!if [$(cc32) -nologo nmakehlp.c -link -subsystem:console > nul]
-!endif
-!endif
-
-#----------------------------------------------------------
-# Test for compiler features
-#----------------------------------------------------------
-
-### test for optimizations
-!if [nmakehlp -c -Ot]
-!message *** Compiler has 'Optimizations'
-OPTIMIZING = 1
-!else
-!message *** Compiler does not have 'Optimizations'
-OPTIMIZING = 0
-!endif
-
-OPTIMIZATIONS =
-
-!if [nmakehlp -c -Ot]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot
-!endif
-
-!if [nmakehlp -c -Oi]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi
-!endif
-
-!if [nmakehlp -c -Op]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -Op
-!endif
-
-!if [nmakehlp -c -fp:strict]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:strict
-!endif
-
-!if [nmakehlp -c -Gs]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs
-!endif
-
-!if [nmakehlp -c -GS]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -GS
-!endif
-
-!if [nmakehlp -c -GL]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -GL
-!endif
-
-DEBUGFLAGS =
-
-!if [nmakehlp -c -RTC1]
-DEBUGFLAGS = $(DEBUGFLAGS) -RTC1
-!elseif [nmakehlp -c -GZ]
-DEBUGFLAGS = $(DEBUGFLAGS) -GZ
-!endif
-
-COMPILERFLAGS =-W3 -DUNICODE -D_UNICODE
-
-# In v13 -GL and -YX are incompatible.
-!if [nmakehlp -c -YX]
-!if ![nmakehlp -c -GL]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -YX
-!endif
-!endif
-
-!if "$(MACHINE)" == "IX86"
-### test for pentium errata
-!if [nmakehlp -c -QI0f]
-!message *** Compiler has 'Pentium 0x0f fix'
-COMPILERFLAGS = $(COMPILERFLAGS) -QI0f
-!else
-!message *** Compiler does not have 'Pentium 0x0f fix'
-!endif
-!endif
-
-!if "$(MACHINE)" == "IA64"
-### test for Itanium errata
-!if [nmakehlp -c -QIA64_Bx]
-!message *** Compiler has 'B-stepping errata workarounds'
-COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx
-!else
-!message *** Compiler does not have 'B-stepping errata workarounds'
-!endif
-!endif
-
-!if "$(MACHINE)" == "IX86"
-### test for -align:4096, when align:512 will do.
-!if [nmakehlp -l -opt:nowin98]
-!message *** Linker has 'Win98 alignment problem'
-ALIGN98_HACK = 1
-!else
-!message *** Linker does not have 'Win98 alignment problem'
-ALIGN98_HACK = 0
-!endif
-!else
-ALIGN98_HACK = 0
-!endif
-
-LINKERFLAGS =
-
-!if [nmakehlp -l -ltcg]
-LINKERFLAGS =-ltcg
-!endif
-
-#----------------------------------------------------------
-# Decode the options requested.
-#----------------------------------------------------------
-
-!if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"]
-STATIC_BUILD = 0
-TCL_THREADS = 1
-DEBUG = 0
-SYMBOLS = 0
-PROFILE = 0
-PGO = 0
-MSVCRT = 0
-LOIMPACT = 0
-TCL_USE_STATIC_PACKAGES = 0
-USE_THREAD_ALLOC = 1
-UNCHECKED = 0
-!else
-!if [nmakehlp -f $(OPTS) "static"]
-!message *** Doing static
-STATIC_BUILD = 1
-!else
-STATIC_BUILD = 0
-!endif
-!if [nmakehlp -f $(OPTS) "msvcrt"]
-!message *** Doing msvcrt
-MSVCRT = 1
-!else
-MSVCRT = 0
-!endif
-!if [nmakehlp -f $(OPTS) "staticpkg"]
-!message *** Doing staticpkg
-TCL_USE_STATIC_PACKAGES = 1
-!else
-TCL_USE_STATIC_PACKAGES = 0
-!endif
-!if [nmakehlp -f $(OPTS) "nothreads"]
-!message *** Compile explicitly for non-threaded tcl
-TCL_THREADS = 0
-!else
-TCL_THREADS = 1
-USE_THREAD_ALLOC= 1
-!endif
-!if [nmakehlp -f $(OPTS) "symbols"]
-!message *** Doing symbols
-DEBUG = 1
-!else
-DEBUG = 0
-!endif
-!if [nmakehlp -f $(OPTS) "pdbs"]
-!message *** Doing pdbs
-SYMBOLS = 1
-!else
-SYMBOLS = 0
-!endif
-!if [nmakehlp -f $(OPTS) "profile"]
-!message *** Doing profile
-PROFILE = 1
-!else
-PROFILE = 0
-!endif
-!if [nmakehlp -f $(OPTS) "pgi"]
-!message *** Doing profile guided optimization instrumentation
-PGO = 1
-!elseif [nmakehlp -f $(OPTS) "pgo"]
-!message *** Doing profile guided optimization
-PGO = 2
-!else
-PGO = 0
-!endif
-!if [nmakehlp -f $(OPTS) "loimpact"]
-!message *** Doing loimpact
-LOIMPACT = 1
-!else
-LOIMPACT = 0
-!endif
-!if [nmakehlp -f $(OPTS) "thrdalloc"]
-!message *** Doing thrdalloc
-USE_THREAD_ALLOC = 1
-!endif
-!if [nmakehlp -f $(OPTS) "tclalloc"]
-!message *** Doing tclalloc
-USE_THREAD_ALLOC = 0
-!endif
-!if [nmakehlp -f $(OPTS) "unchecked"]
-!message *** Doing unchecked
-UNCHECKED = 1
-!else
-UNCHECKED = 0
-!endif
-!endif
-
-
-!if !$(STATIC_BUILD)
-# Make sure we don't build overly fat DLLs.
-MSVCRT = 1
-# We shouldn't statically put the extensions inside the shell when dynamic.
-TCL_USE_STATIC_PACKAGES = 0
-!endif
-
-
-#----------------------------------------------------------
-# Figure-out how to name our intermediate and output directories.
-# We wouldn't want different builds to use the same .obj files
-# by accident.
-#----------------------------------------------------------
-
-#----------------------------------------
-# Naming convention:
-# t = full thread support.
-# s = static library (as opposed to an
-# import library)
-# g = linked to the debug enabled C
-# run-time.
-# x = special static build when it
-# links to the dynamic C run-time.
-#----------------------------------------
-SUFX = tsgx
-
-!if $(DEBUG)
-BUILDDIRTOP = Debug
-!else
-BUILDDIRTOP = Release
-!endif
-
-!if "$(MACHINE)" != "IX86"
-BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE)
-!endif
-!if $(VCVER) > 6
-BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER)
-!endif
-
-!if !$(DEBUG) || $(DEBUG) && $(UNCHECKED)
-SUFX = $(SUFX:g=)
-!endif
-
-TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX
-
-!if !$(STATIC_BUILD)
-TMP_DIRFULL = $(TMP_DIRFULL:Static=)
-SUFX = $(SUFX:s=)
-EXT = dll
-!if $(MSVCRT)
-TMP_DIRFULL = $(TMP_DIRFULL:X=)
-SUFX = $(SUFX:x=)
-!endif
-!else
-TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=)
-EXT = lib
-!if !$(MSVCRT)
-TMP_DIRFULL = $(TMP_DIRFULL:X=)
-SUFX = $(SUFX:x=)
-!endif
-!endif
-
-!if !$(TCL_THREADS)
-TMP_DIRFULL = $(TMP_DIRFULL:Threaded=)
-SUFX = $(SUFX:t=)
-!endif
-
-!ifndef TMP_DIR
-TMP_DIR = $(TMP_DIRFULL)
-!ifndef OUT_DIR
-OUT_DIR = .\$(BUILDDIRTOP)
-!endif
-!else
-!ifndef OUT_DIR
-OUT_DIR = $(TMP_DIR)
-!endif
-!endif
-
-
-#----------------------------------------------------------
-# Decode the statistics requested.
-#----------------------------------------------------------
-
-!if "$(STATS)" == "" || [nmakehlp -f "$(STATS)" "none"]
-TCL_MEM_DEBUG = 0
-TCL_COMPILE_DEBUG = 0
-!else
-!if [nmakehlp -f $(STATS) "memdbg"]
-!message *** Doing memdbg
-TCL_MEM_DEBUG = 1
-!else
-TCL_MEM_DEBUG = 0
-!endif
-!if [nmakehlp -f $(STATS) "compdbg"]
-!message *** Doing compdbg
-TCL_COMPILE_DEBUG = 1
-!else
-TCL_COMPILE_DEBUG = 0
-!endif
-!endif
-
-
-#----------------------------------------------------------
-# Decode the checks requested.
-#----------------------------------------------------------
-
-!if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"]
-TCL_NO_DEPRECATED = 0
-WARNINGS = -W3
-!else
-!if [nmakehlp -f $(CHECKS) "nodep"]
-!message *** Doing nodep check
-TCL_NO_DEPRECATED = 1
-!else
-TCL_NO_DEPRECATED = 0
-!endif
-!if [nmakehlp -f $(CHECKS) "fullwarn"]
-!message *** Doing full warnings check
-WARNINGS = -W4
-!if [nmakehlp -l -warn:3]
-LINKERFLAGS = $(LINKERFLAGS) -warn:3
-!endif
-!else
-WARNINGS = -W3
-!endif
-!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64]
-!message *** Doing 64bit portability warnings
-WARNINGS = $(WARNINGS) -Wp64
-!endif
-!endif
-
-!if $(PGO) > 1
-!if [nmakehlp -l -ltcg:pgoptimize]
-LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize
-!else
-MSG=^
-This compiler does not support profile guided optimization.
-!error $(MSG)
-!endif
-!elseif $(PGO) > 0
-!if [nmakehlp -l -ltcg:pginstrument]
-LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument
-!else
-MSG=^
-This compiler does not support profile guided optimization.
-!error $(MSG)
-!endif
-!endif
-
-#----------------------------------------------------------
-# Set our defines now armed with our options.
-#----------------------------------------------------------
-
-OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) -DSTDC_HEADERS
-
-!if $(TCL_MEM_DEBUG)
-OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG
-!endif
-!if $(TCL_COMPILE_DEBUG)
-OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS
-!endif
-!if $(TCL_THREADS)
-OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1
-!if $(USE_THREAD_ALLOC)
-OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1
-!endif
-!endif
-!if $(STATIC_BUILD)
-OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD
-!endif
-!if $(TCL_NO_DEPRECATED)
-OPTDEFINES = $(OPTDEFINES) -DTCL_NO_DEPRECATED
-!endif
-
-!if !$(DEBUG)
-OPTDEFINES = $(OPTDEFINES) -DNDEBUG
-!if $(OPTIMIZING)
-OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED
-!endif
-!endif
-!if $(PROFILE)
-OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED
-!endif
-!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64"
-OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT
-!endif
-!if $(VCVERSION) < 1300
-OPTDEFINES = $(OPTDEFINES) -DNO_STRTOI64
-!endif
-
-#----------------------------------------------------------
-# Locate the Tcl headers to build against
-#----------------------------------------------------------
-
-!if "$(PROJECT)" == "tcl"
-
-_TCL_H = ..\generic\tcl.h
-
-!else
-
-# If INSTALLDIR set to tcl root dir then reset to the lib dir.
-!if exist("$(_INSTALLDIR)\include\tcl.h")
-_INSTALLDIR=$(_INSTALLDIR)\lib
-!endif
-
-!if !defined(TCLDIR)
-!if exist("$(_INSTALLDIR)\..\include\tcl.h")
-TCLINSTALL = 1
-_TCLDIR = $(_INSTALLDIR)\..
-_TCL_H = $(_INSTALLDIR)\..\include\tcl.h
-TCLDIR = $(_INSTALLDIR)\..
-!else
-MSG=^
-Failed to find tcl.h. Set the TCLDIR macro.
-!error $(MSG)
-!endif
-!else
-_TCLDIR = $(TCLDIR:/=\)
-!if exist("$(_TCLDIR)\include\tcl.h")
-TCLINSTALL = 1
-_TCL_H = $(_TCLDIR)\include\tcl.h
-!elseif exist("$(_TCLDIR)\generic\tcl.h")
-TCLINSTALL = 0
-_TCL_H = $(_TCLDIR)\generic\tcl.h
-!else
-MSG =^
-Failed to find tcl.h. The TCLDIR macro does not appear correct.
-!error $(MSG)
-!endif
-!endif
-!endif
-
-#--------------------------------------------------------------
-# Extract various version numbers from tcl headers
-# The generated file is then included in the makefile.
-#--------------------------------------------------------------
-
-!if [echo REM = This file is generated from rules.vc > versions.vc]
-!endif
-!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" TCL_MAJOR_VERSION >> versions.vc]
-!endif
-!if [echo TCL_MINOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc]
-!endif
-!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc]
-!endif
-
-# If building the tcl core then we need additional package versions
-!if "$(PROJECT)" == "tcl"
-!if [echo PKG_HTTP_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\http\pkgIndex.tcl http >> versions.vc]
-!endif
-!if [echo PKG_TCLTEST_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\tcltest\pkgIndex.tcl tcltest >> versions.vc]
-!endif
-!if [echo PKG_MSGCAT_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\msgcat\pkgIndex.tcl msgcat >> versions.vc]
-!endif
-!if [echo PKG_PLATFORM_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform " >> versions.vc]
-!endif
-!if [echo PKG_SHELL_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform::shell" >> versions.vc]
-!endif
-!if [echo PKG_DDE_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\dde\pkgIndex.tcl "dde " >> versions.vc]
-!endif
-!if [echo PKG_REG_VER =\>> versions.vc] \
- && [nmakehlp -V ..\library\reg\pkgIndex.tcl registry >> versions.vc]
-!endif
-!endif
-
-!include versions.vc
-
-#--------------------------------------------------------------
-# Setup tcl version dependent stuff headers
-#--------------------------------------------------------------
-
-!if "$(PROJECT)" != "tcl"
-
-TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION)
-
-!if $(TCL_VERSION) < 81
-TCL_DOES_STUBS = 0
-!else
-TCL_DOES_STUBS = 1
-!endif
-
-!if $(TCLINSTALL)
-TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe"
-!if !exist($(TCLSH)) && $(TCL_THREADS)
-TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX).exe"
-!endif
-TCLSTUBLIB = "$(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib"
-TCLIMPLIB = "$(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib"
-TCL_LIBRARY = $(_TCLDIR)\lib
-TCLREGLIB = "$(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib"
-TCLDDELIB = "$(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib"
-COFFBASE = \must\have\tcl\sources\to\build\this\target
-TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target
-TCL_INCLUDES = -I"$(_TCLDIR)\include"
-!else
-TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe"
-!if !exist($(TCLSH)) && $(TCL_THREADS)
-TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX).exe"
-!endif
-TCLSTUBLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib"
-TCLIMPLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib"
-TCL_LIBRARY = $(_TCLDIR)\library
-TCLREGLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib"
-TCLDDELIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib"
-COFFBASE = "$(_TCLDIR)\win\coffbase.txt"
-TCLTOOLSDIR = $(_TCLDIR)\tools
-TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win"
-!endif
-
-!endif
-
-#-------------------------------------------------------------------------
-# Locate the Tk headers to build against
-#-------------------------------------------------------------------------
-
-!if "$(PROJECT)" == "tk"
-_TK_H = ..\generic\tk.h
-_INSTALLDIR = $(_INSTALLDIR)\..
-!endif
-
-!ifdef PROJECT_REQUIRES_TK
-!if !defined(TKDIR)
-!if exist("$(_INSTALLDIR)\..\include\tk.h")
-TKINSTALL = 1
-_TKDIR = $(_INSTALLDIR)\..
-_TK_H = $(_TKDIR)\include\tk.h
-TKDIR = $(_TKDIR)
-!elseif exist("$(_TCLDIR)\include\tk.h")
-TKINSTALL = 1
-_TKDIR = $(_TCLDIR)
-_TK_H = $(_TKDIR)\include\tk.h
-TKDIR = $(_TKDIR)
-!endif
-!else
-_TKDIR = $(TKDIR:/=\)
-!if exist("$(_TKDIR)\include\tk.h")
-TKINSTALL = 1
-_TK_H = $(_TKDIR)\include\tk.h
-!elseif exist("$(_TKDIR)\generic\tk.h")
-TKINSTALL = 0
-_TK_H = $(_TKDIR)\generic\tk.h
-!else
-MSG =^
-Failed to find tk.h. The TKDIR macro does not appear correct.
-!error $(MSG)
-!endif
-!endif
-!endif
-
-#-------------------------------------------------------------------------
-# Extract Tk version numbers
-#-------------------------------------------------------------------------
-
-!if defined(PROJECT_REQUIRES_TK) || "$(PROJECT)" == "tk"
-
-!if [echo TK_MAJOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V $(_TK_H) TK_MAJOR_VERSION >> versions.vc]
-!endif
-!if [echo TK_MINOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc]
-!endif
-!if [echo TK_PATCH_LEVEL = \>> versions.vc] \
- && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc]
-!endif
-
-!include versions.vc
-
-TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)
-TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION)
-
-!if "$(PROJECT)" != "tk"
-!if $(TKINSTALL)
-WISH = "$(_TKDIR)\bin\wish$(TK_VERSION)$(SUFX).exe"
-TKSTUBLIB = "$(_TKDIR)\lib\tkstub$(TK_VERSION).lib"
-TKIMPLIB = "$(_TKDIR)\lib\tk$(TK_VERSION)$(SUFX).lib"
-TK_INCLUDES = -I"$(_TKDIR)\include"
-!else
-WISH = "$(_TKDIR)\win\$(BUILDDIRTOP)\wish$(TCL_VERSION)$(SUFX).exe"
-TKSTUBLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tkstub$(TCL_VERSION).lib"
-TKIMPLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tk$(TCL_VERSION)$(SUFX).lib"
-TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib"
-!endif
-!endif
-
-!endif
-
-#----------------------------------------------------------
-# Display stats being used.
-#----------------------------------------------------------
-
-!message *** Intermediate directory will be '$(TMP_DIR)'
-!message *** Output directory will be '$(OUT_DIR)'
-!message *** Suffix for binaries will be '$(SUFX)'
-!message *** Optional defines are '$(OPTDEFINES)'
-!message *** Compiler version $(VCVER). Target machine is $(MACHINE)
-!message *** Host architecture is $(NATIVE_ARCH)
-!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)'
-!message *** Link options '$(LINKERFLAGS)'
-
-!endif
-
diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c
index f5814a43da54..a6ec3d8e4e21 100644
--- a/contrib/tzcode/localtime.c
+++ b/contrib/tzcode/localtime.c
@@ -18,6 +18,7 @@
#ifndef DETECT_TZ_CHANGES_INTERVAL
#define DETECT_TZ_CHANGES_INTERVAL 61
#endif
+int __tz_change_interval = DETECT_TZ_CHANGES_INTERVAL;
#include <sys/stat.h>
#endif
#include <fcntl.h>
@@ -408,10 +409,8 @@ change_in_tz(const char *name)
static char old_name[PATH_MAX];
static struct stat old_sb;
struct stat sb;
- int error;
- error = stat(name, &sb);
- if (error != 0)
+ if (stat(name, &sb) != 0)
return -1;
if (strcmp(name, old_name) != 0) {
@@ -510,13 +509,13 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
* 'doextend' to ignore TZDEFRULES; the change_in_tz()
* function can only keep state for a single file.
*/
- int ret = change_in_tz(name);
- if (ret <= 0) {
- /*
- * Returns an errno value if there was an error,
- * and 0 if the timezone had not changed.
- */
+ switch (change_in_tz(name)) {
+ case -1:
return errno;
+ case 0:
+ return 0;
+ case 1:
+ break;
}
}
fid = _open(name, O_RDONLY | O_BINARY);
@@ -1376,22 +1375,13 @@ recheck_tzdata()
{
static time_t last_checked;
struct timespec now;
- time_t current_time;
- int error;
- /*
- * We want to recheck the timezone file every 61 sec.
- */
- error = clock_gettime(CLOCK_MONOTONIC, &now);
- if (error < 0) {
- /* XXX: Can we somehow report this? */
+ if (clock_gettime(CLOCK_MONOTONIC, &now) < 0)
return 0;
- }
- current_time = now.tv_sec;
- if ((current_time - last_checked > DETECT_TZ_CHANGES_INTERVAL) ||
- (last_checked > current_time)) {
- last_checked = current_time;
+ if ((now.tv_sec - last_checked >= __tz_change_interval) ||
+ (last_checked > now.tv_sec)) {
+ last_checked = now.tv_sec;
return 1;
}
diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist
index 97b555e50dc1..ffdd82ae9911 100644
--- a/etc/mtree/BSD.usr.dist
+++ b/etc/mtree/BSD.usr.dist
@@ -304,6 +304,8 @@
..
indent
..
+ inotify
+ ..
ipfilter
..
ipfw
diff --git a/krb5/lib/crypto/Makefile b/krb5/lib/crypto/Makefile
index 5087a2fb559b..5efe53d12aa8 100644
--- a/krb5/lib/crypto/Makefile
+++ b/krb5/lib/crypto/Makefile
@@ -17,6 +17,7 @@ LIB= k5crypto
# SHLIB_MAJOR= 3
LDFLAGS=-Wl,--no-undefined
LIBADD= com_err krb5support crypto
+VERSION_MAP= ${.CURDIR}/version.map
# XXX The following doesn't work. Even though the pathnames are the same
# XXX we need to use the alternative .include statements.
diff --git a/krb5/lib/crypto/version.map b/krb5/lib/crypto/version.map
new file mode 100644
index 000000000000..bd4c2c1cd23f
--- /dev/null
+++ b/krb5/lib/crypto/version.map
@@ -0,0 +1,108 @@
+KRB5_CRYPTO_1.0 {
+ global:
+ krb5_c_make_random_key;
+ krb5_c_encrypt_length;
+ krb5_process_key;
+ krb5_string_to_cksumtype;
+ krb5_c_valid_enctype;
+ krb5_c_valid_cksumtype;
+ krb5_string_to_key;
+ krb5_c_encrypt_iov;
+ krb5_c_checksum_length;
+ is_keyed_cksum;
+ krb5_c_padding_length;
+ is_coll_proof_cksum;
+ krb5_init_random_key;
+ krb5_c_string_to_key_with_params;
+ krb5_c_random_make_octets;
+ krb5_c_random_os_entropy;
+ krb5_c_decrypt;
+ krb5_c_crypto_length;
+ krb5_c_block_size;
+ krb5_cksumtype_to_string;
+ krb5_c_keyed_checksum_types;
+ krb5_c_is_keyed_cksum;
+ krb5_c_crypto_length_iov;
+ valid_cksumtype;
+ krb5_c_random_seed;
+ krb5_c_random_to_key;
+ krb5_verify_checksum;
+ krb5_c_free_state;
+ krb5_c_verify_checksum;
+ krb5_c_random_add_entropy;
+ krb5_c_decrypt_iov;
+ krb5_c_make_checksum;
+ krb5_checksum_size;
+ krb5_free_cksumtypes;
+ krb5_finish_key;
+ krb5_encrypt_size;
+ krb5_c_keylengths;
+ krb5_c_prf;
+ krb5_encrypt;
+ krb5_string_to_enctype;
+ krb5_c_is_coll_proof_cksum;
+ krb5_c_init_state;
+ krb5_eblock_enctype;
+ krb5_decrypt;
+ krb5_c_encrypt;
+ krb5_c_enctype_compare;
+ krb5_c_verify_checksum_iov;
+ valid_enctype;
+ krb5_enctype_to_string;
+ krb5_enctype_to_name;
+ krb5_c_make_checksum_iov;
+ krb5_calculate_checksum;
+ krb5_c_string_to_key;
+ krb5_use_enctype;
+ krb5_random_key;
+ krb5_finish_random_key;
+ krb5_c_prf_length;
+ krb5int_c_mandatory_cksumtype;
+ krb5_c_fx_cf2_simple;
+ krb5int_c_weak_enctype;
+ krb5_encrypt_data;
+ krb5int_c_copy_keyblock;
+ krb5int_c_copy_keyblock_contents;
+ krb5int_c_free_keyblock_contents;
+ krb5int_c_free_keyblock;
+ krb5int_c_init_keyblock;
+ krb5int_hash_md4;
+ krb5int_hash_md5;
+ krb5int_hash_sha256;
+ krb5int_hash_sha384;
+ krb5int_enc_arcfour;
+ krb5int_hmac;
+ krb5_k_create_key;
+ krb5_k_decrypt;
+ krb5_k_decrypt_iov;
+ krb5_k_encrypt;
+ krb5_k_encrypt_iov;
+ krb5_k_free_key;
+ krb5_k_key_enctype;
+ krb5_k_key_keyblock;
+ krb5_k_make_checksum;
+ krb5_k_make_checksum_iov;
+ krb5_k_prf;
+ krb5_k_reference_key;
+ krb5_k_verify_checksum;
+ krb5_k_verify_checksum_iov;
+ krb5int_aes_encrypt;
+ krb5int_aes_decrypt;
+ krb5int_enc_des3;
+ krb5int_arcfour_gsscrypt;
+ krb5int_camellia_encrypt;
+ krb5int_cmac_checksum;
+ krb5int_enc_aes128;
+ krb5int_enc_aes256;
+ krb5int_enc_camellia128;
+ krb5int_enc_camellia256;
+ krb5int_derive_key;
+ krb5int_derive_random;
+ k5_sha256;
+ krb5int_nfold;
+ k5_allow_weak_pbkdf2iter;
+ krb5_c_prfplus;
+ krb5_c_derive_prfplus;
+ k5_enctype_to_ssf;
+ krb5int_c_deprecated_enctype;
+};
diff --git a/krb5/lib/gssapi/Makefile b/krb5/lib/gssapi/Makefile
index 51ed6f162d65..569452cfb538 100644
--- a/krb5/lib/gssapi/Makefile
+++ b/krb5/lib/gssapi/Makefile
@@ -17,6 +17,7 @@ LIB= gssapi_krb5
# SHLIB_MAJOR= 2
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5 k5crypto com_err krb5profile krb5support
+VERSION_MAP= ${.CURDIR}/version.map
# This is a contcatonation of:
# crypto/krb5/src/lib/gssapi/libgssapi_krb5.exports
diff --git a/krb5/lib/gssapi/version.map b/krb5/lib/gssapi/version.map
new file mode 100644
index 000000000000..afdfe9a0a83a
--- /dev/null
+++ b/krb5/lib/gssapi/version.map
@@ -0,0 +1,172 @@
+KRB5_GSSAPI_1.0 {
+ global:
+ GSS_C_ATTR_LOCAL_LOGIN_USER;
+ GSS_C_INQ_NEGOEX_KEY;
+ GSS_C_INQ_NEGOEX_VERIFY_KEY;
+ GSS_C_INQ_SSPI_SESSION_KEY;
+ GSS_C_MA_AUTH_INIT;
+ GSS_C_MA_AUTH_INIT_ANON;
+ GSS_C_MA_AUTH_INIT_INIT;
+ GSS_C_MA_AUTH_TARG;
+ GSS_C_MA_AUTH_TARG_ANON;
+ GSS_C_MA_AUTH_TARG_INIT;
+ GSS_C_MA_CBINDINGS;
+ GSS_C_MA_COMPRESS;
+ GSS_C_MA_CONF_PROT;
+ GSS_C_MA_CTX_TRANS;
+ GSS_C_MA_DELEG_CRED;
+ GSS_C_MA_DEPRECATED;
+ GSS_C_MA_INTEG_PROT;
+ GSS_C_MA_ITOK_FRAMED;
+ GSS_C_MA_MECH_COMPOSITE;
+ GSS_C_MA_MECH_CONCRETE;
+ GSS_C_MA_MECH_GLUE;
+ GSS_C_MA_MECH_NEGO;
+ GSS_C_MA_MECH_PSEUDO;
+ GSS_C_MA_MIC;
+ GSS_C_MA_NEGOEX_AND_SPNEGO;
+ GSS_C_MA_NOT_DFLT_MECH;
+ GSS_C_MA_NOT_MECH;
+ GSS_C_MA_OOS_DET;
+ GSS_C_MA_PFS;
+ GSS_C_MA_PROT_READY;
+ GSS_C_MA_REPLAY_DET;
+ GSS_C_MA_WRAP;
+ GSS_C_NT_ANONYMOUS;
+ GSS_C_NT_COMPOSITE_EXPORT;
+ GSS_C_NT_EXPORT_NAME;
+ GSS_C_NT_HOSTBASED_SERVICE;
+ GSS_C_NT_HOSTBASED_SERVICE_X;
+ GSS_C_NT_MACHINE_UID_NAME;
+ GSS_C_NT_STRING_UID_NAME;
+ GSS_C_NT_USER_NAME;
+ GSS_C_SEC_CONTEXT_SASL_SSF;
+ GSS_KRB5_CRED_NO_CI_FLAGS_X;
+ GSS_KRB5_GET_CRED_IMPERSONATOR;
+ GSS_KRB5_NT_ENTERPRISE_NAME;
+ GSS_KRB5_NT_PRINCIPAL_NAME;
+ GSS_KRB5_NT_X509_CERT;
+ gss_accept_sec_context;
+ gss_acquire_cred;
+ gss_acquire_cred_from;
+ gss_acquire_cred_impersonate_name;
+ gss_acquire_cred_with_password;
+ gss_add_buffer_set_member;
+ gss_add_cred;
+ gss_add_cred_from;
+ gss_add_cred_impersonate_name;
+ gss_add_cred_with_password;
+ gss_add_oid_set_member;
+ gss_authorize_localname;
+ gss_canonicalize_name;
+ gss_compare_name;
+ gss_complete_auth_token;
+ gss_context_time;
+ gss_create_empty_buffer_set;
+ gss_create_empty_oid_set;
+ gss_decapsulate_token;
+ gss_delete_name_attribute;
+ gss_delete_sec_context;
+ gss_display_mech_attr;
+ gss_display_name;
+ gss_display_name_ext;
+ gss_display_status;
+ gss_duplicate_name;
+ gss_encapsulate_token;
+ gss_export_cred;
+ gss_export_name;
+ gss_export_name_composite;
+ gss_export_sec_context;
+ gss_get_mic;
+ gss_get_mic_iov;
+ gss_get_mic_iov_length;
+ gss_get_name_attribute;
+ gss_import_cred;
+ gss_import_name;
+ gss_import_sec_context;
+ gss_indicate_mechs;
+ gss_indicate_mechs_by_attrs;
+ gss_init_sec_context;
+ gss_inquire_attrs_for_mech;
+ gss_inquire_context;
+ gss_inquire_cred;
+ gss_inquire_cred_by_mech;
+ gss_inquire_cred_by_oid;
+ gss_inquire_mech_for_saslname;
+ gss_inquire_mechs_for_name;
+ gss_inquire_name;
+ gss_inquire_names_for_mech;
+ gss_inquire_saslname_for_mech;
+ gss_inquire_sec_context_by_oid;
+ gss_krb5_ccache_name;
+ gss_krb5_copy_ccache;
+ gss_krb5_export_lucid_sec_context;
+ gss_krb5_free_lucid_sec_context;
+ gss_krb5_get_tkt_flags;
+ gss_krb5_import_cred;
+ gss_krb5_set_allowable_enctypes;
+ gss_krb5_set_cred_rcache;
+ gss_krb5int_make_seal_token_v3;
+ gss_krb5int_unseal_token_v3;
+ gss_localname;
+ gss_map_name_to_any;
+ gss_mech_iakerb;
+ gss_mech_krb5;
+ gss_mech_krb5_old;
+ gss_mech_krb5_wrong;
+ gss_mech_set_krb5;
+ gss_mech_set_krb5_both;
+ gss_mech_set_krb5_old;
+ gss_nt_exported_name;
+ gss_nt_krb5_name;
+ gss_nt_krb5_principal;
+ gss_nt_machine_uid_name;
+ gss_nt_service_name;
+ gss_nt_service_name_v2;
+ gss_nt_string_uid_name;
+ gss_nt_user_name;
+ gss_oid_equal;
+ gss_oid_to_str;
+ gss_pname_to_uid;
+ gss_process_context_token;
+ gss_pseudo_random;
+ gss_release_any_name_mapping;
+ gss_release_buffer;
+ gss_release_buffer_set;
+ gss_release_cred;
+ gss_release_iov_buffer;
+ gss_release_name;
+ gss_release_oid;
+ gss_release_oid_set;
+ gss_seal;
+ gss_set_cred_option;
+ gss_set_name_attribute;
+ gss_set_neg_mechs;
+ gss_set_sec_context_option;
+ gss_sign;
+ gss_store_cred;
+ gss_store_cred_into;
+ gss_str_to_oid;
+ gss_test_oid_set_member;
+ gss_unseal;
+ gss_unwrap;
+ gss_unwrap_aead;
+ gss_unwrap_iov;
+ gss_userok;
+ gss_verify;
+ gss_verify_mic;
+ gss_verify_mic_iov;
+ gss_wrap;
+ gss_wrap_aead;
+ gss_wrap_iov;
+ gss_wrap_iov_length;
+ gss_wrap_size_limit;
+ gssint_g_seqstate_init;
+ gsskrb5_extract_authtime_from_sec_context;
+ gsskrb5_extract_authz_data_from_sec_context;
+ gssspi_mech_invoke;
+ gssspi_set_cred_option;
+ krb5_gss_dbg_client_expcreds;
+ krb5_gss_register_acceptor_identity;
+ krb5_gss_use_kdc_context;
+};
diff --git a/krb5/lib/kadm5clnt/Makefile b/krb5/lib/kadm5clnt/Makefile
index e377f95f5b6e..c9f199bdaea3 100644
--- a/krb5/lib/kadm5clnt/Makefile
+++ b/krb5/lib/kadm5clnt/Makefile
@@ -17,6 +17,7 @@ LIB= kadm5clnt_mit
# SHLIB_MAJOR= 12
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile gssrpc gssapi_krb5 krb5 k5crypto krb5support com_err
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= alt_prof.c \
chpass_util.c \
@@ -88,7 +89,7 @@ ${CHPASS_UTIL_STRINGS_ERR_C}: ${CHPASS_UTIL_STRINGS_ERR}
rm -f et-c-${.PREFIX}.et et-c-${.PREFIX}.c
afterinstall:
- ${INSTALL_LIBSYMLINK} ${SHLIB} ${DESTDIR}${LIBDIR}/libkadm5clnt
+ ${INSTALL_LIBSYMLINK} ${SHLIB_LINK} ${DESTDIR}${LIBDIR}/libkadm5clnt.so
.include <bsd.lib.mk>
diff --git a/krb5/lib/kadm5clnt/version.map b/krb5/lib/kadm5clnt/version.map
new file mode 100644
index 000000000000..9743c7cf6140
--- /dev/null
+++ b/krb5/lib/kadm5clnt/version.map
@@ -0,0 +1,118 @@
+KRB5_KADM5_CLNT_1.0 {
+ global:
+ _kadm5_check_handle;
+ _kadm5_chpass_principal_util;
+ kadm5_chpass_principal;
+ kadm5_chpass_principal_3;
+ kadm5_chpass_principal_util;
+ kadm5_create_policy;
+ kadm5_create_principal;
+ kadm5_create_principal_3;
+ kadm5_decrypt_key;
+ kadm5_delete_policy;
+ kadm5_delete_principal;
+ kadm5_destroy;
+ kadm5_flush;
+ kadm5_free_config_params;
+ kadm5_free_kadm5_key_data;
+ kadm5_free_key_data;
+ kadm5_free_name_list;
+ kadm5_free_policy_ent;
+ kadm5_free_principal_ent;
+ kadm5_free_strings;
+ kadm5_get_admin_service_name;
+ kadm5_get_config_params;
+ kadm5_get_policies;
+ kadm5_get_policy;
+ kadm5_get_principal;
+ kadm5_get_principal_keys;
+ kadm5_get_principals;
+ kadm5_get_privs;
+ kadm5_get_strings;
+ kadm5_init;
+ kadm5_init_anonymous;
+ kadm5_init_krb5_context;
+ kadm5_init_with_creds;
+ kadm5_init_with_password;
+ kadm5_init_with_skey;
+ kadm5_lock;
+ kadm5_modify_policy;
+ kadm5_modify_principal;
+ kadm5_purgekeys;
+ kadm5_randkey_principal;
+ kadm5_randkey_principal_3;
+ kadm5_rename_principal;
+ kadm5_set_string;
+ kadm5_setkey_principal;
+ kadm5_setkey_principal_3;
+ kadm5_setkey_principal_4;
+ kadm5_unlock;
+ krb5_aprof_get_boolean;
+ krb5_aprof_get_deltat;
+ krb5_aprof_get_int32;
+ krb5_aprof_get_string;
+ krb5_aprof_getvals;
+ krb5_flagnum_to_string;
+ krb5_flagspec_to_mask;
+ krb5_flags_to_strings;
+ krb5_free_key_data_contents;
+ krb5_keysalt_is_present;
+ krb5_keysalt_iterate;
+ krb5_klog_close;
+ krb5_klog_init;
+ krb5_klog_reopen;
+ krb5_klog_set_context;
+ krb5_klog_syslog;
+ krb5_string_to_keysalts;
+ xdr_chpass3_arg;
+ xdr_chpass_arg;
+ xdr_chrand3_arg;
+ xdr_chrand_arg;
+ xdr_chrand_ret;
+ xdr_cpol_arg;
+ xdr_cprinc3_arg;
+ xdr_cprinc_arg;
+ xdr_dpol_arg;
+ xdr_dprinc_arg;
+ xdr_generic_ret;
+ xdr_getpkeys_arg;
+ xdr_getpkeys_ret;
+ xdr_getprivs_ret;
+ xdr_gpol_arg;
+ xdr_gpol_ret;
+ xdr_gpols_arg;
+ xdr_gpols_ret;
+ xdr_gprinc_arg;
+ xdr_gprinc_ret;
+ xdr_gprincs_arg;
+ xdr_gprincs_ret;
+ xdr_kadm5_key_data;
+ xdr_kadm5_policy_ent_rec;
+ xdr_kadm5_principal_ent_rec;
+ xdr_kadm5_ret_t;
+ xdr_krb5_deltat;
+ xdr_krb5_enctype;
+ xdr_krb5_flags;
+ xdr_krb5_int16;
+ xdr_krb5_key_data_nocontents;
+ xdr_krb5_key_salt_tuple;
+ xdr_krb5_keyblock;
+ xdr_krb5_kvno;
+ xdr_krb5_octet;
+ xdr_krb5_principal;
+ xdr_krb5_salttype;
+ xdr_krb5_timestamp;
+ xdr_krb5_tl_data;
+ xdr_krb5_ui_2;
+ xdr_krb5_ui_4;
+ xdr_mpol_arg;
+ xdr_mprinc_arg;
+ xdr_nullstring;
+ xdr_nulltype;
+ xdr_rprinc_arg;
+ xdr_setkey3_arg;
+ xdr_setkey4_arg;
+ xdr_setkey_arg;
+ xdr_ui_4;
+ kadm5_init_iprop;
+};
diff --git a/krb5/lib/kadm5srv/Makefile b/krb5/lib/kadm5srv/Makefile
index f716dfcdaedc..90a2180d496a 100644
--- a/krb5/lib/kadm5srv/Makefile
+++ b/krb5/lib/kadm5srv/Makefile
@@ -17,6 +17,7 @@ LIB= kadm5srv_mit
# SHLIB_MAJOR= 12
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile gssrpc gssapi_krb5 kdb5 krb5 k5crypto krb5support com_err
+VERSION_MAP= ${.CURDIR}/version.map
INCSDIR= ${INCLUDEDIR}/kadm5
diff --git a/krb5/lib/kadm5srv/version.map b/krb5/lib/kadm5srv/version.map
new file mode 100644
index 000000000000..a0e9da6daef2
--- /dev/null
+++ b/krb5/lib/kadm5srv/version.map
@@ -0,0 +1,137 @@
+KRB5_KADM5_SRV_1.0 {
+ global:
+ _kadm5_check_handle;
+ _kadm5_chpass_principal_util;
+ hist_princ;
+ kadm5_chpass_principal;
+ kadm5_chpass_principal_3;
+ kadm5_chpass_principal_util;
+ kadm5_create_policy;
+ kadm5_create_principal;
+ kadm5_create_principal_3;
+ kadm5_decrypt_key;
+ kadm5_delete_policy;
+ kadm5_delete_principal;
+ kadm5_destroy;
+ kadm5_flush;
+ kadm5_free_config_params;
+ kadm5_free_kadm5_key_data;
+ kadm5_free_key_data;
+ kadm5_free_name_list;
+ kadm5_free_policy_ent;
+ kadm5_free_principal_ent;
+ kadm5_free_strings;
+ kadm5_get_config_params;
+ kadm5_get_policies;
+ kadm5_get_policy;
+ kadm5_get_principal;
+ kadm5_get_principal_keys;
+ kadm5_get_principals;
+ kadm5_get_privs;
+ kadm5_get_strings;
+ kadm5_init;
+ kadm5_init_anonymous;
+ kadm5_init_krb5_context;
+ kadm5_init_with_creds;
+ kadm5_init_with_password;
+ kadm5_init_with_skey;
+ kadm5_lock;
+ kadm5_modify_policy;
+ kadm5_modify_principal;
+ kadm5_purgekeys;
+ kadm5_randkey_principal;
+ kadm5_randkey_principal_3;
+ kadm5_rename_principal;
+ kadm5_set_string;
+ kadm5_setkey_principal;
+ kadm5_setkey_principal_3;
+ kadm5_setkey_principal_4;
+ kadm5_unlock;
+ kdb_delete_entry;
+ kdb_free_entry;
+ kdb_init_hist;
+ kdb_init_master;
+ kdb_iter_entry;
+ kdb_put_entry;
+ krb5_aprof_get_boolean;
+ krb5_aprof_get_deltat;
+ krb5_aprof_get_int32;
+ krb5_aprof_get_string;
+ krb5_aprof_get_string_all;
+ krb5_aprof_getvals;
+ krb5_copy_key_data_contents;
+ krb5_flagnum_to_string;
+ krb5_flagspec_to_mask;
+ krb5_flags_to_strings;
+ krb5_free_key_data_contents;
+ krb5_keysalt_is_present;
+ krb5_keysalt_iterate;
+ krb5_klog_close;
+ krb5_klog_init;
+ krb5_klog_reopen;
+ krb5_klog_set_context;
+ krb5_klog_syslog;
+ krb5_string_to_keysalts;
+ master_db;
+ master_princ;
+ osa_free_princ_ent;
+ passwd_check;
+ xdr_chpass3_arg;
+ xdr_chpass_arg;
+ xdr_chrand3_arg;
+ xdr_chrand_arg;
+ xdr_chrand_ret;
+ xdr_cpol_arg;
+ xdr_cprinc3_arg;
+ xdr_cprinc_arg;
+ xdr_dpol_arg;
+ xdr_dprinc_arg;
+ xdr_generic_ret;
+ xdr_getpkeys_arg;
+ xdr_getpkeys_ret;
+ xdr_getprivs_ret;
+ xdr_gpol_arg;
+ xdr_gpol_ret;
+ xdr_gpols_arg;
+ xdr_gpols_ret;
+ xdr_gprinc_arg;
+ xdr_gprinc_ret;
+ xdr_gprincs_arg;
+ xdr_gprincs_ret;
+ xdr_gstrings_arg;
+ xdr_gstrings_ret;
+ xdr_kadm5_policy_ent_rec;
+ xdr_kadm5_principal_ent_rec;
+ xdr_kadm5_ret_t;
+ xdr_krb5_deltat;
+ xdr_krb5_enctype;
+ xdr_krb5_flags;
+ xdr_krb5_int16;
+ xdr_krb5_key_data;
+ xdr_krb5_key_data_nocontents;
+ xdr_krb5_key_salt_tuple;
+ xdr_krb5_keyblock;
+ xdr_krb5_kvno;
+ xdr_krb5_octet;
+ xdr_krb5_principal;
+ xdr_krb5_salttype;
+ xdr_krb5_string_attr;
+ xdr_krb5_timestamp;
+ xdr_krb5_tl_data;
+ xdr_krb5_ui_2;
+ xdr_krb5_ui_4;
+ xdr_mpol_arg;
+ xdr_mprinc_arg;
+ xdr_nullstring;
+ xdr_nulltype;
+ xdr_osa_princ_ent_rec;
+ xdr_osa_pw_hist_ent;
+ xdr_purgekeys_arg;
+ xdr_rprinc_arg;
+ xdr_setkey3_arg;
+ xdr_setkey4_arg;
+ xdr_setkey_arg;
+ xdr_sstring_arg;
+ xdr_ui_4;
+ kadm5_init_iprop;
+};
diff --git a/krb5/lib/kdb/Makefile b/krb5/lib/kdb/Makefile
index ac7f058a7f11..57fe32e39347 100644
--- a/krb5/lib/kdb/Makefile
+++ b/krb5/lib/kdb/Makefile
@@ -17,6 +17,7 @@ LIB= kdb5
# SHLIB_MAJOR= 10
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile gssrpc krb5 k5crypto com_err krb5support gssapi_krb5
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= decrypt_key.c \
encrypt_key.c \
diff --git a/krb5/lib/kdb/version.map b/krb5/lib/kdb/version.map
new file mode 100644
index 000000000000..9522af1e9edd
--- /dev/null
+++ b/krb5/lib/kdb/version.map
@@ -0,0 +1,111 @@
+KRB5_KDB5_1.0 {
+ global:
+ krb5_db_setup_lib_handle;
+ krb5_db_open;
+ krb5_db_inited;
+ krb5_db_alloc;
+ krb5_db_free;
+ krb5_db_allowed_to_delegate_from;
+ krb5_db_audit_as_req;
+ krb5_db_check_allowed_to_delegate;
+ krb5_db_get_s4u_x509_principal;
+ krb5_db_check_policy_as;
+ krb5_db_check_policy_tgs;
+ krb5_db_check_transited_realms;
+ krb5_db_create;
+ krb5_db_delete_principal;
+ krb5_db_destroy;
+ krb5_db_fetch_mkey;
+ krb5_db_fetch_mkey_list;
+ krb5_db_fini;
+ krb5_db_free_principal;
+ krb5_db_get_age;
+ krb5_db_get_key_data_kvno;
+ krb5_db_get_context;
+ krb5_db_get_principal;
+ krb5_db_issue_pac;
+ krb5_db_iterate;
+ krb5_db_lock;
+ krb5_db_mkey_list_alias;
+ krb5_db_put_principal;
+ krb5_db_refresh_config;
+ krb5_db_rename_principal;
+ krb5_db_set_context;
+ krb5_db_setup_mkey_name;
+ krb5_db_unlock;
+ krb5_db_store_master_key;
+ krb5_db_store_master_key_list;
+ krb5_dbe_apw;
+ krb5_dbe_ark;
+ krb5_dbe_cpw;
+ krb5_dbe_create_key_data;
+ krb5_dbe_crk;
+ krb5_dbe_find_act_mkey;
+ krb5_dbe_fetch_act_key_list;
+ krb5_dbe_find_enctype;
+ krb5_dbe_find_mkey;
+ krb5_dbe_free_actkvno_list;
+ krb5_dbe_free_key_data_contents;
+ krb5_dbe_free_mkey_aux_list;
+ krb5_dbe_free_key_list;
+ krb5_dbe_free_string;
+ krb5_dbe_free_strings;
+ krb5_dbe_get_mkvno;
+ krb5_dbe_get_string;
+ krb5_dbe_get_strings;
+ krb5_dbe_compute_salt;
+ krb5_dbe_lookup_last_admin_unlock;
+ krb5_dbe_lookup_last_pwd_change;
+ krb5_dbe_lookup_actkvno;
+ krb5_dbe_lookup_mkey_aux;
+ krb5_dbe_lookup_mkvno;
+ krb5_dbe_lookup_mod_princ_data;
+ krb5_dbe_lookup_tl_data;
+ krb5_dbe_search_enctype;
+ krb5_dbe_set_string;
+ krb5_dbe_specialize_salt;
+ krb5_dbe_update_actkvno;
+ krb5_dbe_update_last_admin_unlock;
+ krb5_dbe_update_last_pwd_change;
+ krb5_dbe_update_mkey_aux;
+ krb5_dbe_update_mkvno;
+ krb5_dbe_update_mod_princ_data;
+ krb5_dbe_update_tl_data;
+ krb5_db_update_tl_data;
+ krb5_dbe_def_encrypt_key_data;
+ krb5_dbe_def_decrypt_key_data;
+ krb5_dbe_decrypt_key_data;
+ krb5_dbe_encrypt_key_data;
+ krb5_kt_kdb_ops;
+ krb5_ktkdb_close;
+ krb5_ktkdb_get_entry;
+ krb5_ktkdb_resolve;
+ krb5_ktkdb_set_context;
+ krb5_mkey_pwd_prompt1;
+ krb5_mkey_pwd_prompt2;
+ krb5_db_create_policy;
+ krb5_db_get_policy;
+ krb5_db_put_policy;
+ krb5_db_iter_policy;
+ krb5_db_delete_policy;
+ krb5_db_free_policy;
+ krb5_def_store_mkey_list;
+ krb5_db_promote;
+ krb5_db_register_keytab;
+ ulog_add_update;
+ ulog_init_header;
+ ulog_map;
+ ulog_set_role;
+ ulog_free_entries;
+ xdr_kdb_last_t;
+ xdr_kdb_incr_result_t;
+ xdr_kdb_fullresync_result_t;
+ ulog_fini;
+ ulog_get_entries;
+ ulog_get_last;
+ ulog_get_sno_status;
+ ulog_replay;
+ ulog_set_last;
+ xdr_kdb_incr_update_t;
+ krb5_dbe_sort_key_data;
+};
diff --git a/krb5/lib/krad/Makefile b/krb5/lib/krad/Makefile
index 4b18af482207..28751d9bf9b6 100644
--- a/krb5/lib/krad/Makefile
+++ b/krb5/lib/krad/Makefile
@@ -17,6 +17,7 @@ LIB= krad
# SHLIB_MAJOR= 0
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5 k5crypto com_err krb5profile krb5support verto
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= attr.c \
attrset.c \
diff --git a/krb5/lib/krad/version.map b/krb5/lib/krad/version.map
new file mode 100644
index 000000000000..7e058d9bd494
--- /dev/null
+++ b/krb5/lib/krad/version.map
@@ -0,0 +1,26 @@
+KRB5_KRAD_1.0 {
+ global:
+ krad_code_name2num;
+ krad_code_num2name;
+ krad_attr_name2num;
+ krad_attr_num2name;
+ krad_attrset_new;
+ krad_attrset_copy;
+ krad_attrset_free;
+ krad_attrset_add;
+ krad_attrset_add_number;
+ krad_attrset_del;
+ krad_attrset_get;
+ krad_packet_bytes_needed;
+ krad_packet_free;
+ krad_packet_new_request;
+ krad_packet_new_response;
+ krad_packet_decode_request;
+ krad_packet_decode_response;
+ krad_packet_encode;
+ krad_packet_get_code;
+ krad_packet_get_attr;
+ krad_client_new;
+ krad_client_free;
+ krad_client_send;
+};
diff --git a/krb5/lib/krb5/Makefile b/krb5/lib/krb5/Makefile
index bf90c7fc80f7..76f40a3174cc 100644
--- a/krb5/lib/krb5/Makefile
+++ b/krb5/lib/krb5/Makefile
@@ -17,6 +17,7 @@ LIB= krb5
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile k5crypto com_err krb5support
# SHLIB_MAJOR= 3
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= krb5_libinit.c
diff --git a/krb5/lib/krb5/version.map b/krb5/lib/krb5/version.map
new file mode 100644
index 000000000000..3f37ce0dce31
--- /dev/null
+++ b/krb5/lib/krb5/version.map
@@ -0,0 +1,617 @@
+KRB5_KRB5_1.0 {
+ global:
+ _krb5_conf_boolean;
+ decode_krb5_ad_kdcissued;
+ decode_krb5_ap_rep;
+ decode_krb5_ap_rep_enc_part;
+ decode_krb5_ap_req;
+ decode_krb5_as_rep;
+ decode_krb5_as_req;
+ decode_krb5_authdata;
+ decode_krb5_authenticator;
+ decode_krb5_cammac;
+ decode_krb5_cred;
+ decode_krb5_enc_cred_part;
+ decode_krb5_enc_data;
+ decode_krb5_enc_kdc_rep_part;
+ decode_krb5_enc_priv_part;
+ decode_krb5_enc_sam_response_enc_2;
+ decode_krb5_enc_tkt_part;
+ decode_krb5_encryption_key;
+ decode_krb5_error;
+ decode_krb5_etype_info;
+ decode_krb5_etype_info2;
+ decode_krb5_fast_req;
+ decode_krb5_fast_response;
+ decode_krb5_iakerb_finished;
+ decode_krb5_iakerb_header;
+ decode_krb5_kdc_req_body;
+ decode_krb5_otp_tokeninfo;
+ decode_krb5_kkdcp_message;
+ decode_krb5_pa_enc_ts;
+ decode_krb5_pa_for_user;
+ decode_krb5_pa_fx_fast_reply;
+ decode_krb5_pa_fx_fast_request;
+ decode_krb5_pa_otp_challenge;
+ decode_krb5_pa_otp_req;
+ decode_krb5_pa_otp_enc_req;
+ decode_krb5_pa_pac_options;
+ decode_krb5_pa_pac_req;
+ decode_krb5_pa_s4u_x509_user;
+ decode_krb5_pa_spake;
+ decode_krb5_padata_sequence;
+ decode_krb5_priv;
+ decode_krb5_safe;
+ decode_krb5_sam_challenge_2;
+ decode_krb5_sam_challenge_2_body;
+ decode_krb5_sam_response_2;
+ decode_krb5_secure_cookie;
+ decode_krb5_setpw_req;
+ decode_krb5_spake_factor;
+ decode_krb5_tgs_rep;
+ decode_krb5_tgs_req;
+ decode_krb5_ticket;
+ decode_krb5_typed_data;
+ decode_utf8_strings;
+ encode_krb5_ad_kdcissued;
+ encode_krb5_ap_rep;
+ encode_krb5_ap_rep_enc_part;
+ encode_krb5_ap_req;
+ encode_krb5_as_rep;
+ encode_krb5_as_req;
+ encode_krb5_authdata;
+ encode_krb5_authenticator;
+ encode_krb5_cammac;
+ encode_krb5_checksum;
+ encode_krb5_cred;
+ encode_krb5_enc_cred_part;
+ encode_krb5_enc_data;
+ encode_krb5_enc_kdc_rep_part;
+ encode_krb5_enc_priv_part;
+ encode_krb5_enc_sam_response_enc_2;
+ encode_krb5_enc_tkt_part;
+ encode_krb5_encryption_key;
+ encode_krb5_error;
+ encode_krb5_etype_info;
+ encode_krb5_etype_info2;
+ encode_krb5_fast_response;
+ encode_krb5_iakerb_finished;
+ encode_krb5_iakerb_header;
+ encode_krb5_kdc_req_body;
+ encode_krb5_otp_tokeninfo;
+ encode_krb5_kkdcp_message;
+ encode_krb5_pa_enc_ts;
+ encode_krb5_pa_for_user;
+ encode_krb5_pa_fx_fast_reply;
+ encode_krb5_pa_otp_challenge;
+ encode_krb5_pa_otp_req;
+ encode_krb5_pa_otp_enc_req;
+ encode_krb5_pa_pac_options;
+ encode_krb5_pa_s4u_x509_user;
+ encode_krb5_pa_spake;
+ encode_krb5_padata_sequence;
+ encode_krb5_pkinit_supp_pub_info;
+ encode_krb5_priv;
+ encode_krb5_s4u_userid;
+ encode_krb5_safe;
+ encode_krb5_sam_challenge_2;
+ encode_krb5_sam_challenge_2_body;
+ encode_krb5_sam_response_2;
+ encode_krb5_secure_cookie;
+ encode_krb5_sp80056a_other_info;
+ encode_krb5_spake_factor;
+ encode_krb5_tgs_rep;
+ encode_krb5_tgs_req;
+ encode_krb5_ticket;
+ encode_krb5_typed_data;
+ encode_utf8_strings;
+ k5_add_empty_pa_data;
+ k5_add_pa_data_element;
+ k5_add_pa_data_from_data;
+ k5_alloc_pa_data;
+ k5_authind_decode;
+ k5_build_conf_principals;
+ k5_cc_store_primary_cred;
+ k5_ccselect_free_context;
+ k5_change_error_message_code;
+ k5_etypes_contains;
+ k5_expand_path_tokens;
+ k5_expand_path_tokens_extra;
+ k5_externalize_auth_context;
+ k5_externalize_authdata;
+ k5_externalize_authdata_context;
+ k5_externalize_context;
+ k5_externalize_keyblock;
+ k5_externalize_principal;
+ k5_free_algorithm_identifier;
+ k5_free_cammac;
+ k5_free_data_ptr_list;
+ k5_free_otp_tokeninfo;
+ k5_free_kkdcp_message;
+ k5_free_pa_data_element;
+ k5_free_pa_otp_challenge;
+ k5_free_pa_otp_req;
+ k5_free_secure_cookie;
+ k5_free_pa_spake;
+ k5_free_serverlist;
+ k5_free_spake_factor;
+ k5_hostrealm_free_context;
+ k5_init_trace;
+ k5_internalize_auth_context;
+ k5_internalize_authdata;
+ k5_internalize_authdata_context;
+ k5_internalize_context;
+ k5_internalize_keyblock;
+ k5_internalize_principal;
+ k5_is_string_numeric;
+ k5_kt_get_principal;
+ k5_kt_have_match;
+ k5_localauth_free_context;
+ k5_locate_kdc;
+ k5_marshal_cred;
+ k5_marshal_princ;
+ k5_os_free_context;
+ k5_os_init_context;
+ k5_parse_host_string;
+ k5_plugin_free_modules;
+ k5_plugin_load;
+ k5_plugin_load_all;
+ k5_plugin_register;
+ k5_plugin_register_dyn;
+ k5_rc_close;
+ k5_rc_get_name;
+ k5_rc_resolve;
+ k5_rc_store;
+ k5_size_auth_context;
+ k5_size_authdata;
+ k5_size_authdata_context;
+ k5_size_context;
+ k5_size_keyblock;
+ k5_size_principal;
+ k5_sname_compare;
+ k5_unmarshal_cred;
+ k5_unmarshal_princ;
+ k5_unwrap_cammac_svc;
+ k5_zapfree_pa_data;
+ krb524_convert_creds_kdc;
+ krb524_init_ets;
+ krb5_425_conv_principal;
+ krb5_524_conv_principal;
+ krb5_524_convert_creds;
+ krb5_address_compare;
+ krb5_address_order;
+ krb5_address_search;
+ krb5_allow_weak_crypto;
+ krb5_aname_to_localname;
+ krb5_anonymous_principal;
+ krb5_anonymous_realm;
+ krb5_appdefault_boolean;
+ krb5_appdefault_string;
+ krb5_auth_con_free;
+ krb5_auth_con_genaddrs;
+ krb5_auth_con_get_checksum_func;
+ krb5_auth_con_get_authdata_context;
+ krb5_auth_con_getaddrs;
+ krb5_auth_con_getauthenticator;
+ krb5_auth_con_getflags;
+ krb5_auth_con_getivector;
+ krb5_auth_con_getkey;
+ krb5_auth_con_getkey_k;
+ krb5_auth_con_getlocalseqnumber;
+ krb5_auth_con_getlocalsubkey;
+ krb5_auth_con_getpermetypes;
+ krb5_auth_con_getrcache;
+ krb5_auth_con_getrecvsubkey;
+ krb5_auth_con_getrecvsubkey_k;
+ krb5_auth_con_getremoteseqnumber;
+ krb5_auth_con_getremotesubkey;
+ krb5_auth_con_getsendsubkey;
+ krb5_auth_con_getsendsubkey_k;
+ krb5_auth_con_init;
+ krb5_auth_con_initivector;
+ krb5_auth_con_set_authdata_context;
+ krb5_auth_con_set_checksum_func;
+ krb5_auth_con_set_req_cksumtype;
+ krb5_auth_con_set_safe_cksumtype;
+ krb5_auth_con_setaddrs;
+ krb5_auth_con_setflags;
+ krb5_auth_con_setivector;
+ krb5_auth_con_setpermetypes;
+ krb5_auth_con_setports;
+ krb5_auth_con_setrcache;
+ krb5_auth_con_setrecvsubkey;
+ krb5_auth_con_setrecvsubkey_k;
+ krb5_auth_con_setsendsubkey;
+ krb5_auth_con_setsendsubkey_k;
+ krb5_auth_con_setuseruserkey;
+ krb5_authdata_context_copy;
+ krb5_authdata_context_free;
+ krb5_authdata_context_init;
+ krb5_authdata_delete_attribute;
+ krb5_authdata_get_attribute_types;
+ krb5_authdata_get_attribute;
+ krb5_authdata_set_attribute;
+ krb5_authdata_export_attributes;
+ krb5_authdata_export_authdata;
+ krb5_authdata_export_internal;
+ krb5_authdata_free_internal;
+ krb5_authdata_import_attributes;
+ krb5_build_principal;
+ krb5_build_principal_alloc_va;
+ krb5_build_principal_ext;
+ krb5_build_principal_va;
+ krb5_cc_cache_match;
+ krb5_cc_close;
+ krb5_cc_copy_creds;
+ krb5_cc_default;
+ krb5_cc_default_name;
+ krb5_cc_destroy;
+ krb5_cc_dfl_ops;
+ krb5_cc_dup;
+ krb5_cc_end_seq_get;
+ krb5_cc_file_ops;
+ krb5_cc_gen_new;
+ krb5_cc_get_config;
+ krb5_cc_get_full_name;
+ krb5_cc_get_name;
+ krb5_cc_get_principal;
+ krb5_cc_get_type;
+ krb5_cc_move;
+ krb5_cc_initialize;
+ krb5_cc_new_unique;
+ krb5_cc_next_cred;
+ krb5_cc_register;
+ krb5_cc_remove_cred;
+ krb5_cc_resolve;
+ krb5_cc_retrieve_cred;
+ krb5_cc_select;
+ krb5_cc_set_config;
+ krb5_cc_set_default_name;
+ krb5_cc_set_flags;
+ krb5_cc_start_seq_get;
+ krb5_cc_store_cred;
+ krb5_cc_support_switch;
+ krb5_cc_switch;
+ krb5_cccol_cursor_free;
+ krb5_cccol_cursor_new;
+ krb5_cccol_cursor_next;
+ krb5_cccol_have_content;
+ krb5_change_cache;
+ krb5_change_password;
+ krb5_check_clockskew;
+ krb5_check_transited_list;
+ krb5_chpw_message;
+ krb5_chpw_result_code_string;
+ krb5_clear_error_message;
+ krb5_copy_addr;
+ krb5_copy_addresses;
+ krb5_copy_authdata;
+ krb5_copy_authenticator;
+ krb5_copy_checksum;
+ krb5_copy_context;
+ krb5_copy_creds;
+ krb5_copy_data;
+ krb5_copy_error_message;
+ krb5_copy_keyblock;
+ krb5_copy_keyblock_contents;
+ krb5_copy_principal;
+ krb5_copy_ticket;
+ krb5_crypto_us_timeofday;
+ krb5_decode_authdata_container;
+ krb5_decode_ticket;
+ krb5_decrypt_tkt_part;
+ krb5_deltat_to_string;
+ krb5_encode_authdata_container;
+ krb5_encode_kdc_rep;
+ krb5_encrypt_helper;
+ krb5_encrypt_tkt_part;
+ krb5_expand_hostname;
+ krb5_fcc_ops;
+ krb5_find_authdata;
+ krb5_free_ad_kdcissued;
+ krb5_free_address;
+ krb5_free_addresses;
+ krb5_free_ap_rep;
+ krb5_free_ap_rep_enc_part;
+ krb5_free_ap_req;
+ krb5_free_authdata;
+ krb5_free_authenticator;
+ krb5_free_authenticator_contents;
+ krb5_free_checksum;
+ krb5_free_checksum_contents;
+ krb5_free_config_files;
+ krb5_free_context;
+ krb5_free_cred;
+ krb5_free_cred_contents;
+ krb5_free_cred_enc_part;
+ krb5_free_creds;
+ krb5_free_data;
+ krb5_free_data_contents;
+ krb5_free_default_realm;
+ krb5_free_enc_data;
+ krb5_free_enc_kdc_rep_part;
+ krb5_free_enc_sam_response_enc_2;
+ krb5_free_enc_sam_response_enc_2_contents;
+ krb5_free_enc_tkt_part;
+ krb5_free_enctypes;
+ krb5_free_error;
+ krb5_free_error_message;
+ krb5_free_etype_info;
+ krb5_free_fast_armored_req;
+ krb5_free_fast_req;
+ krb5_free_fast_response;
+ krb5_free_host_realm;
+ krb5_free_iakerb_finished;
+ krb5_free_iakerb_header;
+ krb5_free_kdc_rep;
+ krb5_free_kdc_req;
+ krb5_free_keyblock;
+ krb5_free_keyblock_contents;
+ krb5_free_keytab_entry_contents;
+ krb5_free_last_req;
+ krb5_free_octet_data;
+ krb5_free_pa_data;
+ krb5_free_pa_enc_ts;
+ krb5_free_pa_for_user;
+ krb5_free_pa_pac_req;
+ krb5_free_pa_s4u_x509_user;
+ krb5_free_principal;
+ krb5_free_priv;
+ krb5_free_priv_enc_part;
+ krb5_free_realm_tree;
+ krb5_free_safe;
+ krb5_free_sam_challenge_2;
+ krb5_free_sam_challenge_2_body;
+ krb5_free_sam_challenge_2_body_contents;
+ krb5_free_sam_challenge_2_contents;
+ krb5_free_sam_response_2;
+ krb5_free_sam_response_2_contents;
+ krb5_free_string;
+ krb5_free_tgt_creds;
+ krb5_free_ticket;
+ krb5_free_tickets;
+ krb5_free_tkt_authent;
+ krb5_free_unparsed_name;
+ krb5_fwd_tgt_creds;
+ krb5_gen_portaddr;
+ krb5_gen_replay_name;
+ krb5_generate_seq_number;
+ krb5_generate_subkey;
+ krb5_get_cred_via_tkt;
+ krb5_get_credentials;
+ krb5_get_credentials_for_proxy;
+ krb5_get_credentials_for_user;
+ krb5_get_credentials_renew;
+ krb5_get_credentials_validate;
+ krb5_get_default_config_files;
+ krb5_get_default_in_tkt_ktypes;
+ krb5_get_default_realm;
+ krb5_get_error_message;
+ krb5_get_etype_info;
+ krb5_get_fallback_host_realm;
+ krb5_get_host_realm;
+ krb5_get_in_tkt_with_keytab;
+ krb5_get_in_tkt_with_password;
+ krb5_get_in_tkt_with_skey;
+ krb5_get_init_creds_keytab;
+ krb5_get_init_creds_opt_alloc;
+ krb5_get_init_creds_opt_free;
+ krb5_get_init_creds_opt_free_pa;
+ krb5_get_init_creds_opt_get_fast_flags;
+ krb5_get_init_creds_opt_get_pa;
+ krb5_get_init_creds_opt_init;
+ krb5_get_init_creds_opt_set_address_list;
+ krb5_get_init_creds_opt_set_anonymous;
+ krb5_get_init_creds_opt_set_canonicalize;
+ krb5_get_init_creds_opt_set_change_password_prompt;
+ krb5_get_init_creds_opt_set_etype_list;
+ krb5_get_init_creds_opt_set_expire_callback;
+ krb5_get_init_creds_opt_set_fast_ccache;
+ krb5_get_init_creds_opt_set_fast_ccache_name;
+ krb5_get_init_creds_opt_set_fast_flags;
+ krb5_get_init_creds_opt_set_forwardable;
+ krb5_get_init_creds_opt_set_in_ccache;
+ krb5_get_init_creds_opt_set_out_ccache;
+ krb5_get_init_creds_opt_set_pa;
+ krb5_get_init_creds_opt_set_pac_request;
+ krb5_get_init_creds_opt_set_preauth_list;
+ krb5_get_init_creds_opt_set_proxiable;
+ krb5_get_init_creds_opt_set_renew_life;
+ krb5_get_init_creds_opt_set_responder;
+ krb5_get_init_creds_opt_set_salt;
+ krb5_get_init_creds_opt_set_tkt_life;
+ krb5_get_init_creds_password;
+ krb5_get_notification_message;
+ krb5_get_permitted_enctypes;
+ krb5_get_profile;
+ krb5_get_prompt_types;
+ krb5_get_realm_domain;
+ krb5_get_renewed_creds;
+ krb5_get_server_rcache;
+ krb5_get_tgs_ktypes;
+ krb5_get_time_offsets;
+ krb5_get_validated_creds;
+ krb5_init_context;
+ krb5_init_context_profile;
+ krb5_init_creds_free;
+ krb5_init_creds_get;
+ krb5_init_creds_get_creds;
+ krb5_init_creds_get_error;
+ krb5_init_creds_get_times;
+ krb5_init_creds_init;
+ krb5_init_creds_set_keytab;
+ krb5_init_creds_set_password;
+ krb5_init_creds_set_service;
+ krb5_init_creds_step;
+ krb5_init_keyblock;
+ krb5_init_secure_context;
+ krb5_is_config_principal;
+ krb5_is_permitted_enctype;
+ krb5_is_referral_realm;
+ krb5_is_thread_safe;
+ krb5_kdc_rep_decrypt_proc;
+ krb5_kdc_sign_ticket;
+ krb5_kdc_verify_ticket;
+ krb5_kt_add_entry;
+ krb5_kt_client_default;
+ krb5_kt_close;
+ krb5_kt_default;
+ krb5_kt_default_name;
+ krb5_kt_dfl_ops;
+ krb5_kt_dup;
+ krb5_kt_end_seq_get;
+ krb5_kt_free_entry;
+ krb5_kt_get_entry;
+ krb5_kt_get_name;
+ krb5_kt_get_type;
+ krb5_kt_have_content;
+ krb5_kt_next_entry;
+ krb5_kt_read_service_key;
+ krb5_kt_register;
+ krb5_kt_remove_entry;
+ krb5_kt_resolve;
+ krb5_kt_start_seq_get;
+ krb5_ktf_ops;
+ krb5_ktf_writable_ops;
+ krb5_kuserok;
+ krb5_lock_file;
+ krb5_make_authdata_kdc_issued;
+ krb5_make_full_ipaddr;
+ krb5_make_fulladdr;
+ krb5_marshal_credentials;
+ krb5_mcc_ops;
+ krb5_merge_authdata;
+ krb5_mk_1cred;
+ krb5_mk_error;
+ krb5_mk_ncred;
+ krb5_mk_priv;
+ krb5_mk_rep;
+ krb5_mk_rep_dce;
+ krb5_mk_req;
+ krb5_mk_req_extended;
+ krb5_mk_safe;
+ krb5_net_read;
+ krb5_net_write;
+ krb5_os_localaddr;
+ krb5_overridekeyname;
+ krb5_pac_add_buffer;
+ krb5_pac_free;
+ krb5_pac_get_buffer;
+ krb5_pac_get_types;
+ krb5_pac_init;
+ krb5_pac_parse;
+ krb5_pac_sign;
+ krb5_pac_sign_ext;
+ krb5_pac_verify;
+ krb5_pac_verify_ext;
+ krb5_pac_get_client_info;
+ krb5_parse_name;
+ krb5_parse_name_flags;
+ krb5_prepend_error_message;
+ krb5_principal2salt;
+ krb5_principal2salt_norealm;
+ krb5_principal_compare;
+ krb5_principal_compare_any_realm;
+ krb5_principal_compare_flags;
+ krb5_prompter_posix;
+ krb5_rc_default;
+ krb5_rc_destroy;
+ krb5_rc_get_lifespan;
+ krb5_rc_initialize;
+ krb5_rd_cred;
+ krb5_rd_error;
+ krb5_rd_priv;
+ krb5_rd_rep;
+ krb5_rd_rep_dce;
+ krb5_rd_req;
+ krb5_rd_req_decoded;
+ krb5_rd_req_decoded_anyflag;
+ krb5_rd_safe;
+ krb5_read_message;
+ krb5_read_password;
+ krb5_realm_compare;
+ krb5_recvauth;
+ krb5_recvauth_version;
+ krb5_responder_get_challenge;
+ krb5_responder_list_questions;
+ krb5_responder_set_answer;
+ krb5_responder_otp_get_challenge;
+ krb5_responder_otp_set_answer;
+ krb5_responder_otp_challenge_free;
+ krb5_responder_pkinit_get_challenge;
+ krb5_responder_pkinit_set_answer;
+ krb5_responder_pkinit_challenge_free;
+ krb5_salttype_to_string;
+ krb5_sendauth;
+ krb5_sendto_kdc;
+ krb5_ser_pack_bytes;
+ krb5_ser_pack_int32;
+ krb5_ser_pack_int64;
+ krb5_ser_unpack_bytes;
+ krb5_ser_unpack_int32;
+ krb5_ser_unpack_int64;
+ krb5_server_decrypt_ticket_keytab;
+ krb5_set_config_files;
+ krb5_set_debugging_time;
+ krb5_set_default_realm;
+ krb5_set_default_tgs_enctypes;
+ krb5_set_default_tgs_ktypes;
+ krb5_set_error_message;
+ krb5_set_password;
+ krb5_set_password_using_ccache;
+ krb5_set_principal_realm;
+ krb5_set_real_time;
+ krb5_set_kdc_send_hook;
+ krb5_set_kdc_recv_hook;
+ krb5_set_time_offsets;
+ krb5_set_trace_callback;
+ krb5_set_trace_filename;
+ krb5_sname_match;
+ krb5_sname_to_principal;
+ krb5_string_to_deltat;
+ krb5_string_to_salttype;
+ krb5_string_to_timestamp;
+ krb5int_tgtname;
+ krb5_tkt_creds_free;
+ krb5_tkt_creds_get;
+ krb5_tkt_creds_get_creds;
+ krb5_tkt_creds_get_times;
+ krb5_tkt_creds_init;
+ krb5_tkt_creds_step;
+ krb5_timeofday;
+ krb5_timestamp_to_sfstring;
+ krb5_timestamp_to_string;
+ krb5_unlock_file;
+ krb5_unmarshal_credentials;
+ krb5_unpack_full_ipaddr;
+ krb5_unparse_name;
+ krb5_unparse_name_ext;
+ krb5_unparse_name_flags;
+ krb5_unparse_name_flags_ext;
+ krb5_us_timeofday;
+ krb5_use_natural_time;
+ krb5_verify_authdata_kdc_issued;
+ krb5_verify_init_creds;
+ krb5_verify_init_creds_opt_init;
+ krb5_verify_init_creds_opt_set_ap_req_nofail;
+ krb5_vprepend_error_message;
+ krb5_vset_error_message;
+ krb5_vwrap_error_message;
+ krb5_walk_realm_tree;
+ krb5_wrap_error_message;
+ krb5_write_message;
+ krb5int_accessor;
+ krb5int_cc_default;
+ krb5int_cleanup_library;
+ krb5int_copy_data_contents;
+ krb5int_copy_data_contents_add0;
+ krb5int_find_pa_data;
+ krb5int_foreach_localaddr;
+ krb5int_free_data_list;
+ krb5int_get_authdata_containee_types;
+ krb5int_init_context_kdc;
+ krb5int_initialize_library;
+ krb5int_parse_enctype_list;
+ krb5int_random_string;
+ krb5int_trace;
+};
diff --git a/krb5/lib/rpc/Makefile b/krb5/lib/rpc/Makefile
index 13499b184d30..f6dfd014ca3c 100644
--- a/krb5/lib/rpc/Makefile
+++ b/krb5/lib/rpc/Makefile
@@ -17,6 +17,7 @@ LIB= gssrpc
# SHLIB_MAJOR= 4
LDFLAGS=-Wl,--no-undefined
LIBADD= gssapi_krb5 krb5 k5crypto com_err krb5support
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= auth_gss.c \
auth_gssapi.c \
diff --git a/krb5/lib/rpc/version.map b/krb5/lib/rpc/version.map
new file mode 100644
index 000000000000..4a5052b71536
--- /dev/null
+++ b/krb5/lib/rpc/version.map
@@ -0,0 +1,147 @@
+KRB5_RPC_1.0 {
+ global:
+ gssrpc_auth_debug_gss;
+ gssrpc_auth_debug_gssapi;
+ gssrpc_auth_gssapi_create;
+ gssrpc_auth_gssapi_create_default;
+ gssrpc_auth_gssapi_display_status;
+ gssrpc_auth_gssapi_seal_seq;
+ gssrpc_auth_gssapi_unseal_seq;
+ gssrpc_auth_gssapi_unwrap_data;
+ gssrpc_auth_gssapi_wrap_data;
+ gssrpc_authgss_create;
+ gssrpc_authgss_create_default;
+ gssrpc_authgss_get_private_data;
+ gssrpc_authgss_service;
+ gssrpc_authnone_create;
+ gssrpc_authunix_create;
+ gssrpc_authunix_create_default;
+ gssrpc_bindresvport;
+ gssrpc_bindresvport_sa;
+ gssrpc_callrpc;
+ gssrpc_clnt_broadcast;
+ gssrpc_clnt_create;
+ gssrpc_clnt_pcreateerror;
+ gssrpc_clnt_perrno;
+ gssrpc_clnt_perror;
+ gssrpc_clnt_spcreateerror;
+ gssrpc_clnt_sperrno;
+ gssrpc_clnt_sperror;
+ gssrpc_clntraw_create;
+ gssrpc_clnttcp_create;
+ gssrpc_clntudp_bufcreate;
+ gssrpc_clntudp_create;
+ gssrpc_get_myaddress;
+ gssrpc_getrpcport;
+ gssrpc_log_debug;
+ gssrpc_log_hexdump;
+ gssrpc_log_status;
+ gssrpc_misc_debug_gss;
+ gssrpc_misc_debug_gssapi;
+ gssrpc_pmap_getmaps;
+ gssrpc_pmap_getport;
+ gssrpc_pmap_rmtcall;
+ gssrpc_pmap_set;
+ gssrpc_pmap_unset;
+ gssrpc_registerrpc;
+ gssrpc_rpc_createrr;
+ gssrpc_svc_auth_gss_ops;
+ gssrpc_svc_auth_gssapi_ops;
+ gssrpc_svc_auth_none;
+ gssrpc_svc_auth_none_ops;
+ gssrpc_svc_debug_gss;
+ gssrpc_svc_debug_gssapi;
+ gssrpc_svc_fdset;
+ gssrpc_svc_fdset_init;
+ gssrpc_svc_getreq;
+ gssrpc_svc_getreqset;
+ gssrpc_svc_maxfd;
+ gssrpc_svc_register;
+ gssrpc_svc_run;
+ gssrpc_svc_sendreply;
+ gssrpc_svc_unregister;
+ gssrpc_svcauth_gss_get_principal;
+ gssrpc_svcauth_gss_set_log_badauth_func;
+ gssrpc_svcauth_gss_set_log_badauth2_func;
+ gssrpc_svcauth_gss_set_log_badverf_func;
+ gssrpc_svcauth_gss_set_log_miscerr_func;
+ gssrpc_svcauth_gss_set_svc_name;
+ gssrpc_svcauth_gssapi_set_log_badauth_func;
+ gssrpc_svcauth_gssapi_set_log_badauth2_func;
+ gssrpc_svcauth_gssapi_set_log_badverf_func;
+ gssrpc_svcauth_gssapi_set_log_miscerr_func;
+ gssrpc_svcauth_gssapi_set_names;
+ gssrpc_svcauth_gssapi_unset_names;
+ gssrpc_svcerr_auth;
+ gssrpc_svcerr_decode;
+ gssrpc_svcerr_noproc;
+ gssrpc_svcerr_noprog;
+ gssrpc_svcerr_progvers;
+ gssrpc_svcerr_systemerr;
+ gssrpc_svcerr_weakauth;
+ gssrpc_svcfd_create;
+ gssrpc_svcraw_create;
+ gssrpc_svctcp_create;
+ gssrpc_svcudp_bufcreate;
+ gssrpc_svcudp_create;
+ gssrpc_svcudp_enablecache;
+ gssrpc_xdr_accepted_reply;
+ gssrpc_xdr_array;
+ gssrpc_xdr_authgssapi_creds;
+ gssrpc_xdr_authgssapi_init_arg;
+ gssrpc_xdr_authgssapi_init_res;
+ gssrpc_xdr_authunix_parms;
+ gssrpc_xdr_bool;
+ gssrpc_xdr_bytes;
+ gssrpc_xdr_callhdr;
+ gssrpc_xdr_callmsg;
+ gssrpc_xdr_char;
+ gssrpc_xdr_des_block;
+ gssrpc_xdr_enum;
+ gssrpc_xdr_free;
+ gssrpc_xdr_gss_buf;
+ gssrpc_xdr_int;
+ gssrpc_xdr_int32;
+ gssrpc_xdr_long;
+ gssrpc_xdr_netobj;
+ gssrpc_xdr_opaque;
+ gssrpc_xdr_opaque_auth;
+ gssrpc_xdr_pmap;
+ gssrpc_xdr_pmaplist;
+ gssrpc_xdr_pointer;
+ gssrpc_xdr_reference;
+ gssrpc_xdr_rejected_reply;
+ gssrpc_xdr_replymsg;
+ gssrpc_xdr_rmtcall_args;
+ gssrpc_xdr_rmtcallres;
+ gssrpc_xdr_rpc_gss_buf;
+ gssrpc_xdr_rpc_gss_cred;
+ gssrpc_xdr_rpc_gss_data;
+ gssrpc_xdr_rpc_gss_init_args;
+ gssrpc_xdr_rpc_gss_init_res;
+ gssrpc_xdr_rpc_gss_unwrap_data;
+ gssrpc_xdr_rpc_gss_wrap_data;
+ gssrpc_xdr_short;
+ gssrpc_xdr_sizeof;
+ gssrpc_xdr_string;
+ gssrpc_xdr_u_char;
+ gssrpc_xdr_u_int;
+ gssrpc_xdr_u_int32;
+ gssrpc_xdr_u_long;
+ gssrpc_xdr_u_short;
+ gssrpc_xdr_union;
+ gssrpc_xdr_vector;
+ gssrpc_xdr_void;
+ gssrpc_xdr_wrapstring;
+ gssrpc_xdralloc_create;
+ gssrpc_xdralloc_getdata;
+ gssrpc_xdralloc_release;
+ gssrpc_xdrmem_create;
+ gssrpc_xdrrec_create;
+ gssrpc_xdrrec_endofrecord;
+ gssrpc_xdrrec_eof;
+ gssrpc_xdrrec_skiprecord;
+ gssrpc_xdrstdio_create;
+ gssrpc_xprt_register;
+ gssrpc_xprt_unregister;
+};
diff --git a/krb5/plugins/audit/Makefile b/krb5/plugins/audit/Makefile
index 507cde261300..eb615a3b89f4 100644
--- a/krb5/plugins/audit/Makefile
+++ b/krb5/plugins/audit/Makefile
@@ -16,6 +16,7 @@ PACKAGE= krb5
LIB= kdc_j_encode
LIBDIR= ${PLUGINSDIR}/audit
LDFLAGS=-Wl,--no-undefined
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/audit
diff --git a/krb5/plugins/audit/version.map b/krb5/plugins/audit/version.map
new file mode 100644
index 000000000000..b6d3368df002
--- /dev/null
+++ b/krb5/plugins/audit/version.map
@@ -0,0 +1,10 @@
+KRB5_AUDIT_1.0 {
+ global:
+ kau_j_kdc_stop;
+ kau_j_kdc_start;
+ kau_j_as_req;
+ kau_j_tgs_req;
+ kau_j_tgs_s4u2self;
+ kau_j_tgs_s4u2proxy;
+ kau_j_tgs_u2u;
+};
diff --git a/krb5/plugins/k5tls/Makefile b/krb5/plugins/k5tls/Makefile
index 8af5efb06b80..790794d4744c 100644
--- a/krb5/plugins/k5tls/Makefile
+++ b/krb5/plugins/k5tls/Makefile
@@ -18,6 +18,7 @@ SHLIBDIR= ${LIBDIR}
LIB= k5tls
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5 krb5profile krb5support ssl crypto k5crypto com_err sys
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= notls.c \
openssl.c
diff --git a/krb5/plugins/k5tls/version.map b/krb5/plugins/k5tls/version.map
new file mode 100644
index 000000000000..802628aaaf63
--- /dev/null
+++ b/krb5/plugins/k5tls/version.map
@@ -0,0 +1,4 @@
+KRB5_K5TLS_1.0 {
+ global:
+ tls_k5tls_initvt;
+};
diff --git a/krb5/plugins/kdb/db2/Makefile b/krb5/plugins/kdb/db2/Makefile
index 7526283f37be..a91bea73677b 100644
--- a/krb5/plugins/kdb/db2/Makefile
+++ b/krb5/plugins/kdb/db2/Makefile
@@ -18,6 +18,7 @@ SHLIBDIR= ${LIBDIR}
LIB= db2
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile krb5 com_err k5crypto kadm5srv_mit kdb5 gssrpc gssapi_krb5 krb5support
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= \
adb_openclose.c \
diff --git a/krb5/plugins/kdb/db2/version.map b/krb5/plugins/kdb/db2/version.map
new file mode 100644
index 000000000000..aa524e506fb8
--- /dev/null
+++ b/krb5/plugins/kdb/db2/version.map
@@ -0,0 +1,109 @@
+KRB5_DB2_1.0 {
+ global:
+ __default_hash;
+ __kdb2_add_bigpage;
+ __kdb2_add_ovflpage;
+ __kdb2_addel;
+ __kdb2_big_delete;
+ __kdb2_big_insert;
+ __kdb2_big_keydata;
+ __kdb2_big_return;
+ __kdb2_bt_close;
+ __kdb2_bt_cmp;
+ __kdb2_bt_defcmp;
+ __kdb2_bt_defpfx;
+ __kdb2_bt_deleaf;
+ __kdb2_bt_delete;
+ __kdb2_bt_dmpage;
+ __kdb2_bt_dnpage;
+ __kdb2_bt_dpage;
+ __kdb2_bt_dump;
+ __kdb2_bt_fd;
+ __kdb2_bt_free;
+ __kdb2_bt_get;
+ __kdb2_bt_new;
+ __kdb2_bt_open;
+ __kdb2_bt_pgin;
+ __kdb2_bt_pgout;
+ __kdb2_bt_put;
+ __kdb2_bt_relink;
+ __kdb2_bt_ret;
+ __kdb2_bt_search;
+ __kdb2_bt_seq;
+ __kdb2_bt_setcur;
+ __kdb2_bt_split;
+ __kdb2_bt_stat;
+ __kdb2_bt_sync;
+ __kdb2_call_hash;
+ __kdb2_cursor_creat;
+ __kdb2_dbpanic;
+ __kdb2_delete_page;
+ __kdb2_delpair;
+ __kdb2_expand_table;
+ __kdb2_find_bigpair;
+ __kdb2_free_ovflpage;
+ __kdb2_get_bigkey;
+ __kdb2_get_item;
+ __kdb2_get_item_done;
+ __kdb2_get_item_first;
+ __kdb2_get_item_next;
+ __kdb2_get_item_reset;
+ __kdb2_get_page;
+ __kdb2_hash_open;
+ __kdb2_ibitmap;
+ __kdb2_log2;
+ __kdb2_new_page;
+ __kdb2_ovfl_delete;
+ __kdb2_ovfl_get;
+ __kdb2_ovfl_put;
+ __kdb2_pgin_routine;
+ __kdb2_pgout_routine;
+ __kdb2_put_page;
+ __kdb2_rec_close;
+ __kdb2_rec_delete;
+ __kdb2_rec_dleaf;
+ __kdb2_rec_fd;
+ __kdb2_rec_fmap;
+ __kdb2_rec_fpipe;
+ __kdb2_rec_get;
+ __kdb2_rec_iput;
+ __kdb2_rec_open;
+ __kdb2_rec_put;
+ __kdb2_rec_ret;
+ __kdb2_rec_search;
+ __kdb2_rec_seq;
+ __kdb2_rec_sync;
+ __kdb2_rec_vmap;
+ __kdb2_rec_vpipe;
+ __kdb2_split_page;
+ kdb2_dbm_clearerr;
+ kdb2_dbm_close;
+ kdb2_dbm_delete;
+ kdb2_dbm_dirfno;
+ kdb2_dbm_error;
+ kdb2_dbm_fetch;
+ kdb2_dbm_firstkey;
+ kdb2_dbm_nextkey;
+ kdb2_dbm_open;
+ kdb2_dbm_store;
+ kdb2_dbminit;
+ kdb2_dbopen;
+ kdb2_delete;
+ kdb2_fetch;
+ kdb2_firstkey;
+ kdb2_hcreate;
+ kdb2_hdestroy;
+ kdb2_hsearch;
+ kdb2_mpool_close;
+ kdb2_mpool_delete;
+ kdb2_mpool_filter;
+ kdb2_mpool_get;
+ kdb2_mpool_new;
+ kdb2_mpool_open;
+ kdb2_mpool_put;
+ kdb2_mpool_stat;
+ kdb2_mpool_sync;
+ kdb2_nextkey;
+ kdb2_store;
+ kdb_function_table;
+};
diff --git a/krb5/plugins/preauth/otp/Makefile b/krb5/plugins/preauth/otp/Makefile
index 9222f9785a80..724d8df16230 100644
--- a/krb5/plugins/preauth/otp/Makefile
+++ b/krb5/plugins/preauth/otp/Makefile
@@ -17,6 +17,7 @@ LIB= otp
LIBDIR= ${PLUGINSDIR}/preauth
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile krad verto krb5 k5crypto com_err krb5support m
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/preauth/otp
diff --git a/krb5/plugins/preauth/otp/version.map b/krb5/plugins/preauth/otp/version.map
new file mode 100644
index 000000000000..9d2ee5ea7213
--- /dev/null
+++ b/krb5/plugins/preauth/otp/version.map
@@ -0,0 +1,4 @@
+KRB5_PREAUTH_OTP {
+ global:
+ kdcpreauth_otp_initvt;
+};
diff --git a/krb5/plugins/preauth/pkinit/Makefile b/krb5/plugins/preauth/pkinit/Makefile
index f2a76d1e33da..600b02b02346 100644
--- a/krb5/plugins/preauth/pkinit/Makefile
+++ b/krb5/plugins/preauth/pkinit/Makefile
@@ -17,6 +17,7 @@ LIB= pkinit
LIBDIR= ${PLUGINSDIR}/preauth
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile krb5 com_err k5crypto crypto krb5support
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/preauth/pkinit
diff --git a/krb5/plugins/preauth/pkinit/version.map b/krb5/plugins/preauth/pkinit/version.map
new file mode 100644
index 000000000000..39a9f81f83ef
--- /dev/null
+++ b/krb5/plugins/preauth/pkinit/version.map
@@ -0,0 +1,5 @@
+KRB5_PREAUTH_PKINIT_1.0 {
+ global:
+ clpreauth_pkinit_initvt;
+ kdcpreauth_pkinit_initvt;
+};
diff --git a/krb5/plugins/preauth/spake/Makefile b/krb5/plugins/preauth/spake/Makefile
index a5d9179f8adc..62d8a5aa9574 100644
--- a/krb5/plugins/preauth/spake/Makefile
+++ b/krb5/plugins/preauth/spake/Makefile
@@ -17,6 +17,7 @@ LIB= spake
LIBDIR= ${PLUGINSDIR}/preauth
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile krb5 k5crypto com_err krb5support crypto sys
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/preauth/spake
diff --git a/krb5/plugins/preauth/spake/version.map b/krb5/plugins/preauth/spake/version.map
new file mode 100644
index 000000000000..7763f289c80d
--- /dev/null
+++ b/krb5/plugins/preauth/spake/version.map
@@ -0,0 +1,5 @@
+KRB5_PLUGINS_SPAKE_1.0 {
+ global:
+ clpreauth_spake_initvt;
+ kdcpreauth_spake_initvt;
+};
diff --git a/krb5/plugins/preauth/test/Makefile b/krb5/plugins/preauth/test/Makefile
index 71b7200b2039..411868e9a1d1 100644
--- a/krb5/plugins/preauth/test/Makefile
+++ b/krb5/plugins/preauth/test/Makefile
@@ -17,6 +17,7 @@ LIB= test
LIBDIR= ${PLUGINSDIR}/preauth
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5 k5crypto com_err krb5support
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/preauth/test
diff --git a/krb5/plugins/preauth/test/version.map b/krb5/plugins/preauth/test/version.map
new file mode 100644
index 000000000000..e27e14869833
--- /dev/null
+++ b/krb5/plugins/preauth/test/version.map
@@ -0,0 +1,5 @@
+KRB5_PREAUTH_TEST_1.0 {
+ global:
+ clpreauth_test_initvt;
+ kdcpreauth_test_initvt;
+};
diff --git a/krb5/util/et/Makefile b/krb5/util/et/Makefile
index 4457cd199801..16b700fb5d1f 100644
--- a/krb5/util/et/Makefile
+++ b/krb5/util/et/Makefile
@@ -18,6 +18,7 @@ LIB= com_err
LDFLAGS=-Wl,--no-undefined
INCSDIR=${INCLUDEDIR}
LIBADD= krb5support
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= com_err.c \
diff --git a/krb5/util/et/version.map b/krb5/util/et/version.map
new file mode 100644
index 000000000000..be846b139ebc
--- /dev/null
+++ b/krb5/util/et/version.map
@@ -0,0 +1,12 @@
+KRB5_ET_1.0 {
+ global:
+ add_error_table;
+ com_err;
+ com_err_va;
+ error_message;
+ error_table_name;
+ error_table_name_r;
+ remove_error_table;
+ reset_com_err_hook;
+ set_com_err_hook;
+};
diff --git a/krb5/util/profile/Makefile b/krb5/util/profile/Makefile
index 24e06e8c5024..72ef3176ab5d 100644
--- a/krb5/util/profile/Makefile
+++ b/krb5/util/profile/Makefile
@@ -15,6 +15,7 @@ PACKAGE= krb5
LIB= krb5profile
LIBADD= com_err krb5support
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= prof_file.c \
prof_get.c \
diff --git a/krb5/util/profile/version.map b/krb5/util/profile/version.map
new file mode 100644
index 000000000000..d7fd0059983d
--- /dev/null
+++ b/krb5/util/profile/version.map
@@ -0,0 +1,33 @@
+KRB5_PROFILE_1.0 {
+ global:
+ et_prof_error_table;
+ initialize_prof_error_table;
+ profile_abandon;
+ profile_add_relation;
+ profile_clear_relation;
+ profile_flush;
+ profile_free_list;
+ profile_get_boolean;
+ profile_get_integer;
+ profile_get_relation_names;
+ profile_get_string;
+ profile_get_subsection_names;
+ profile_get_values;
+ profile_init;
+ profile_init_flags;
+ profile_init_path;
+ profile_init_vtable;
+ profile_iterator;
+ profile_iterator_create;
+ profile_iterator_free;
+ profile_release;
+ profile_release_string;
+ profile_rename_section;
+ profile_ser_externalize;
+ profile_ser_internalize;
+ profile_ser_size;
+ profile_update_relation;
+ profile_flush_to_file;
+ profile_flush_to_buffer;
+ profile_free_buffer;
+};
diff --git a/krb5/util/support/Makefile b/krb5/util/support/Makefile
index 9ba1b8169d8e..25ef7faf74ee 100644
--- a/krb5/util/support/Makefile
+++ b/krb5/util/support/Makefile
@@ -16,6 +16,7 @@ PACKAGE= krb5-lib
LIB= krb5support
# SHLIB_MAJOR= 0
LDFLAGS=-Wl,--no-undefined
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/util/support
diff --git a/krb5/util/support/version.map b/krb5/util/support/version.map
new file mode 100644
index 000000000000..f4de213d33d9
--- /dev/null
+++ b/krb5/util/support/version.map
@@ -0,0 +1,102 @@
+KRB5_SUPPORT_1.0 {
+ global:
+ k5_base64_decode;
+ k5_base64_encode;
+ k5_bcmp;
+ k5_buf_init_fixed;
+ k5_buf_init_dynamic;
+ k5_buf_init_dynamic_zap;
+ k5_buf_add;
+ k5_buf_add_len;
+ k5_buf_add_fmt;
+ k5_buf_add_vfmt;
+ k5_buf_cstring;
+ k5_buf_get_space;
+ k5_buf_truncate;
+ k5_buf_status;
+ k5_buf_free;
+ k5_set_error;
+ k5_vset_error;
+ k5_get_error;
+ k5_free_error;
+ k5_clear_error;
+ k5_set_error_info_callout_fn;
+ k5_hashtab_add;
+ k5_hashtab_create;
+ k5_hashtab_free;
+ k5_hashtab_get;
+ k5_hashtab_remove;
+ k5_hex_decode;
+ k5_hex_encode;
+ k5_json_array_add;
+ k5_json_array_create;
+ k5_json_array_fmt;
+ k5_json_array_get;
+ k5_json_array_length;
+ k5_json_array_set;
+ k5_json_bool_create;
+ k5_json_bool_value;
+ k5_json_decode;
+ k5_json_encode;
+ k5_json_get_tid;
+ k5_json_null_create;
+ k5_json_null_create_val;
+ k5_json_number_create;
+ k5_json_number_value;
+ k5_json_object_count;
+ k5_json_object_create;
+ k5_json_object_get;
+ k5_json_object_iterate;
+ k5_json_object_set;
+ k5_json_release;
+ k5_json_retain;
+ k5_json_string_create;
+ k5_json_string_create_base64;
+ k5_json_string_create_len;
+ k5_json_string_unbase64;
+ k5_json_string_utf8;
+ k5_os_mutex_init;
+ k5_os_mutex_destroy;
+ k5_os_mutex_lock;
+ k5_os_mutex_unlock;
+ k5_once;
+ k5_path_isabs;
+ k5_path_join;
+ k5_path_split;
+ k5_siphash24;
+ k5_strerror_r;
+ k5_utf8_to_utf16le;
+ k5_utf16le_to_utf8;
+ k5_dir_filenames;
+ k5_free_filenames;
+ krb5int_key_register;
+ krb5int_key_delete;
+ krb5int_getspecific;
+ krb5int_setspecific;
+ krb5int_getaddrinfo;
+ krb5int_freeaddrinfo;
+ krb5int_gai_strerror;
+ krb5int_getnameinfo;
+ krb5int_in6addr_any;
+ krb5int_pthread_loaded;
+ krb5int_open_plugin;
+ krb5int_close_plugin;
+ krb5int_get_plugin_data;
+ krb5int_get_plugin_func;
+ krb5int_open_plugin_dirs;
+ krb5int_close_plugin_dirs;
+ krb5int_get_plugin_dir_data;
+ krb5int_get_plugin_dir_func;
+ krb5int_free_plugin_dir_data;
+ krb5int_free_plugin_dir_func;
+ krb5int_mutex_alloc;
+ krb5int_mutex_free;
+ krb5int_mutex_lock;
+ krb5int_mutex_unlock;
+ krb5int_gmt_mktime;
+ krb5int_ucs4_to_utf8;
+ krb5int_utf8_to_ucs4;
+ krb5int_utf8_lentab;
+ krb5int_utf8_mintab;
+ krb5int_zap;
+};
diff --git a/krb5/util/verto/Makefile b/krb5/util/verto/Makefile
index 57367e5284e0..18faddb3a09e 100644
--- a/krb5/util/verto/Makefile
+++ b/krb5/util/verto/Makefile
@@ -15,6 +15,7 @@ PACKAGE= krb5
LIB= verto
# SHLIB_MAJOR= 0
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/util/verto
diff --git a/krb5/util/verto/libverto.exports b/krb5/util/verto/libverto.exports
new file mode 100644
index 000000000000..3745d5014653
--- /dev/null
+++ b/krb5/util/verto/libverto.exports
@@ -0,0 +1,33 @@
+verto_add_child
+verto_add_idle
+verto_add_io
+verto_add_signal
+verto_add_timeout
+verto_break
+verto_cleanup
+verto_convert_module
+verto_default
+verto_del
+verto_fire
+verto_free
+verto_get_ctx
+verto_get_fd
+verto_get_fd_state
+verto_get_flags
+verto_get_interval
+verto_get_private
+verto_get_proc
+verto_get_proc_status
+verto_get_signal
+verto_get_supported_types
+verto_get_type
+verto_new
+verto_reinitialize
+verto_run
+verto_run_once
+verto_set_allocator
+verto_set_default
+verto_set_fd_state
+verto_set_flags
+verto_set_private
+verto_set_proc_status
diff --git a/krb5/util/verto/version.map b/krb5/util/verto/version.map
new file mode 100644
index 000000000000..5fc734e25d3a
--- /dev/null
+++ b/krb5/util/verto/version.map
@@ -0,0 +1,36 @@
+KRB5_VERTO_1.0 {
+ global:
+ verto_add_child;
+ verto_add_idle;
+ verto_add_io;
+ verto_add_signal;
+ verto_add_timeout;
+ verto_break;
+ verto_cleanup;
+ verto_convert_module;
+ verto_default;
+ verto_del;
+ verto_fire;
+ verto_free;
+ verto_get_ctx;
+ verto_get_fd;
+ verto_get_fd_state;
+ verto_get_flags;
+ verto_get_interval;
+ verto_get_private;
+ verto_get_proc;
+ verto_get_proc_status;
+ verto_get_signal;
+ verto_get_supported_types;
+ verto_get_type;
+ verto_new;
+ verto_reinitialize;
+ verto_run;
+ verto_run_once;
+ verto_set_allocator;
+ verto_set_default;
+ verto_set_fd_state;
+ verto_set_flags;
+ verto_set_private;
+ verto_set_proc_status;
+};
diff --git a/lib/clang/libclang/Makefile b/lib/clang/libclang/Makefile
index dc9e0010e309..7eb2c99b25c8 100644
--- a/lib/clang/libclang/Makefile
+++ b/lib/clang/libclang/Makefile
@@ -841,6 +841,11 @@ SRCS_MIN+= Tooling/ArgumentsAdjusters.cpp
SRCS_MIN+= Tooling/CommonOptionsParser.cpp
SRCS_MIN+= Tooling/CompilationDatabase.cpp
SRCS_MIN+= Tooling/Core/Replacement.cpp
+SRCS_MIN+= Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
+SRCS_MIN+= Tooling/DependencyScanning/DependencyScanningService.cpp
+SRCS_MIN+= Tooling/DependencyScanning/DependencyScanningTool.cpp
+SRCS_MIN+= Tooling/DependencyScanning/DependencyScanningWorker.cpp
+SRCS_MIN+= Tooling/DependencyScanning/ModuleDepCollector.cpp
SRCS_MIN+= Tooling/ExpandResponseFilesCompilationDatabase.cpp
SRCS_MIN+= Tooling/FileMatchTrie.cpp
SRCS_MIN+= Tooling/GuessTargetAndModeCompilationDatabase.cpp
@@ -848,6 +853,7 @@ SRCS_MIN+= Tooling/Inclusions/HeaderIncludes.cpp
SRCS_MIN+= Tooling/Inclusions/IncludeStyle.cpp
SRCS_MIN+= Tooling/InterpolatingCompilationDatabase.cpp
SRCS_MIN+= Tooling/JSONCompilationDatabase.cpp
+SRCS_MIN+= Tooling/LocateToolCompilationDatabase.cpp
SRCS_MIN+= Tooling/Refactoring.cpp
SRCS_MIN+= Tooling/RefactoringCallbacks.cpp
SRCS_MIN+= Tooling/Tooling.cpp
diff --git a/lib/lib80211/regdomain.xml b/lib/lib80211/regdomain.xml
index 9116e54c31cf..16b74445f429 100644
--- a/lib/lib80211/regdomain.xml
+++ b/lib/lib80211/regdomain.xml
@@ -494,6 +494,10 @@
<flags>IEEE80211_CHAN_PASSIVE</flags>
<flags>IEEE80211_CHAN_DFS</flags>
</band>
+ <band>
+ <freqband ref="A20_5745_5865"/>
+ <maxpower>13</maxpower>
+ </band>
</netband>
<netband mode="11ng">
<band>
@@ -548,6 +552,14 @@
<flags>IEEE80211_CHAN_PASSIVE</flags>
<flags>IEEE80211_CHAN_DFS</flags>
</band>
+ <band>
+ <freqband ref="NA20_5745_5865"/>
+ <maxpower>13</maxpower>
+ </band>
+ <band>
+ <freqband ref="NA40_5745_5845"/>
+ <maxpower>13</maxpower>
+ </band>
</netband>
<netband mode="11ac">
<!-- 5150-5250/80, 200 mW, indoor -->
@@ -645,7 +657,7 @@
<flags>IEEE80211_CHAN_DFS</flags>
</band>
<band>
- <freqband ref="AC2_5745_5805_40"/>
+ <freqband ref="AC2_5745_5845_40"/>
<maxpower>13</maxpower>
<flags>IEEE80211_CHAN_HT40</flags>
<flags>IEEE80211_CHAN_VHT40</flags>
@@ -658,13 +670,6 @@
<flags>IEEE80211_CHAN_VHT80</flags>
<flags>IEEE80211_CHAN_DFS</flags>
</band>
- <band>
- <freqband ref="AC2_5745_5885_160"/>
- <maxpower>13</maxpower>
- <flags>IEEE80211_CHAN_HT40</flags>
- <flags>IEEE80211_CHAN_VHT160</flags>
- <flags>IEEE80211_CHAN_DFS</flags>
- </band>
</netband>
</rd>
@@ -2304,6 +2309,29 @@
<chanwidth>20</chanwidth> <chansep>20</chansep>
<flags>IEEE80211_CHAN_A</flags>
</freqband>
+<freqband id="A20_5745_5865">
+ <freqstart>5745</freqstart>
+ <freqend>5865</freqend>
+ <chanwidth>20</chanwidth>
+ <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="NA20_5745_5865">
+ <freqstart>5745</freqstart>
+ <freqend>5865</freqend>
+ <chanwidth>20</chanwidth>
+ <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+ <flags>IEEE80211_CHAN_HT20</flags>
+</freqband>
+<freqband id="NA40_5745_5845">
+ <freqstart>5745</freqstart>
+ <freqend>5845</freqend>
+ <chanwidth>40</chanwidth>
+ <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+ <flags>IEEE80211_CHAN_HT40</flags>
+</freqband>
<freqband id="F1_5660_5700">
<freqstart>5660</freqstart> <freqend>5700</freqend>
<chanwidth>20</chanwidth> <chansep>20</chansep>
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index ad13aaa65621..4d064d18d36e 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -89,6 +89,7 @@ SRCS+= \
glob.c \
glob-compat11.c \
initgroups.c \
+ inotify.c \
isatty.c \
isinf.c \
isnan.c \
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index 8faecf4b3048..26f638568efc 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -458,12 +458,13 @@ FBSD_1.8 {
aio_read2;
aio_write2;
execvpe;
- fscandir;
- fscandir_b;
fdscandir;
fdscandir_b;
fts_open_b;
glob_b;
+ inotify_add_watch;
+ inotify_init;
+ inotify_init1;
psiginfo;
rtld_get_var;
rtld_set_var;
@@ -595,7 +596,6 @@ FBSDprivate_1.0 {
__libc_tcdrain;
- __pthread_distribute_static_tls;
__pthread_map_stacks_exec;
__fillcontextx;
__fillcontextx2;
diff --git a/lib/libc/gen/dup3.3 b/lib/libc/gen/dup3.3
index f2798930797b..338a9ae74c64 100644
--- a/lib/libc/gen/dup3.3
+++ b/lib/libc/gen/dup3.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 16, 2013
+.Dd May 17, 2025
.Dt DUP3 3
.Os
.Sh NAME
@@ -47,6 +47,11 @@ The close-on-exec flag on the new file descriptor is determined by the
bit in
.Fa flags .
.Pp
+The close-on-fork flag on the new file descriptor is determined by the
+.Dv O_CLOFORK
+bit in
+.Fa flags .
+.Pp
If
.Fa oldd
\*(Ne
@@ -91,7 +96,9 @@ argument.
The
.Fa flags
argument has bits set other than
-.Dv O_CLOEXEC .
+.Dv O_CLOEXEC
+or
+.Dv O_CLOFORK .
.El
.Sh SEE ALSO
.Xr accept 2 ,
@@ -112,3 +119,7 @@ The
.Fn dup3
function appeared in
.Fx 10.0 .
+The
+.Dv O_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libc/gen/dup3.c b/lib/libc/gen/dup3.c
index fca1e99fb47b..1401c1f5b607 100644
--- a/lib/libc/gen/dup3.c
+++ b/lib/libc/gen/dup3.c
@@ -39,21 +39,22 @@ int __dup3(int, int, int);
int
__dup3(int oldfd, int newfd, int flags)
{
- int how;
+ int fdflags;
if (oldfd == newfd) {
errno = EINVAL;
return (-1);
}
- if (flags & ~O_CLOEXEC) {
+ if ((flags & ~(O_CLOEXEC | O_CLOFORK)) != 0) {
errno = EINVAL;
return (-1);
}
- how = (flags & O_CLOEXEC) ? F_DUP2FD_CLOEXEC : F_DUP2FD;
+ fdflags = ((flags & O_CLOEXEC) != 0 ? FD_CLOEXEC : 0) |
+ ((flags & O_CLOFORK) != 0 ? FD_CLOFORK : 0);
- return (_fcntl(oldfd, how, newfd));
+ return (_fcntl(oldfd, F_DUP3FD | (fdflags << F_DUP3FD_SHIFT), newfd));
}
__weak_reference(__dup3, dup3);
diff --git a/lib/libc/gen/elf_utils.c b/lib/libc/gen/elf_utils.c
index 330aa8f17f7e..3714a0dc42b5 100644
--- a/lib/libc/gen/elf_utils.c
+++ b/lib/libc/gen/elf_utils.c
@@ -41,7 +41,6 @@
#include "libc_private.h"
void __pthread_map_stacks_exec(void);
-void __pthread_distribute_static_tls(size_t, void *, size_t, size_t);
int
__elf_phdr_match_addr(struct dl_phdr_info *phdr_info, void *addr)
@@ -105,28 +104,3 @@ __pthread_map_stacks_exec(void)
((void (*)(void))__libc_interposing[INTERPOS_map_stacks_exec])();
}
-
-void
-__libc_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
- char *tlsbase;
-
-#ifdef TLS_VARIANT_I
- tlsbase = (char *)_tcb_get() + offset;
-#else
- tlsbase = (char *)_tcb_get() - offset;
-#endif
- memcpy(tlsbase, src, len);
- memset(tlsbase + len, 0, total_len - len);
-}
-
-#pragma weak __pthread_distribute_static_tls
-void
-__pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
-
- ((void (*)(size_t, void *, size_t, size_t))__libc_interposing[
- INTERPOS_distribute_static_tls])(offset, src, len, total_len);
-}
diff --git a/lib/libc/gen/err.c b/lib/libc/gen/err.c
index 24ea242560b8..16cbe27693e7 100644
--- a/lib/libc/gen/err.c
+++ b/lib/libc/gen/err.c
@@ -30,9 +30,12 @@
*/
#include "namespace.h"
+#include <sys/exterrvar.h>
#include <err.h>
#include <errno.h>
+#include <exterr.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -43,6 +46,11 @@
static FILE *err_file; /* file to use for error output */
static void (*err_exit)(int);
+static void verrci(bool doexterr, int eval, int code, const char *fmt,
+ va_list ap) __printf0like(4, 0) __dead2;
+static void vwarnci(bool doexterr, int code, const char *fmt, va_list ap)
+ __printf0like(3, 0);
+
/*
* This is declared to take a `void *' so that the caller is not required
* to include <stdio.h> first. However, it is really a `FILE *', and the
@@ -70,14 +78,14 @@ _err(int eval, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- verrc(eval, errno, fmt, ap);
+ verrci(true, eval, errno, fmt, ap);
va_end(ap);
}
void
verr(int eval, const char *fmt, va_list ap)
{
- verrc(eval, errno, fmt, ap);
+ verrci(true, eval, errno, fmt, ap);
}
void
@@ -85,13 +93,24 @@ errc(int eval, int code, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- verrc(eval, code, fmt, ap);
+ verrci(false, eval, code, fmt, ap);
va_end(ap);
}
void
verrc(int eval, int code, const char *fmt, va_list ap)
{
+ verrci(false, eval, code, fmt, ap);
+}
+
+static void
+vexterr(bool doexterr, int code, const char *fmt, va_list ap)
+{
+ char exterr[UEXTERROR_MAXLEN]; /* libc knows the buffer size */
+ int extstatus;
+
+ if (doexterr)
+ extstatus = uexterr_gettext(exterr, sizeof(exterr));
if (err_file == NULL)
err_set_file(NULL);
fprintf(err_file, "%s: ", _getprogname());
@@ -99,7 +118,16 @@ verrc(int eval, int code, const char *fmt, va_list ap)
vfprintf(err_file, fmt, ap);
fprintf(err_file, ": ");
}
- fprintf(err_file, "%s\n", strerror(code));
+ fprintf(err_file, "%s", strerror(code));
+ if (doexterr && extstatus == 0 && exterr[0] != '\0')
+ fprintf(err_file, " (extended error %s)", exterr);
+ fprintf(err_file, "\n");
+}
+
+static void
+verrci(bool doexterr, int eval, int code, const char *fmt, va_list ap)
+{
+ vexterr(doexterr, code, fmt, ap);
if (err_exit)
err_exit(eval);
exit(eval);
@@ -157,17 +185,16 @@ warnc(int code, const char *fmt, ...)
void
vwarnc(int code, const char *fmt, va_list ap)
{
+ vwarnci(false, code, fmt, ap);
+}
+
+static void
+vwarnci(bool doexterr, int code, const char *fmt, va_list ap)
+{
int saved_errno;
saved_errno = errno;
- if (err_file == NULL)
- err_set_file(NULL);
- fprintf(err_file, "%s: ", _getprogname());
- if (fmt != NULL) {
- vfprintf(err_file, fmt, ap);
- fprintf(err_file, ": ");
- }
- fprintf(err_file, "%s\n", strerror(code));
+ vexterr(doexterr, code, fmt, ap);
errno = saved_errno;
}
diff --git a/lib/libc/gen/fdopendir.c b/lib/libc/gen/fdopendir.c
index 67c0766b6d83..9393cbe28f85 100644
--- a/lib/libc/gen/fdopendir.c
+++ b/lib/libc/gen/fdopendir.c
@@ -30,14 +30,13 @@
*/
#include "namespace.h"
-#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
+#include <stdbool.h>
#include "un-namespace.h"
#include "gen-private.h"
@@ -49,8 +48,16 @@
DIR *
fdopendir(int fd)
{
+ int flags, rc;
- if (_fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ flags = _fcntl(fd, F_GETFD, 0);
+ if (flags == -1)
return (NULL);
+
+ if ((flags & FD_CLOEXEC) == 0) {
+ rc = _fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ if (rc == -1)
+ return (NULL);
+ }
return (__opendir_common(fd, DTF_HIDEW | DTF_NODUP, true));
}
diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3
index 5860d1be1a1e..ee558b892c8c 100644
--- a/lib/libc/gen/fts.3
+++ b/lib/libc/gen/fts.3
@@ -394,7 +394,7 @@ must be specified.
The options are selected by
.Em or Ns 'ing
the following values:
-.Bl -tag -width "FTS_PHYSICAL"
+.Bl -tag -width "FTS_COMFOLLOWDIR"
.It Dv FTS_COMFOLLOW
This option causes any symbolic link specified as a root path to be
followed immediately whether or not
diff --git a/lib/libc/gen/gen-private.h b/lib/libc/gen/gen-private.h
index 3792a61ff942..b6749b3435cd 100644
--- a/lib/libc/gen/gen-private.h
+++ b/lib/libc/gen/gen-private.h
@@ -43,8 +43,8 @@ struct pthread_mutex;
*/
struct _dirdesc {
int dd_fd; /* file descriptor associated with directory */
- long dd_loc; /* offset in current buffer */
- long dd_size; /* amount of data returned by getdirentries */
+ size_t dd_loc; /* offset in current buffer */
+ size_t dd_size; /* amount of data returned by getdirentries */
char *dd_buf; /* data buffer */
int dd_len; /* size of data buffer */
off_t dd_seek; /* magic cookie returned by getdirentries */
diff --git a/lib/libc/gen/inotify.c b/lib/libc/gen/inotify.c
new file mode 100644
index 000000000000..7ce53aaccd58
--- /dev/null
+++ b/lib/libc/gen/inotify.c
@@ -0,0 +1,48 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Klara, Inc.
+ */
+
+#include "namespace.h"
+#include <sys/fcntl.h>
+#include <sys/inotify.h>
+#include <sys/specialfd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+/*
+ * Provide compatibility with libinotify, which uses different values for these
+ * flags.
+ */
+#define IN_NONBLOCK_OLD 0x80000
+#define IN_CLOEXEC_OLD 0x00800
+
+int
+inotify_add_watch(int fd, const char *pathname, uint32_t mask)
+{
+ return (inotify_add_watch_at(fd, AT_FDCWD, pathname, mask));
+}
+
+int
+inotify_init1(int flags)
+{
+ struct specialfd_inotify args;
+
+ if ((flags & IN_NONBLOCK_OLD) != 0) {
+ flags &= ~IN_NONBLOCK_OLD;
+ flags |= IN_NONBLOCK;
+ }
+ if ((flags & IN_CLOEXEC_OLD) != 0) {
+ flags &= ~IN_CLOEXEC_OLD;
+ flags |= IN_CLOEXEC;
+ }
+ args.flags = flags;
+ return (__sys___specialfd(SPECIALFD_INOTIFY, &args, sizeof(args)));
+}
+
+int
+inotify_init(void)
+{
+ return (inotify_init1(0));
+}
diff --git a/lib/libc/gen/libc_interposing_table.c b/lib/libc/gen/libc_interposing_table.c
index 8eae6c7f5d95..025a67ac3eac 100644
--- a/lib/libc/gen/libc_interposing_table.c
+++ b/lib/libc/gen/libc_interposing_table.c
@@ -42,7 +42,6 @@ interpos_func_t __libc_interposing[INTERPOS_MAX] = {
SLOT(spinlock, __libc_spinlock_stub),
SLOT(spinunlock, __libc_spinunlock_stub),
SLOT(map_stacks_exec, __libc_map_stacks_exec),
- SLOT(distribute_static_tls, __libc_distribute_static_tls),
SLOT(uexterr_gettext, __libc_uexterr_gettext),
};
#undef SLOT
diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c
index 956c92c321e8..08d9eb10eaa2 100644
--- a/lib/libc/gen/opendir.c
+++ b/lib/libc/gen/opendir.c
@@ -30,14 +30,7 @@
*/
#include "namespace.h"
-#include <sys/param.h>
-
#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include "un-namespace.h"
#include "gen-private.h"
diff --git a/lib/libc/gen/opendir2.c b/lib/libc/gen/opendir2.c
index b9ac23e6d9fd..c5c2e662efd8 100644
--- a/lib/libc/gen/opendir2.c
+++ b/lib/libc/gen/opendir2.c
@@ -30,11 +30,12 @@
*/
#include "namespace.h"
-#include <sys/param.h>
+#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -52,8 +53,7 @@ __opendir2(const char *name, int flags)
if ((flags & (__DTF_READALL | __DTF_SKIPREAD)) != 0)
return (NULL);
- if ((fd = _open(name,
- O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)) == -1)
+ if ((fd = _open(name, O_DIRECTORY | O_RDONLY | O_CLOEXEC)) == -1)
return (NULL);
dir = __opendir_common(fd, flags, false);
@@ -264,6 +264,7 @@ DIR *
__opendir_common(int fd, int flags, bool use_current_pos)
{
DIR *dirp;
+ ssize_t ret;
int incr;
int saved_errno;
bool unionstack;
@@ -313,13 +314,11 @@ __opendir_common(int fd, int flags, bool use_current_pos)
* to prime dd_seek. This also checks if the
* fd passed to fdopendir() is a directory.
*/
- dirp->dd_size = _getdirentries(dirp->dd_fd,
+ ret = _getdirentries(dirp->dd_fd,
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
- if (dirp->dd_size < 0) {
- if (errno == EINVAL)
- errno = ENOTDIR;
+ if (ret < 0)
goto fail;
- }
+ dirp->dd_size = (size_t)ret;
dirp->dd_flags |= __DTF_SKIPREAD;
} else {
dirp->dd_size = 0;
diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c
index 2a2fa999b7ce..b70102954df1 100644
--- a/lib/libc/gen/readdir.c
+++ b/lib/libc/gen/readdir.c
@@ -48,8 +48,9 @@ struct dirent *
_readdir_unlocked(DIR *dirp, int flags)
{
struct dirent *dp;
- long initial_seek;
- long initial_loc = 0;
+ off_t initial_seek;
+ size_t initial_loc = 0;
+ ssize_t ret;
for (;;) {
if (dirp->dd_loc >= dirp->dd_size) {
@@ -61,11 +62,13 @@ _readdir_unlocked(DIR *dirp, int flags)
}
if (dirp->dd_loc == 0 &&
!(dirp->dd_flags & (__DTF_READALL | __DTF_SKIPREAD))) {
+ dirp->dd_size = 0;
initial_seek = dirp->dd_seek;
- dirp->dd_size = _getdirentries(dirp->dd_fd,
+ ret = _getdirentries(dirp->dd_fd,
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
- if (dirp->dd_size <= 0)
+ if (ret <= 0)
return (NULL);
+ dirp->dd_size = (size_t)ret;
_fixtelldir(dirp, initial_seek, initial_loc);
}
dirp->dd_flags &= ~__DTF_SKIPREAD;
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c
index 8e62fe980868..fb589f4b36b6 100644
--- a/lib/libc/gen/scandir.c
+++ b/lib/libc/gen/scandir.c
@@ -252,9 +252,3 @@ scandir_thunk_cmp(const void *p1, const void *p2, void *thunk)
return (dc((const struct dirent **)p1, (const struct dirent **)p2));
}
#endif
-
-#ifdef I_AM_SCANDIR_B
-__weak_reference(fdscandir_b, fscandir_b);
-#else
-__weak_reference(fdscandir, fscandir);
-#endif
diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c
index b751fafd975f..1731cc4d7a2c 100644
--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -118,7 +118,7 @@ _seekdir(DIR *dirp, long loc)
struct dirent *dp;
union ddloc_packed ddloc;
off_t loc_seek;
- long loc_loc;
+ size_t loc_loc;
ddloc.l = loc;
@@ -171,7 +171,7 @@ _seekdir(DIR *dirp, long loc)
* fetching a new block to fix any such telldir locations.
*/
void
-_fixtelldir(DIR *dirp, long oldseek, long oldloc)
+_fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc)
{
struct ddloc_mem *lp;
diff --git a/lib/libc/gen/telldir.h b/lib/libc/gen/telldir.h
index 6d113491e819..02fd52af9060 100644
--- a/lib/libc/gen/telldir.h
+++ b/lib/libc/gen/telldir.h
@@ -46,9 +46,9 @@
*/
struct ddloc_mem {
LIST_ENTRY(ddloc_mem) loc_lqe; /* entry in list */
- long loc_index; /* key associated with structure */
+ size_t loc_index; /* key associated with structure */
off_t loc_seek; /* magic cookie returned by getdirentries */
- long loc_loc; /* offset of entry in buffer */
+ size_t loc_loc; /* offset of entry in buffer */
};
#ifdef __LP64__
@@ -102,7 +102,7 @@ bool _filldir(DIR *, bool);
struct dirent *_readdir_unlocked(DIR *, int);
void _reclaim_telldir(DIR *);
void _seekdir(DIR *, long);
-void _fixtelldir(DIR *dirp, long oldseek, long oldloc);
+void _fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc);
DIR *__opendir_common(int, int, bool);
#define RDU_SKIP 0x0001
diff --git a/lib/libc/gen/uexterr_format.c b/lib/libc/gen/uexterr_format.c
index 32b57ffb6e1a..e8ddfbd578e3 100644
--- a/lib/libc/gen/uexterr_format.c
+++ b/lib/libc/gen/uexterr_format.c
@@ -20,12 +20,16 @@ __uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz)
if (bufsz > UEXTERROR_MAXLEN)
bufsz = UEXTERROR_MAXLEN;
if (ue->error == 0) {
- strlcpy(buf, "No error", bufsz);
+ strlcpy(buf, "", bufsz);
return (0);
}
- snprintf(buf, bufsz,
- "errno %d category %u (src line %u) p1 %#jx p2 %#jx %s",
- ue->error, ue->cat, ue->src_line,
- (uintmax_t)ue->p1, (uintmax_t)ue->p2, ue->msg);
+ if (ue->msg[0] == '\0') {
+ snprintf(buf, bufsz,
+ "errno %d category %u (src line %u) p1 %#jx p2 %#jx",
+ ue->error, ue->cat, ue->src_line,
+ (uintmax_t)ue->p1, (uintmax_t)ue->p2);
+ } else {
+ strlcpy(buf, ue->msg, bufsz);
+ }
return (0);
}
diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c
index f1437e30bbe2..f8080c20d121 100644
--- a/lib/libc/gen/wordexp.c
+++ b/lib/libc/gen/wordexp.c
@@ -265,7 +265,15 @@ cleanup:
errno = serrno;
return (error);
}
- if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ /*
+ * Check process exit status, but ignore ECHILD as the child may have
+ * been automatically reaped if the process had set SIG_IGN or
+ * SA_NOCLDWAIT for SIGCHLD, and our reason for waitpid was just to
+ * reap our own child on behalf of the calling process.
+ */
+ if (wpid < 0 && errno != ECHILD)
+ return (WRDE_NOSPACE); /* abort for unknown reason */
+ if (wpid >= 0 && (!WIFEXITED(status) || WEXITSTATUS(status) != 0))
return (WRDE_NOSPACE); /* abort for unknown reason */
/*
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index 1bc22f3931a5..db4cbc32be35 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -249,7 +249,7 @@ enum {
INTERPOS_map_stacks_exec,
INTERPOS_fdatasync,
INTERPOS_clock_nanosleep,
- INTERPOS_distribute_static_tls,
+ INTERPOS__reserved0, /* was distribute_static_tls */
INTERPOS_pdfork,
INTERPOS_uexterr_gettext,
INTERPOS_MAX
@@ -361,8 +361,6 @@ struct dl_phdr_info;
int __elf_phdr_match_addr(struct dl_phdr_info *, void *);
void __init_elf_aux_vector(void);
void __libc_map_stacks_exec(void);
-void __libc_distribute_static_tls(__size_t, void *, __size_t, __size_t);
-__uintptr_t __libc_static_tls_base(__size_t);
void _pthread_cancel_enter(int);
void _pthread_cancel_leave(int);
diff --git a/lib/libc/powerpc64/gen/_ctx_start.S b/lib/libc/powerpc64/gen/_ctx_start.S
index c2f8abfd6486..98225f9c1138 100644
--- a/lib/libc/powerpc64/gen/_ctx_start.S
+++ b/lib/libc/powerpc64/gen/_ctx_start.S
@@ -34,6 +34,16 @@
ld %r2,8(%r14)
ld %r14,0(%r14)
#else
+ /*
+ * The stack frame was already set up in makecontext(),
+ * so we can safely use the guaranteed fields here.
+ *
+ * Note we do step on the allocated stack frame's TOC,
+ * but since we never return from this function (i.e.
+ * never restore the stack frame) this should be safe.
+ */
+ std %r2,24(%r1) /* save TOC */
+
/* Load global entry point */
mr %r12,%r14
#endif
@@ -41,6 +51,10 @@
blrl /* branch to start function */
mr %r3,%r15 /* pass pointer to ucontext as argument */
nop
+#if defined(_CALL_ELF) && _CALL_ELF != 1
+ /* Restore TOC */
+ ld %r2,24(%r1)
+#endif
bl CNAME(_ctx_done) /* branch to ctxt completion func */
/*
* we should never return from the
diff --git a/lib/libc/powerpc64/gen/makecontext.c b/lib/libc/powerpc64/gen/makecontext.c
index 75c2d40bdd60..9e3a976fa1bd 100644
--- a/lib/libc/powerpc64/gen/makecontext.c
+++ b/lib/libc/powerpc64/gen/makecontext.c
@@ -78,7 +78,7 @@ __makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
*/
stackargs = (argc > 8) ? argc - 8 : 0;
sp = (char *) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size
- - sizeof(uintptr_t)*(stackargs + 2);
+ - sizeof(uintptr_t)*(stackargs + 6);
sp = (char *)((uintptr_t)sp & ~0x1f);
mc = &ucp->uc_mcontext;
@@ -119,6 +119,7 @@ __makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
mc->mc_srr0 = *(uintptr_t *)_ctx_start;
#else
mc->mc_srr0 = (uintptr_t) _ctx_start;
+ mc->mc_gpr[12] = (uintptr_t) _ctx_start;/* required for prologue */
#endif
mc->mc_gpr[1] = (uintptr_t) sp; /* new stack pointer */
mc->mc_gpr[14] = (uintptr_t) start; /* r14 <- start */
diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c
index a0d7b71df782..49ec97eda39d 100644
--- a/lib/libc/stdio/fdopen.c
+++ b/lib/libc/stdio/fdopen.c
@@ -46,7 +46,7 @@ FILE *
fdopen(int fd, const char *mode)
{
FILE *fp;
- int flags, oflags, fdflags, tmp;
+ int flags, oflags, fdflags, rc, tmp;
/*
* File descriptors are a full int, but _file is only a short.
@@ -76,9 +76,19 @@ fdopen(int fd, const char *mode)
if ((fp = __sfp()) == NULL)
return (NULL);
- if ((oflags & O_CLOEXEC) && _fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
- fp->_flags = 0;
- return (NULL);
+ if ((oflags & O_CLOEXEC) != 0) {
+ tmp = _fcntl(fd, F_GETFD, 0);
+ if (tmp == -1) {
+ fp->_flags = 0;
+ return (NULL);
+ }
+ if ((tmp & FD_CLOEXEC) == 0) {
+ rc = _fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
+ if (rc == -1) {
+ fp->_flags = 0;
+ return (NULL);
+ }
+ }
}
fp->_flags = flags;
diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c
index f0732b6d6741..048fd30b3193 100644
--- a/lib/libc/stdio/freopen.c
+++ b/lib/libc/stdio/freopen.c
@@ -55,7 +55,7 @@ freopen(const char * __restrict file, const char * __restrict mode,
FILE * __restrict fp)
{
int f;
- int dflags, flags, isopen, oflags, sverrno, wantfd;
+ int dflags, fdflags, flags, isopen, oflags, sverrno, wantfd;
if ((flags = __sflags(mode, &oflags)) == 0) {
sverrno = errno;
@@ -113,8 +113,12 @@ freopen(const char * __restrict file, const char * __restrict mode,
(void) ftruncate(fp->_file, (off_t)0);
if (!(oflags & O_APPEND))
(void) _sseek(fp, (fpos_t)0, SEEK_SET);
- if (oflags & O_CLOEXEC)
- (void) _fcntl(fp->_file, F_SETFD, FD_CLOEXEC);
+ if ((oflags & O_CLOEXEC) != 0) {
+ fdflags = _fcntl(fp->_file, F_GETFD, 0);
+ if (fdflags != -1 && (fdflags & FD_CLOEXEC) == 0)
+ (void) _fcntl(fp->_file, F_SETFD,
+ fdflags | FD_CLOEXEC);
+ }
f = fp->_file;
isopen = 0;
wantfd = -1;
diff --git a/lib/libc/stdio/mktemp.3 b/lib/libc/stdio/mktemp.3
index 2b8b2d6c9e44..8d38dd2cd57e 100644
--- a/lib/libc/stdio/mktemp.3
+++ b/lib/libc/stdio/mktemp.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 29, 2019
+.Dd July 07, 2025
.Dt MKTEMP 3
.Os
.Sh NAME
@@ -101,9 +101,10 @@ The permitted flags are
.Dv O_DIRECT ,
.Dv O_SHLOCK ,
.Dv O_EXLOCK ,
-.Dv O_SYNC
+.Dv O_SYNC ,
+.Dv O_CLOEXEC
and
-.Dv O_CLOEXEC .
+.Dv O_CLOFORK .
.Pp
The
.Fn mkstemps
diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c
index 8aff226acf14..a2f80ee7b0dd 100644
--- a/lib/libc/stdio/mktemp.c
+++ b/lib/libc/stdio/mktemp.c
@@ -121,7 +121,7 @@ _gettemp(int dfd, char *path, int *doopen, int domkdir, int slen, int oflags)
if ((doopen != NULL && domkdir) || slen < 0 ||
(oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC |
- O_CLOEXEC)) != 0) {
+ O_CLOEXEC | O_CLOFORK)) != 0) {
errno = EINVAL;
return (0);
}
diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc
index 5d0ce7765b63..647cbe6f40ba 100644
--- a/lib/libc/stdtime/Makefile.inc
+++ b/lib/libc/stdtime/Makefile.inc
@@ -18,6 +18,7 @@ CFLAGS.${src}+= -I${LIBC_SRCTOP}/stdtime
CFLAGS.localtime.c+= -DALL_STATE -DTHREAD_SAFE
.if ${MK_DETECT_TZ_CHANGES} != "no"
CFLAGS.localtime.c+= -DDETECT_TZ_CHANGES
+CFLAGS.Version.map+= -DDETECT_TZ_CHANGES
.endif
MAN+= ctime.3 strftime.3 strptime.3 time2posix.3 tzset.3
diff --git a/lib/libc/stdtime/Symbol.map b/lib/libc/stdtime/Symbol.map
index 669d4d47907b..6a34cd3ea590 100644
--- a/lib/libc/stdtime/Symbol.map
+++ b/lib/libc/stdtime/Symbol.map
@@ -35,3 +35,9 @@ FBSD_1.8 {
daylight;
timezone;
};
+
+FBSDprivate_1.0 {
+#ifdef DETECT_TZ_CHANGES
+ __tz_change_interval;
+#endif
+};
diff --git a/lib/libc/string/memchr.3 b/lib/libc/string/memchr.3
index f5d1fe5d5c7f..65617a117371 100644
--- a/lib/libc/string/memchr.3
+++ b/lib/libc/string/memchr.3
@@ -52,7 +52,10 @@ locates the first occurrence of
(converted to an
.Vt "unsigned char" )
in string
-.Fa b .
+.Fa b ,
+limited to at most
+.Fa len
+characters.
.Pp
The
.Fn memrchr
@@ -61,15 +64,18 @@ function behaves like
except that it locates the last occurrence of
.Fa c
in string
-.Fa b .
+.Fa b ,
+limited to the first
+.Fa len
+characters.
.Sh RETURN VALUES
The
.Fn memchr
and
.Fn memrchr
-functions
-return a pointer to the byte located,
-or NULL if no such byte exists within
+functions return a pointer to the byte located, or
+.Dv NULL
+if no such byte exists within
.Fa len
bytes.
.Sh SEE ALSO
diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile
index a967ad5ddf91..8c2151105209 100644
--- a/lib/libc/tests/gen/Makefile
+++ b/lib/libc/tests/gen/Makefile
@@ -20,6 +20,7 @@ ATF_TESTS_C+= glob2_test
ATF_TESTS_C+= glob_blocks_test
.endif
ATF_TESTS_C+= makecontext_test
+ATF_TESTS_C+= opendir_test
ATF_TESTS_C+= popen_test
ATF_TESTS_C+= posix_spawn_test
ATF_TESTS_C+= realpath2_test
diff --git a/lib/libc/tests/gen/opendir_test.c b/lib/libc/tests/gen/opendir_test.c
new file mode 100644
index 000000000000..b7481255654f
--- /dev/null
+++ b/lib/libc/tests/gen/opendir_test.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+/*
+ * Create a directory with a single subdirectory.
+ */
+static void
+opendir_prepare(const struct atf_tc *tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("dir/subdir", 0755));
+}
+
+/*
+ * Assuming dirp represents the directory created by opendir_prepare(),
+ * verify that readdir() returns what we expected to see there.
+ */
+static void
+opendir_check(const struct atf_tc *tc, DIR *dirp)
+{
+ struct dirent *ent;
+
+ ATF_REQUIRE((ent = readdir(dirp)) != NULL);
+ ATF_CHECK_EQ(1, ent->d_namlen);
+ ATF_CHECK_STREQ(".", ent->d_name);
+ ATF_CHECK_EQ(DT_DIR, ent->d_type);
+ ATF_REQUIRE((ent = readdir(dirp)) != NULL);
+ ATF_CHECK_EQ(2, ent->d_namlen);
+ ATF_CHECK_STREQ("..", ent->d_name);
+ ATF_CHECK_EQ(DT_DIR, ent->d_type);
+ ATF_REQUIRE((ent = readdir(dirp)) != NULL);
+ ATF_CHECK_EQ(sizeof("subdir") - 1, ent->d_namlen);
+ ATF_CHECK_STREQ("subdir", ent->d_name);
+ ATF_CHECK_EQ(DT_DIR, ent->d_type);
+ ATF_CHECK(readdir(dirp) == NULL);
+ ATF_CHECK(readdir(dirp) == NULL);
+}
+
+ATF_TC(opendir_ok);
+ATF_TC_HEAD(opendir_ok, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Open a directory.");
+}
+ATF_TC_BODY(opendir_ok, tc)
+{
+ DIR *dirp;
+
+ opendir_prepare(tc);
+ ATF_REQUIRE((dirp = opendir("dir")) != NULL);
+ opendir_check(tc, dirp);
+ ATF_CHECK_EQ(0, closedir(dirp));
+}
+
+ATF_TC(opendir_fifo);
+ATF_TC_HEAD(opendir_fifo, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Do not hang if given a named pipe.");
+}
+ATF_TC_BODY(opendir_fifo, tc)
+{
+ DIR *dirp;
+ int fd;
+
+ ATF_REQUIRE((fd = mkfifo("fifo", 0644)) >= 0);
+ ATF_REQUIRE_EQ(0, close(fd));
+ ATF_REQUIRE((dirp = opendir("fifo")) == NULL);
+ ATF_CHECK_EQ(ENOTDIR, errno);
+}
+
+ATF_TC(fdopendir_ok);
+ATF_TC_HEAD(fdopendir_ok, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Open a directory from a directory descriptor.");
+}
+ATF_TC_BODY(fdopendir_ok, tc)
+{
+ DIR *dirp;
+ int dd;
+
+ opendir_prepare(tc);
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE((dirp = fdopendir(dd)) != NULL);
+ opendir_check(tc, dirp);
+ ATF_CHECK_EQ(dd, fdclosedir(dirp));
+ ATF_CHECK_EQ(0, close(dd));
+}
+
+ATF_TC(fdopendir_ebadf);
+ATF_TC_HEAD(fdopendir_ebadf, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Open a directory from an invalid descriptor.");
+}
+ATF_TC_BODY(fdopendir_ebadf, tc)
+{
+ DIR *dirp;
+ int dd;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_CHECK_EQ(0, close(dd));
+ ATF_REQUIRE((dirp = fdopendir(dd)) == NULL);
+ ATF_CHECK_EQ(EBADF, errno);
+}
+
+ATF_TC(fdopendir_enotdir);
+ATF_TC_HEAD(fdopendir_enotdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Open a directory from a non-directory descriptor.");
+}
+ATF_TC_BODY(fdopendir_enotdir, tc)
+{
+ DIR *dirp;
+ int fd;
+
+ ATF_REQUIRE((fd = open("file", O_CREAT | O_RDWR, 0644)) >= 0);
+ ATF_REQUIRE((dirp = fdopendir(fd)) == NULL);
+ ATF_CHECK_EQ(ENOTDIR, errno);
+ ATF_CHECK_EQ(0, close(fd));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, opendir_ok);
+ ATF_TP_ADD_TC(tp, fdopendir_ok);
+ ATF_TP_ADD_TC(tp, fdopendir_ebadf);
+ ATF_TP_ADD_TC(tp, fdopendir_enotdir);
+ ATF_TP_ADD_TC(tp, opendir_fifo);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/scandir_test.c b/lib/libc/tests/gen/scandir_test.c
index f7b52b5e3616..afd25bf7c0b2 100644
--- a/lib/libc/tests/gen/scandir_test.c
+++ b/lib/libc/tests/gen/scandir_test.c
@@ -157,7 +157,7 @@ ATF_TC_BODY(scandir_error, tc)
{
char path[16];
struct dirent **namelist = NULL;
- int fd, i, ret;
+ int fd, i;
ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
for (i = 0; i < 1024; i++) {
@@ -170,9 +170,8 @@ ATF_TC_BODY(scandir_error, tc)
scandir_error_count = 0;
scandir_error_fd = fd;
scandir_error_select_return = 0;
- ret = fdscandir(fd, &namelist, scandir_error_select, NULL);
- ATF_CHECK_EQ(-1, ret);
- ATF_CHECK_ERRNO(EBADF, ret < 0);
+ ATF_CHECK_ERRNO(EBADF,
+ fdscandir(fd, &namelist, scandir_error_select, NULL) < 0);
ATF_CHECK_EQ(NULL, namelist);
/* second pass, select everything */
@@ -180,9 +179,8 @@ ATF_TC_BODY(scandir_error, tc)
scandir_error_count = 0;
scandir_error_fd = fd;
scandir_error_select_return = 1;
- ret = fdscandir(fd, &namelist, scandir_error_select, NULL);
- ATF_CHECK_EQ(-1, ret);
- ATF_CHECK_ERRNO(EBADF, ret < 0);
+ ATF_CHECK_ERRNO(EBADF,
+ fdscandir(fd, &namelist, scandir_error_select, NULL) < 0);
ATF_CHECK_EQ(NULL, namelist);
}
diff --git a/lib/libc/tests/gen/wordexp_test.c b/lib/libc/tests/gen/wordexp_test.c
index 909097fbf51e..a8b9d5509633 100644
--- a/lib/libc/tests/gen/wordexp_test.c
+++ b/lib/libc/tests/gen/wordexp_test.c
@@ -292,6 +292,31 @@ ATF_TC_BODY(with_SIGCHILD_handler_test, tc)
ATF_REQUIRE(r == 0);
}
+ATF_TC_WITHOUT_HEAD(with_SIGCHILD_ignore_test);
+ATF_TC_BODY(with_SIGCHILD_ignore_test, tc)
+{
+ struct sigaction sa;
+ wordexp_t we;
+ int r;
+
+ /* With SIGCHLD set to ignore so that the kernel auto-reaps zombies. */
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ r = sigaction(SIGCHLD, &sa, NULL);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("hello world", &we, 0);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 2);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
+ ATF_REQUIRE(we.we_wordv[2] == NULL);
+ wordfree(&we);
+ sa.sa_handler = SIG_DFL;
+ r = sigaction(SIGCHLD, &sa, NULL);
+ ATF_REQUIRE(r == 0);
+}
+
ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test);
ATF_TC_BODY(with_unused_non_default_IFS_test, tc)
{
@@ -350,6 +375,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test);
ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test);
ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test);
+ ATF_TP_ADD_TC(tp, with_SIGCHILD_ignore_test);
ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test);
ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test);
diff --git a/lib/libc/tests/stdtime/Makefile b/lib/libc/tests/stdtime/Makefile
index c7a7f5b9436f..adb883cc5b9a 100644
--- a/lib/libc/tests/stdtime/Makefile
+++ b/lib/libc/tests/stdtime/Makefile
@@ -1,6 +1,9 @@
-.include <bsd.own.mk>
+.include <src.opts.mk>
ATF_TESTS_C+= strptime_test
+.if ${MK_DETECT_TZ_CHANGES} != "no"
+ATF_TESTS_C+= detect_tz_changes_test
+.endif
TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/}
diff --git a/lib/libc/tests/stdtime/detect_tz_changes_test.c b/lib/libc/tests/stdtime/detect_tz_changes_test.c
new file mode 100644
index 000000000000..9722546747fd
--- /dev/null
+++ b/lib/libc/tests/stdtime/detect_tz_changes_test.c
@@ -0,0 +1,281 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static const time_t then = 1751328000; /* 2025-07-01 00:00:00 UTC */
+static const char *tz_change_interval_sym = "__tz_change_interval";
+static int *tz_change_interval_p;
+static const int tz_change_interval = 3;
+static int tz_change_timeout = 90;
+
+static bool debugging;
+
+static void
+debug(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (debugging) {
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ }
+}
+
+static void
+change_tz(const char *tzn)
+{
+ static const char *zfn = "/usr/share/zoneinfo";
+ static const char *tfn = "root/etc/.localtime";
+ static const char *dfn = "root/etc/localtime";
+ ssize_t clen;
+ int zfd, sfd, dfd;
+
+ ATF_REQUIRE((zfd = open(zfn, O_DIRECTORY | O_SEARCH)) >= 0);
+ ATF_REQUIRE((sfd = openat(zfd, tzn, O_RDONLY)) >= 0);
+ ATF_REQUIRE((dfd = open(tfn, O_CREAT | O_TRUNC | O_WRONLY)) >= 0);
+ do {
+ clen = copy_file_range(sfd, NULL, dfd, NULL, SSIZE_MAX, 0);
+ ATF_REQUIRE_MSG(clen != -1, "failed to copy %s/%s: %m",
+ zfn, tzn);
+ } while (clen > 0);
+ ATF_CHECK_EQ(0, close(dfd));
+ ATF_CHECK_EQ(0, close(sfd));
+ ATF_CHECK_EQ(0, close(zfd));
+ ATF_REQUIRE_EQ(0, rename(tfn, dfn));
+ debug("time zone %s installed", tzn);
+}
+
+/*
+ * Test time zone change detection.
+ *
+ * The parent creates a chroot containing only /etc/localtime, initially
+ * set to UTC. It then forks a child which enters the chroot, repeatedly
+ * checks the current time zone, and prints it to stdout if it changes
+ * (including once on startup). Meanwhile, the parent waits for output
+ * from the child. Every time it receives a line of text from the child,
+ * it checks that it is as expected, then changes /etc/localtime within
+ * the chroot to the next case in the list. Once it reaches the end of
+ * the list, it closes a pipe to notify the child, which terminates.
+ *
+ * Note that ATF and / or Kyua may have set the timezone before the test
+ * case starts (even unintentionally). Therefore, we start the test only
+ * after we've received and discarded the first report from the child,
+ * which should come almost immediately on startup.
+ */
+ATF_TC(detect_tz_changes);
+ATF_TC_HEAD(detect_tz_changes, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test timezone change detection");
+ atf_tc_set_md_var(tc, "require.user", "root");
+ atf_tc_set_md_var(tc, "timeout", "600");
+}
+ATF_TC_BODY(detect_tz_changes, tc)
+{
+ static const struct tzcase {
+ const char *tzfn;
+ const char *expect;
+ } tzcases[] = {
+ /*
+ * A handful of time zones and the expected result of
+ * strftime("%z (%Z)", tm) when that time zone is active
+ * and tm represents a date in the summer of 2025.
+ */
+ { "America/Vancouver", "-0700 (PDT)" },
+ { "America/New_York", "-0400 (EDT)" },
+ { "Europe/London", "+0100 (BST)" },
+ { "Europe/Paris", "+0200 (CEST)" },
+ { "Asia/Kolkata", "+0530 (IST)" },
+ { "Asia/Tokyo", "+0900 (JST)" },
+ { "Australia/Canberra", "+1000 (AEST)" },
+ { "UTC", "+0000 (UTC)" },
+ { 0 },
+ };
+ char obuf[1024] = "";
+ char ebuf[1024] = "";
+ struct pollfd fds[3];
+ int opd[2], epd[2], spd[2];
+ time_t changed, now;
+ const struct tzcase *tzcase = NULL;
+ struct tm *tm;
+ size_t olen = 0, elen = 0;
+ ssize_t rlen;
+ long curoff = LONG_MIN;
+ pid_t pid;
+ int nfds, status;
+
+ /* speed up the test if possible */
+ tz_change_interval_p = dlsym(RTLD_SELF, tz_change_interval_sym);
+ if (tz_change_interval_p != NULL &&
+ *tz_change_interval_p > tz_change_interval) {
+ debug("reducing detection interval from %d to %d",
+ *tz_change_interval_p, tz_change_interval);
+ *tz_change_interval_p = tz_change_interval;
+ tz_change_timeout = tz_change_interval * 3;
+ }
+ /* prepare chroot */
+ ATF_REQUIRE_EQ(0, mkdir("root", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755));
+ change_tz("UTC");
+ time(&changed);
+ /* output, error, sync pipes */
+ if (pipe(opd) != 0 || pipe(epd) != 0 || pipe(spd) != 0)
+ atf_tc_fail("failed to pipe");
+ /* fork child */
+ if ((pid = fork()) < 0)
+ atf_tc_fail("failed to fork");
+ if (pid == 0) {
+ /* child */
+ dup2(opd[1], STDOUT_FILENO);
+ close(opd[0]);
+ close(opd[1]);
+ dup2(epd[1], STDERR_FILENO);
+ close(epd[0]);
+ close(epd[1]);
+ close(spd[0]);
+ unsetenv("TZ");
+ ATF_REQUIRE_EQ(0, chroot("root"));
+ ATF_REQUIRE_EQ(0, chdir("/"));
+ fds[0].fd = spd[1];
+ fds[0].events = POLLIN;
+ for (;;) {
+ ATF_REQUIRE(poll(fds, 1, 100) >= 0);
+ if (fds[0].revents & POLLHUP) {
+ /* parent closed sync pipe */
+ _exit(0);
+ }
+ ATF_REQUIRE((tm = localtime(&then)) != NULL);
+ if (tm->tm_gmtoff == curoff)
+ continue;
+ olen = strftime(obuf, sizeof(obuf), "%z (%Z)", tm);
+ ATF_REQUIRE(olen > 0);
+ fprintf(stdout, "%s\n", obuf);
+ fflush(stdout);
+ curoff = tm->tm_gmtoff;
+ }
+ _exit(2);
+ }
+ /* parent */
+ close(opd[1]);
+ close(epd[1]);
+ close(spd[1]);
+ /* receive output until child terminates */
+ fds[0].fd = opd[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = epd[0];
+ fds[1].events = POLLIN;
+ fds[2].fd = spd[0];
+ fds[2].events = POLLIN;
+ nfds = 3;
+ for (;;) {
+ ATF_REQUIRE(poll(fds, 3, 1000) >= 0);
+ time(&now);
+ if (fds[0].revents & POLLIN && olen < sizeof(obuf)) {
+ rlen = read(opd[0], obuf + olen, sizeof(obuf) - olen);
+ ATF_REQUIRE(rlen >= 0);
+ olen += rlen;
+ }
+ if (olen > 0) {
+ ATF_REQUIRE_EQ('\n', obuf[olen - 1]);
+ obuf[--olen] = '\0';
+ /* tzcase will be NULL at first */
+ if (tzcase != NULL) {
+ debug("%s", obuf);
+ ATF_REQUIRE_STREQ(tzcase->expect, obuf);
+ debug("change to %s detected after %d s",
+ tzcase->tzfn, (int)(now - changed));
+ if (tz_change_interval_p != NULL) {
+ ATF_CHECK((int)(now - changed) >=
+ *tz_change_interval_p - 1);
+ ATF_CHECK((int)(now - changed) <=
+ *tz_change_interval_p + 1);
+ }
+ }
+ olen = 0;
+ /* first / next test case */
+ if (tzcase == NULL)
+ tzcase = tzcases;
+ else
+ tzcase++;
+ if (tzcase->tzfn == NULL) {
+ /* test is over */
+ break;
+ }
+ change_tz(tzcase->tzfn);
+ changed = now;
+ }
+ if (fds[1].revents & POLLIN && elen < sizeof(ebuf)) {
+ rlen = read(epd[0], ebuf + elen, sizeof(ebuf) - elen);
+ ATF_REQUIRE(rlen >= 0);
+ elen += rlen;
+ }
+ if (elen > 0) {
+ ATF_REQUIRE_EQ(elen, fwrite(ebuf, 1, elen, stderr));
+ elen = 0;
+ }
+ if (nfds > 2 && fds[2].revents & POLLHUP) {
+ /* child closed sync pipe */
+ break;
+ }
+ /*
+ * The timeout for this test case is set to 10 minutes,
+ * because it can take that long to run with the default
+ * 61-second interval. However, each individual tzcase
+ * entry should not take much longer than the detection
+ * interval to test, so we can detect a problem long
+ * before Kyua terminates us.
+ */
+ if ((now - changed) > tz_change_timeout) {
+ close(spd[0]);
+ if (tz_change_interval_p == NULL &&
+ tzcase == tzcases) {
+ /*
+ * The most likely explanation in this
+ * case is that libc was built without
+ * time zone change detection.
+ */
+ atf_tc_skip("time zone change detection "
+ "does not appear to be enabled");
+ }
+ atf_tc_fail("timed out waiting for change to %s "
+ "to be detected", tzcase->tzfn);
+ }
+ }
+ close(opd[0]);
+ close(epd[0]);
+ close(spd[0]); /* this will wake up and terminate the child */
+ if (olen > 0)
+ ATF_REQUIRE_EQ(olen, fwrite(obuf, 1, olen, stdout));
+ if (elen > 0)
+ ATF_REQUIRE_EQ(elen, fwrite(ebuf, 1, elen, stderr));
+ ATF_REQUIRE_EQ(pid, waitpid(pid, &status, 0));
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE_EQ(0, WEXITSTATUS(status));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ debugging = !getenv("__RUNNING_INSIDE_ATF_RUN") &&
+ isatty(STDERR_FILENO);
+ ATF_TP_ADD_TC(tp, detect_tz_changes);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/sys/Makefile b/lib/libc/tests/sys/Makefile
index 89d341ff400a..88f8191a16eb 100644
--- a/lib/libc/tests/sys/Makefile
+++ b/lib/libc/tests/sys/Makefile
@@ -7,11 +7,11 @@ ATF_TESTS_C+= brk_test
.endif
ATF_TESTS_C+= cpuset_test
ATF_TESTS_C+= errno_test
+ATF_TESTS_C+= swapcontext_test
ATF_TESTS_C+= queue_test
ATF_TESTS_C+= sendfile_test
-# TODO: clone, lwp_create, lwp_ctl, posix_fadvise, recvmmsg,
-# swapcontext
+# TODO: clone, lwp_create, lwp_ctl, posix_fadvise, recvmmsg
NETBSD_ATF_TESTS_C+= access_test
NETBSD_ATF_TESTS_C+= bind_test
NETBSD_ATF_TESTS_C+= chroot_test
diff --git a/lib/libc/tests/sys/swapcontext_test.c b/lib/libc/tests/sys/swapcontext_test.c
new file mode 100644
index 000000000000..f341a746e515
--- /dev/null
+++ b/lib/libc/tests/sys/swapcontext_test.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2025 Raptor Computing Systems, LLC
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <errno.h>
+
+#include <atf-c.h>
+
+#define STACK_SIZE (64ull << 10)
+
+static volatile int callback_reached = 0;
+
+static ucontext_t uctx_save, uctx_switch;
+
+static void swapcontext_callback()
+{
+ // Increment callback reached variable
+ // If this is called multiple times, we will fail the test
+ // If this is not called at all, we will fail the test
+ callback_reached++;
+}
+
+ATF_TC(swapcontext_basic);
+ATF_TC_HEAD(swapcontext_basic, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify basic functionality of swapcontext");
+}
+
+ATF_TC_BODY(swapcontext_basic, tc)
+{
+ char *stack;
+ int res;
+
+ stack = malloc(STACK_SIZE);
+ ATF_REQUIRE_MSG(stack != NULL, "malloc failed: %s", strerror(errno));
+ res = getcontext(&uctx_switch);
+ ATF_REQUIRE_MSG(res == 0, "getcontext failed: %s", strerror(errno));
+
+ uctx_switch.uc_stack.ss_sp = stack;
+ uctx_switch.uc_stack.ss_size = STACK_SIZE;
+ uctx_switch.uc_link = &uctx_save;
+ makecontext(&uctx_switch, swapcontext_callback, 0);
+
+ res = swapcontext(&uctx_save, &uctx_switch);
+
+ ATF_REQUIRE_MSG(res == 0, "swapcontext failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(callback_reached == 1,
+ "callback failed, reached %d times", callback_reached);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, swapcontext_basic);
+
+ return (atf_no_error());
+}
+
diff --git a/lib/libcasper/services/cap_dns/tests/dns_test.c b/lib/libcasper/services/cap_dns/tests/dns_test.c
index 76534bbbebad..56d867e474f5 100644
--- a/lib/libcasper/services/cap_dns/tests/dns_test.c
+++ b/lib/libcasper/services/cap_dns/tests/dns_test.c
@@ -198,18 +198,17 @@ hostent_compare(const struct hostent *hp0, const struct hostent *hp1)
static void
runtest(cap_channel_t *capdns, unsigned int expected)
{
- unsigned int result, failure;
+ unsigned int result;
struct addrinfo *ais, *aic, hints, *hintsp;
struct hostent *hps, *hpc;
struct in_addr ip4;
struct in6_addr ip6;
int caperr, syserr;
- failure = result = 0;
+ result = 0;
hps = gethostbyname("example.com");
if (hps == NULL) {
- failure |= GETHOSTBYNAME;
fprintf(stderr, "Unable to resolve %s IPv4.\n", "example.com");
} else {
hpc = cap_gethostbyname(capdns, "example.com");
@@ -219,7 +218,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hps = gethostbyname2("example.com", AF_INET);
if (hps == NULL) {
- failure |= GETHOSTBYNAME2_AF_INET;
fprintf(stderr, "Unable to resolve %s IPv4.\n", "example.com");
} else {
hpc = cap_gethostbyname2(capdns, "example.com", AF_INET);
@@ -229,7 +227,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hps = gethostbyname2("example.com", AF_INET6);
if (hps == NULL) {
- failure |= GETHOSTBYNAME2_AF_INET6;
fprintf(stderr, "Unable to resolve %s IPv6.\n", "example.com");
} else {
hpc = cap_gethostbyname2(capdns, "example.com", AF_INET6);
@@ -250,7 +247,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
syserr = getaddrinfo("freebsd.org", "25", hintsp, &ais);
if (syserr != 0) {
- failure |= GETADDRINFO_AF_UNSPEC;
fprintf(stderr,
"Unable to issue [system] getaddrinfo() for AF_UNSPEC: %s\n",
gai_strerror(syserr));
@@ -268,7 +264,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hints.ai_family = AF_INET;
syserr = getaddrinfo("freebsd.org", "25", hintsp, &ais);
if (syserr != 0) {
- failure |= GETADDRINFO_AF_INET;
fprintf(stderr,
"Unable to issue [system] getaddrinfo() for AF_UNSPEC: %s\n",
gai_strerror(syserr));
@@ -286,7 +281,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hints.ai_family = AF_INET6;
syserr = getaddrinfo("freebsd.org", "25", hintsp, &ais);
if (syserr != 0) {
- failure |= GETADDRINFO_AF_INET6;
fprintf(stderr,
"Unable to issue [system] getaddrinfo() for AF_UNSPEC: %s\n",
gai_strerror(syserr));
@@ -308,7 +302,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
inet_pton(AF_INET, GOOGLE_DNS_IPV4, &ip4);
hps = gethostbyaddr(&ip4, sizeof(ip4), AF_INET);
if (hps == NULL) {
- failure |= GETHOSTBYADDR_AF_INET;
fprintf(stderr, "Unable to resolve %s.\n", GOOGLE_DNS_IPV4);
} else {
hpc = cap_gethostbyaddr(capdns, &ip4, sizeof(ip4), AF_INET);
@@ -319,7 +312,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
inet_pton(AF_INET6, GOOGLE_DNS_IPV6, &ip6);
hps = gethostbyaddr(&ip6, sizeof(ip6), AF_INET6);
if (hps == NULL) {
- failure |= GETHOSTBYADDR_AF_INET6;
fprintf(stderr, "Unable to resolve %s.\n", GOOGLE_DNS_IPV6);
} else {
hpc = cap_gethostbyaddr(capdns, &ip6, sizeof(ip6), AF_INET6);
@@ -329,21 +321,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
}
}
- /*
- * If we had any failures, make sure that all lookups failed. If some
- * succeeded and some failed, there's a problem with the test or the DNS
- * and we should not fail silently.
- */
- if (failure != 0) {
- ATF_REQUIRE_MSG(failure == (GETHOSTBYNAME |
- GETHOSTBYNAME2_AF_INET | GETHOSTBYNAME2_AF_INET6 |
- GETADDRINFO_AF_UNSPEC | GETADDRINFO_AF_INET |
- GETADDRINFO_AF_INET6 |
- GETHOSTBYADDR_AF_INET | GETHOSTBYADDR_AF_INET6),
- "expected all tests to fail, got 0x%x", failure);
- atf_tc_skip(
- "no name lookups succeeded, tests require Internet access");
- }
ATF_REQUIRE_MSG(result == expected,
"expected 0x%x, got 0x%x", expected, result);
}
@@ -367,6 +344,7 @@ cap_dns_init(void)
ATF_TC(dns_no_limits);
ATF_TC_HEAD(dns_no_limits, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_no_limits, tc)
{
@@ -386,6 +364,7 @@ ATF_TC_BODY(dns_no_limits, tc)
ATF_TC(dns_all_limits);
ATF_TC_HEAD(dns_all_limits, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_all_limits, tc)
{
@@ -417,6 +396,7 @@ ATF_TC_BODY(dns_all_limits, tc)
ATF_TC(dns_name_limit);
ATF_TC_HEAD(dns_name_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_name_limit, tc)
{
@@ -448,6 +428,7 @@ ATF_TC_BODY(dns_name_limit, tc)
ATF_TC(dns_addr_limit);
ATF_TC_HEAD(dns_addr_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_addr_limit, tc)
{
@@ -478,6 +459,7 @@ ATF_TC_BODY(dns_addr_limit, tc)
ATF_TC(dns_inet_limit);
ATF_TC_HEAD(dns_inet_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_inet_limit, tc)
{
@@ -509,6 +491,7 @@ ATF_TC_BODY(dns_inet_limit, tc)
ATF_TC(dns_inet6_limit);
ATF_TC_HEAD(dns_inet6_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_inet6_limit, tc)
{
@@ -540,6 +523,7 @@ ATF_TC_BODY(dns_inet6_limit, tc)
ATF_TC(dns_name_inet_limit);
ATF_TC_HEAD(dns_name_inet_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_name_inet_limit, tc)
{
@@ -581,6 +565,7 @@ ATF_TC_BODY(dns_name_inet_limit, tc)
ATF_TC(dns_name_inet6_limit);
ATF_TC_HEAD(dns_name_inet6_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_name_inet6_limit, tc)
{
@@ -622,6 +607,7 @@ ATF_TC_BODY(dns_name_inet6_limit, tc)
ATF_TC(dns_addr_inet_limit);
ATF_TC_HEAD(dns_addr_inet_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_addr_inet_limit, tc)
{
@@ -662,6 +648,7 @@ ATF_TC_BODY(dns_addr_inet_limit, tc)
ATF_TC(dns_addr_inet6_limit);
ATF_TC_HEAD(dns_addr_inet6_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_addr_inet6_limit, tc)
{
diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c
index 0d85ed468284..786d5647d993 100644
--- a/lib/libfetch/common.c
+++ b/lib/libfetch/common.c
@@ -277,13 +277,16 @@ conn_t *
fetch_reopen(int sd)
{
conn_t *conn;
+ int flags;
int opt = 1;
/* allocate and fill connection structure */
if ((conn = calloc(1, sizeof(*conn))) == NULL)
return (NULL);
- fcntl(sd, F_SETFD, FD_CLOEXEC);
- setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof opt);
+ flags = fcntl(sd, F_GETFD);
+ if (flags != -1 && (flags & FD_CLOEXEC) == 0)
+ (void)fcntl(sd, F_SETFD, flags | FD_CLOEXEC);
+ (void)setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
conn->sd = sd;
++conn->ref;
return (conn);
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
index 8d5ca01b0ce6..fc835485a51e 100644
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <net/if.h>
+#include <net/if_bridgevar.h> /* for ifbvlan_set_t */
#include <netinet/in.h>
#include <netinet/ip_carp.h>
@@ -64,6 +65,7 @@ struct lagg_reqport;
struct ifconfig_bridge_status {
struct ifbropreq *params; /**< current operational parameters */
struct ifbreq *members; /**< list of bridge members */
+ ifbvlan_set_t *member_vlans; /**< bridge member vlan sets */
size_t members_count; /**< how many member interfaces */
uint32_t cache_size; /**< size of address cache */
uint32_t cache_lifetime; /**< address cache entry lifetime */
diff --git a/lib/libifconfig/libifconfig_bridge.c b/lib/libifconfig/libifconfig_bridge.c
index 2a9bbc35858b..b4a920f488c5 100644
--- a/lib/libifconfig/libifconfig_bridge.c
+++ b/lib/libifconfig/libifconfig_bridge.c
@@ -66,40 +66,37 @@ ifconfig_bridge_get_bridge_status(ifconfig_handle_t *h,
{
struct ifbifconf members;
struct ifbrparam cache_param;
- struct _ifconfig_bridge_status *bridge;
- char *buf;
+ struct _ifconfig_bridge_status *bridge = NULL;
+ char *buf = NULL;
+ members.ifbic_buf = NULL;
*bridgep = NULL;
bridge = calloc(1, sizeof(struct _ifconfig_bridge_status));
if (bridge == NULL) {
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
- return (-1);
+ goto err;
}
bridge->inner.params = &bridge->params;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGCACHE,
&cache_param, sizeof(cache_param), false) != 0) {
- free(bridge);
- return (-1);
+ goto err;
}
bridge->inner.cache_size = cache_param.ifbrp_csize;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGTO,
&cache_param, sizeof(cache_param), false) != 0) {
- free(bridge);
- return (-1);
+ goto err;
}
bridge->inner.cache_lifetime = cache_param.ifbrp_ctime;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGPARAM,
&bridge->params, sizeof(bridge->params), false) != 0) {
- free(bridge);
- return (-1);
+ goto err;
}
- members.ifbic_buf = NULL;
for (size_t len = 8192;
(buf = realloc(members.ifbic_buf, len)) != NULL;
len *= 2) {
@@ -107,27 +104,52 @@ ifconfig_bridge_get_bridge_status(ifconfig_handle_t *h,
members.ifbic_len = len;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGIFS,
&members, sizeof(members), false) != 0) {
- free(buf);
- free(bridge);
- return (-1);
+ goto err;
}
if ((members.ifbic_len + sizeof(*members.ifbic_req)) < len)
break;
}
if (buf == NULL) {
- free(members.ifbic_buf);
- free(bridge);
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
- return (-1);
+ goto err;
}
bridge->inner.members = members.ifbic_req;
bridge->inner.members_count =
members.ifbic_len / sizeof(*members.ifbic_req);
+ bridge->inner.member_vlans = calloc(bridge->inner.members_count,
+ sizeof(ifbvlan_set_t));
+ if (bridge->inner.member_vlans == NULL) {
+ h->error.errtype = OTHER;
+ h->error.errcode = ENOMEM;
+ goto err;
+ }
+ for (size_t i = 0; i < bridge->inner.members_count; ++i) {
+ struct ifbif_vlan_req vreq;
+ memset(&vreq, 0, sizeof(vreq));
+ strlcpy(vreq.bv_ifname, bridge->inner.members[i].ifbr_ifsname,
+ sizeof(vreq.bv_ifname));
+
+ if (ifconfig_bridge_ioctlwrap(h, name, BRDGGIFVLANSET, &vreq,
+ sizeof(vreq), false) != 0) {
+ goto err;
+ }
+
+ __BIT_COPY(BRVLAN_SETSIZE, &vreq.bv_set,
+ &bridge->inner.member_vlans[i]);
+ }
+
*bridgep = &bridge->inner;
return (0);
+
+err:
+ free(members.ifbic_buf);
+ if (bridge)
+ free(bridge->inner.member_vlans);
+ free(bridge);
+ return (-1);
}
void
diff --git a/lib/libnvmf/libnvmf.h b/lib/libnvmf/libnvmf.h
index 9840e190a24f..7cdd7e433455 100644
--- a/lib/libnvmf/libnvmf.h
+++ b/lib/libnvmf/libnvmf.h
@@ -342,7 +342,8 @@ int nvmf_host_request_queues(struct nvmf_qpair *qp, u_int requested,
*/
int nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata);
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout);
/*
* Disconnect an active host association previously handed off to the
@@ -370,7 +371,8 @@ int nvmf_reconnect_params(int fd, nvlist_t **nvlp);
*/
int nvmf_reconnect_host(int fd, const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata);
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout);
/*
* Fetch connection status from an existing kernel host.
diff --git a/lib/libnvmf/nvmf_host.c b/lib/libnvmf/nvmf_host.c
index 89cdd5c6bb70..3266f8898296 100644
--- a/lib/libnvmf/nvmf_host.c
+++ b/lib/libnvmf/nvmf_host.c
@@ -792,7 +792,8 @@ static int
prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
const struct nvme_discovery_log_entry *dle, const char *hostnqn,
struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
const struct nvmf_association *na = admin_qp->nq_association;
nvlist_t *nvl, *nvl_qp, *nvl_rparams;
@@ -820,6 +821,9 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
nvlist_add_string(nvl_rparams, "hostnqn", hostnqn);
nvlist_add_number(nvl_rparams, "num_io_queues", num_queues);
nvlist_add_number(nvl_rparams, "kato", admin_qp->nq_kato);
+ nvlist_add_number(nvl_rparams, "reconnect_delay", reconnect_delay);
+ nvlist_add_number(nvl_rparams, "controller_loss_timeout",
+ controller_loss_timeout);
nvlist_add_number(nvl_rparams, "io_qsize", io_queues[0]->nq_qsize);
nvlist_add_bool(nvl_rparams, "sq_flow_control",
na->na_params.sq_flow_control);
@@ -842,6 +846,9 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
nvl = nvlist_create(0);
nvlist_add_number(nvl, "trtype", na->na_trtype);
nvlist_add_number(nvl, "kato", admin_qp->nq_kato);
+ nvlist_add_number(nvl, "reconnect_delay", reconnect_delay);
+ nvlist_add_number(nvl, "controller_loss_timeout",
+ controller_loss_timeout);
nvlist_move_nvlist(nvl, "rparams", nvl_rparams);
/* First, the admin queue. */
@@ -872,7 +879,8 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
int
nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
struct nvmf_ioc_nv nv;
u_int i;
@@ -885,7 +893,8 @@ nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
}
error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp,
- num_queues, io_queues, cdata);
+ num_queues, io_queues, cdata, reconnect_delay,
+ controller_loss_timeout);
if (error != 0)
goto out;
@@ -981,14 +990,16 @@ nvmf_reconnect_params(int fd, nvlist_t **nvlp)
int
nvmf_reconnect_host(int fd, const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
struct nvmf_ioc_nv nv;
u_int i;
int error;
error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp,
- num_queues, io_queues, cdata);
+ num_queues, io_queues, cdata, reconnect_delay,
+ controller_loss_timeout);
if (error != 0)
goto out;
diff --git a/lib/libopenbsd/Makefile b/lib/libopenbsd/Makefile
index 675ed476c51d..dca1c08b0aed 100644
--- a/lib/libopenbsd/Makefile
+++ b/lib/libopenbsd/Makefile
@@ -2,7 +2,8 @@ PACKAGE=lib${LIB}
LIB= openbsd
SRCS= imsg-buffer.c \
imsg.c \
- ohash.c
+ ohash.c \
+ recallocarray.c
.if !defined(BOOTSTRAPPING)
# Skip getdtablecount.c when bootstrapping since it doesn't compile for Linux
# and is not used by any of the bootstrap tools
diff --git a/lib/libopenbsd/recallocarray.c b/lib/libopenbsd/recallocarray.c
new file mode 100644
index 000000000000..11e1fda744c7
--- /dev/null
+++ b/lib/libopenbsd/recallocarray.c
@@ -0,0 +1,82 @@
+/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
+/*
+ * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *recallocarray(void *, size_t, size_t, size_t);
+
+void *
+recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
+{
+ size_t oldsize, newsize;
+ void *newptr;
+
+ if (ptr == NULL)
+ return calloc(newnmemb, size);
+
+ if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ newnmemb > 0 && SIZE_MAX / newnmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ newsize = newnmemb * size;
+
+ if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
+ errno = EINVAL;
+ return NULL;
+ }
+ oldsize = oldnmemb * size;
+
+ /*
+ * Don't bother too much if we're shrinking just a bit,
+ * we do not shrink for series of small steps, oh well.
+ */
+ if (newsize <= oldsize) {
+ size_t d = oldsize - newsize;
+
+ if (d < oldsize / 2 && d < (size_t)getpagesize()) {
+ memset((char *)ptr + newsize, 0, d);
+ return ptr;
+ }
+ }
+
+ newptr = malloc(newsize);
+ if (newptr == NULL)
+ return NULL;
+
+ if (newsize > oldsize) {
+ memcpy(newptr, ptr, oldsize);
+ memset((char *)newptr + oldsize, 0, newsize - oldsize);
+ } else
+ memcpy(newptr, ptr, newsize);
+
+ explicit_bzero(ptr, oldsize);
+ free(ptr);
+
+ return newptr;
+}
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
index 29f464ef6414..eb8137f6c76f 100644
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -625,6 +625,10 @@ procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmap
type = PS_FST_TYPE_EVENTFD;
data = file.f_data;
break;
+ case DTYPE_INOTIFY:
+ type = PS_FST_TYPE_INOTIFY;
+ data = file.f_data;
+ break;
default:
continue;
}
@@ -717,6 +721,7 @@ kinfo_type2fst(int kftype)
{ KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET },
{ KF_TYPE_VNODE, PS_FST_TYPE_VNODE },
{ KF_TYPE_EVENTFD, PS_FST_TYPE_EVENTFD },
+ { KF_TYPE_INOTIFY, PS_FST_TYPE_INOTIFY },
{ KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN }
};
#define NKFTYPES (sizeof(kftypes2fst) / sizeof(*kftypes2fst))
diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h
index 0e9a4214414c..548747f90171 100644
--- a/lib/libprocstat/libprocstat.h
+++ b/lib/libprocstat/libprocstat.h
@@ -71,6 +71,7 @@
#define PS_FST_TYPE_PROCDESC 13
#define PS_FST_TYPE_DEV 14
#define PS_FST_TYPE_EVENTFD 15
+#define PS_FST_TYPE_INOTIFY 16
/*
* Special descriptor numbers.
diff --git a/lib/libsecureboot/h/libsecureboot.h b/lib/libsecureboot/h/libsecureboot.h
index 017558536825..d32df9594332 100644
--- a/lib/libsecureboot/h/libsecureboot.h
+++ b/lib/libsecureboot/h/libsecureboot.h
@@ -29,6 +29,7 @@
#include <sys/param.h>
#ifdef _STANDALONE
+#define _DEBUG_LEVEL_VAR DebugVe
#include <stand.h>
#else
#include <sys/types.h>
diff --git a/lib/libsys/Makefile.sys b/lib/libsys/Makefile.sys
index 491c765e9416..3eb4bf85153d 100644
--- a/lib/libsys/Makefile.sys
+++ b/lib/libsys/Makefile.sys
@@ -224,6 +224,7 @@ MAN+= abort2.2 \
getsockopt.2 \
gettimeofday.2 \
getuid.2 \
+ inotify.2 \
intro.2 \
ioctl.2 \
issetugid.2 \
@@ -448,6 +449,11 @@ MLINKS+=getrlimit.2 setrlimit.2
MLINKS+=getsockopt.2 setsockopt.2
MLINKS+=gettimeofday.2 settimeofday.2
MLINKS+=getuid.2 geteuid.2
+MLINKS+=inotify.2 inotify_init.2 \
+ inotify.2 inotify_init1.2 \
+ inotify.2 inotify_add_watch.2 \
+ inotify.2 inotify_add_watch_at.2 \
+ inotify.2 inotify_rm_watch.2
MLINKS+=intro.2 errno.2
MLINKS+=jail.2 jail_attach.2 \
jail.2 jail_get.2 \
diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map
index 7fac1ed6160d..45e0160100af 100644
--- a/lib/libsys/Symbol.sys.map
+++ b/lib/libsys/Symbol.sys.map
@@ -381,6 +381,8 @@ FBSD_1.8 {
exterrctl;
fchroot;
getrlimitusage;
+ inotify_add_watch_at;
+ inotify_rm_watch;
kcmp;
setcred;
};
diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h
index e2a8f2253814..1799906eb885 100644
--- a/lib/libsys/_libsys.h
+++ b/lib/libsys/_libsys.h
@@ -466,6 +466,8 @@ typedef int (__sys_getrlimitusage_t)(u_int, int, rlim_t *);
typedef int (__sys_fchroot_t)(int);
typedef int (__sys_setcred_t)(u_int, const struct setcred *, size_t);
typedef int (__sys_exterrctl_t)(u_int, u_int, void *);
+typedef int (__sys_inotify_add_watch_at_t)(int, int, const char *, uint32_t);
+typedef int (__sys_inotify_rm_watch_t)(int, int);
void __sys_exit(int rval);
int __sys_fork(void);
@@ -868,6 +870,8 @@ int __sys_getrlimitusage(u_int which, int flags, rlim_t * res);
int __sys_fchroot(int fd);
int __sys_setcred(u_int flags, const struct setcred * wcred, size_t size);
int __sys_exterrctl(u_int op, u_int flags, void * ptr);
+int __sys_inotify_add_watch_at(int fd, int dfd, const char * path, uint32_t mask);
+int __sys_inotify_rm_watch(int fd, int wd);
__END_DECLS
#endif /* __LIBSYS_H_ */
diff --git a/lib/libsys/accept.2 b/lib/libsys/accept.2
index 53926b3153d2..2da2af066a5b 100644
--- a/lib/libsys/accept.2
+++ b/lib/libsys/accept.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 9, 2014
+.Dd May 17, 2025
.Dt ACCEPT 2
.Os
.Sh NAME
@@ -85,6 +85,13 @@ and the close-on-exec flag on the new file descriptor can be set via the
flag in the
.Fa flags
argument.
+Similarly, the
+.Dv O_CLOFORK
+property can be set via the
+.Dv SOCK_CLOFORK
+flag in the
+.Fa flags
+argument.
.Pp
If no pending connections are
present on the queue, and the original socket
@@ -234,3 +241,8 @@ The
.Fn accept4
system call appeared in
.Fx 10.0 .
+.Pp
+The
+.Dv SOCK_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/closefrom.2 b/lib/libsys/closefrom.2
index aaa4c55607ac..1885a6fdeaa8 100644
--- a/lib/libsys/closefrom.2
+++ b/lib/libsys/closefrom.2
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 3, 2022
+.Dd May 17, 2025
.Dt CLOSEFROM 2
.Os
.Sh NAME
@@ -59,6 +59,8 @@ Supported
.Bl -tag -width ".Dv CLOSE_RANGE_CLOEXEC"
.It Dv CLOSE_RANGE_CLOEXEC
Set the close-on-exec flag on descriptors in the range instead of closing them.
+.It Dv CLOSE_RANGE_CLOFORK
+Set the close-on-fork flag on descriptors in the range instead of closing them.
.El
.Sh RETURN VALUES
Upon successful completion,
@@ -90,3 +92,8 @@ The
.Fn closefrom
function first appeared in
.Fx 8.0 .
+.Pp
+The
+.Dv CLOSE_RANGE_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/execve.2 b/lib/libsys/execve.2
index 5a35980e9555..dc85b9321e48 100644
--- a/lib/libsys/execve.2
+++ b/lib/libsys/execve.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 26, 2022
+.Dd July 02, 2025
.Dt EXECVE 2
.Os
.Sh NAME
@@ -127,7 +127,10 @@ flag is set (see
and
.Xr fcntl 2 ) .
Descriptors that remain open are unaffected by
-.Fn execve .
+.Fn execve ,
+except those with the close-on-fork flag
+.Dv FD_CLOFORK
+which is cleared from all file descriptors.
If any of the standard descriptors (0, 1, and/or 2) are closed at the
time
.Fn execve
diff --git a/lib/libsys/fcntl.2 b/lib/libsys/fcntl.2
index 604de43e5e8c..d67c38cfbc6c 100644
--- a/lib/libsys/fcntl.2
+++ b/lib/libsys/fcntl.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 5, 2025
+.Dd June 24, 2025
.Dt FCNTL 2
.Os
.Sh NAME
@@ -81,6 +81,13 @@ to remain open across
.Xr execve 2
system calls.
.It
+The fork-on-exec flag
+.Dv FD_CLOFORK
+associated with the new file descriptor is cleared, so the file descriptor is
+to remain open across
+.Xr fork 2
+system calls.
+.It
The
.Dv FD_RESOLVE_BENEATH
flag, described below, will be set if it was set on the original
@@ -95,6 +102,15 @@ flag associated with the new file descriptor is set, so the file descriptor
is closed when
.Xr execve 2
system call executes.
+.It Dv F_DUPFD_CLOFORK
+Like
+.Dv F_DUPFD ,
+but the
+.Dv FD_CLOFORK
+flag associated with the new file descriptor is set, so the file descriptor
+is closed when
+.Xr fork 2
+system call executes.
.It Dv F_DUP2FD
It is functionally equivalent to
.Bd -literal -offset indent
@@ -117,6 +133,11 @@ Use
.Fn dup2
instead of
.Dv F_DUP2FD .
+.It Dv F_DUP3FD
+Used to implement the
+.Fn dup3
+call.
+Do not use it.
.It Dv F_GETFD
Get the flags associated with the file descriptor
.Fa fd .
@@ -128,6 +149,10 @@ The file will be closed upon execution of
.Fa ( arg
is ignored).
Otherwise, the file descriptor will remain open.
+.It Dv FD_CLOFORK
+The file will be closed upon execution of the
+.Fn fork
+family of system calls.
.It Dv FD_RESOLVE_BENEATH
All path name lookups relative to that file descriptor
will behave as if the lookup had
@@ -153,7 +178,8 @@ descriptor to also have the flag set.
Set flags associated with
.Fa fd .
The available flags are
-.Dv FD_CLOEXEC
+.Dv FD_CLOEXEC ,
+.Dv FD_CLOFORK
and
.Dv FD_RESOLVE_BENEATH .
The
@@ -551,7 +577,7 @@ A new file descriptor.
A file descriptor equal to
.Fa arg .
.It Dv F_GETFD
-Value of flag (only the low-order bit is defined).
+Value of flags.
.It Dv F_GETFL
Value of flags.
.It Dv F_GETOWN
@@ -785,8 +811,10 @@ for the reasons as stated in
.Sh STANDARDS
The
.Dv F_DUP2FD
-constant is non portable.
-It is provided for compatibility with AIX and Solaris.
+and
+.Dv F_DUP3FD
+constants are not portable.
+They are provided for compatibility with AIX and Solaris.
.Pp
Per
.St -susv4 ,
@@ -811,3 +839,10 @@ The
.Dv F_DUP2FD
constant first appeared in
.Fx 7.1 .
+.Pp
+The
+.Dv F_DUPFD_CLOFORK
+and
+.Dv F_DUP3FD
+flags appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/fhopen.2 b/lib/libsys/fhopen.2
index aba53f1dd907..b281ac3d8949 100644
--- a/lib/libsys/fhopen.2
+++ b/lib/libsys/fhopen.2
@@ -31,7 +31,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd April 6, 2025
+.Dd July 20, 2025
.Dt FHOPEN 2
.Os
.Sh NAME
@@ -140,7 +140,7 @@ is no longer valid.
.Xr fstatfs 2 ,
.Xr getfh 2 ,
.Xr open 2 ,
-.Xr named_attribute 9
+.Xr named_attribute 7
.Sh HISTORY
The
.Fn fhopen ,
diff --git a/lib/libsys/fork.2 b/lib/libsys/fork.2
index 7d548a42890d..e59b208a9ff5 100644
--- a/lib/libsys/fork.2
+++ b/lib/libsys/fork.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 5, 2021
+.Dd May 17, 2024
.Dt FORK 2
.Os
.Sh NAME
@@ -68,6 +68,16 @@ by the parent.
This descriptor copying is also used by the shell to
establish standard input and output for newly created processes
as well as to set up pipes.
+Any file descriptors that were marked with the close-on-fork flag,
+.Dv FD_CLOFORK
+.Po see
+.Fn fcntl 2
+and
+.Dv O_CLOFORK
+in
+.Fn open 2
+.Pc ,
+will not be present in the child process, but remain open in the parent.
.It
The child process' resource utilizations
are set to 0; see
diff --git a/lib/libsys/getdirentries.2 b/lib/libsys/getdirentries.2
index 0e5840ce25cd..202ae133f548 100644
--- a/lib/libsys/getdirentries.2
+++ b/lib/libsys/getdirentries.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 5, 2023
+.Dd July 8, 2025
.Dt GETDIRENTRIES 2
.Os
.Sh NAME
@@ -178,9 +178,7 @@ or non-NULL
.Fa basep
point outside the allocated address space.
.It Bq Er EINVAL
-The file referenced by
-.Fa fd
-is not a directory, or
+The value of
.Fa nbytes
is too small for returning a directory entry or block of entries,
or the current position pointer is invalid.
@@ -192,6 +190,10 @@ error occurred while reading from or writing to the file system.
Corrupted data was detected while reading from the file system.
.It Bq Er ENOENT
Directory unlinked but still open.
+.It Bq Er ENOTDIR
+The file referenced by
+.Fa fd
+is not a directory.
.El
.Sh SEE ALSO
.Xr lseek 2 ,
diff --git a/lib/libsys/inotify.2 b/lib/libsys/inotify.2
new file mode 100644
index 000000000000..f94509d6f59e
--- /dev/null
+++ b/lib/libsys/inotify.2
@@ -0,0 +1,379 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Klara, Inc.
+.\"
+.Dd May 19, 2025
+.Dt INOTIFY 2
+.Os
+.Sh NAME
+.Nm inotify_init ,
+.Nm inotify_init1 ,
+.Nm inotify_add_watch ,
+.Nm inotify_add_watch_at ,
+.Nm inotify_rm_watch
+.Nd monitor file system events
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/inotify.h
+.Ft int
+.Fo inotify_init
+.Fc
+.Ft int
+.Fo inotify_init1
+.Fa "int flags"
+.Fc
+.Ft int
+.Fo inotify_add_watch
+.Fa "int fd"
+.Fa "const char *pathname"
+.Fa "uint32_t mask"
+.Fc
+.Ft int
+.Fo inotify_add_watch_at
+.Fa "int fd"
+.Fa "int dfd"
+.Fa "const char *pathname"
+.Fa "uint32_t mask"
+.Fc
+.Ft int
+.Fo inotify_rm_watch
+.Fa "int fd"
+.Fa "uint32_t wd"
+.Fc
+.Bd -literal
+struct inotify_event {
+ int wd; /* Watch descriptor */
+ uint32_t mask; /* Event and flags */
+ uint32_t cookie; /* Unique ID which links rename events */
+ uint32_t len; /* Name field size, including nul bytes */
+ char name[0]; /* Filename (nul-terminated) */
+};
+.Ed
+.Sh DESCRIPTION
+The inotify system calls provide an interface to monitor file system events.
+They aim to be compatible with the Linux inotify interface.
+The provided functionality is similar to the
+.Dv EVFILT_VNODE
+filter of the
+.Xr kevent 2
+system call, but further allows monitoring of a directory without needing to
+open each object in that directory.
+This avoids races and reduces the number of file descriptors needed to monitor
+a large file hierarchy.
+.Pp
+inotify allows one or more file system objects, generally files or directories,
+to be watched for events, such as file open or close.
+Watched objects are associated with a file descriptor returned
+by
+.Fn inotify_init
+or
+.Fn inotify_init1 .
+When an event occurs, a record describing the event becomes available for
+reading from the inotify file descriptor.
+Each inotify descriptor thus refers to a queue of events waiting to be read.
+inotify descriptors are inherited across
+.Xr fork 2
+calls and may be passed to other processes via
+.Xr unix 4
+sockets.
+.Pp
+The
+.Fn inotify_init1
+system call accepts two flags.
+The
+.Dv IN_NONBLOCK
+flag causes the inotify descriptor to be opened in non-blocking mode, such that
+.Xr read 2
+calls will not block if no records are available to consume, and will instead
+return
+.Er EWOULDBLOCK .
+The
+.Dv IN_CLOEXEC
+flag causes the inotify descriptor to be closed automatically when
+.Xr execve 2
+is called.
+.Pp
+To watch a file or directory, the
+.Fn inotify_add_watch
+or
+.Fn inotify_add_watch_at
+system calls must be used.
+They take a path and a mask of events to watch for, and return a
+.Dq watch descriptor ,
+a non-negative integer which uniquely identifies the watched object within the
+inotify descriptor.
+.Pp
+The
+.Fn inotify_rm_watch
+system call removes a watch from an inotify descriptor.
+.Pp
+When watching a directory, objects within the directory are monitored for events
+as well as the directory itself.
+A record describing an inotify event consists of a
+.Dq struct inotify_event
+followed by the name of the object in the directory being watched.
+If the watched object itself generates an event, no name is present.
+Extra nul bytes may follow the file name in order to provide alignment for a
+subsequent record.
+.Pp
+The following events are defined:
+.Bl -tag -width IN_CLOSE_NOWRITE
+.It Dv IN_ACCESS
+A file's contents were accessed, e.g., by
+.Xr read 2
+.Xr copy_file_range 2 ,
+.Xr sendfile 2 ,
+or
+.Xr getdirentries 2 .
+.It Dv IN_ATTRIB
+A file's metadata was changed, e.g., by
+.Xr chmod 2
+or
+.Xr unlink 2 .
+.It Dv IN_CLOSE_WRITE
+A file that was previously opened for writing was closed.
+.It Dv IN_CLOSE_NOWRITE
+A file that was previously opened read-only was closed.
+.It Dv IN_CREATE
+A file within a watched directory was created, e.g., by
+.Xr open 2 ,
+.Xr mkdir 2 ,
+.Xr symlink 2 ,
+.Xr mknod 2 ,
+or
+.Xr bind 2 .
+.It Dv IN_DELETE
+A file or directory within a watched directory was removed.
+.It Dv IN_DELETE_SELF
+The watched file or directory itself was deleted.
+This event is generated only when the link count of the file drops
+to zero.
+.It Dv IN_MODIFY
+A file's contents were modified, e.g., by
+.Xr write 2
+or
+.Xr copy_file_range 2 .
+.It Dv IN_MOVE_SELF
+The watched file or directory itself was renamed.
+.It Dv IN_MOVED_FROM
+A file or directory was moved from a watched directory.
+.It Dv IN_MOVED_TO
+A file or directory was moved into a watched directory.
+A
+.Xr rename 2
+call thus may generate two events, one for the old name and one for the new
+name.
+These are linked together by the
+.Ar cookie
+field in the inotify record, which can be compared to link the two records
+to the same event.
+.It Dv IN_OPEN
+A file was opened.
+.El
+.Pp
+Some additional flags may be set in inotify event records:
+.Bl -tag -width IN_Q_OVERFLOW
+.It Dv IN_IGNORED
+When a watch is removed from a file, for example because it was created with the
+.Dv IN_ONESHOT
+flag, the file was deleted, or the watch was explicitly removed with
+.Xr inotify_rm_watch 2 ,
+an event with this mask is generated to indicate that the watch will not
+generate any more events.
+Once this event is generated, the watch is automatically removed, and in
+particular should not be removed manually with
+.Xr inotify_rm_watch 2 .
+.It Dv IN_ISDIR
+When the subject of an event is a directory, this flag is set in the
+.Ar mask
+.It Dv IN_Q_OVERFLOW
+One or more events were dropped, for example because of a kernel memory allocation
+failure or because the event queue size hit a limit.
+.It Dv IN_UNMOUNT
+The filesystem containing the watched object was unmounted.
+.El
+.Pp
+A number of flags may also be specified in the
+.Ar mask
+given to
+.Fn inotify_add_watch
+and
+.Fn inotify_add_watch_at :
+.Bl -tag -width IN_DONT_FOLLOW
+.It Dv IN_DONT_FOLLOW
+If
+.Ar pathname
+is a symbolic link, do not follow it.
+.It Dv IN_EXCL_UNLINK
+This currently has no effect, see the
+.Sx BUGS
+section.
+.In Dv IN_MASK_ADD
+When adding a watch to an object, and that object is already watched by the
+same inotify descriptor, by default the mask of the existing watch is
+overwritten.
+When
+.Dv IN_MASK_ADD
+is specified, the mask of the existing watch is instead logically ORed with
+the new mask.
+.In Dv IN_MASK_CREATE
+When
+.Fn inotify_add watch
+is used to add a watch to an object,
+.Dv IN_MASK_CREATE
+is specified, and that object is already watched by the same inotify descriptor,
+return an error instead of updating the existing watch.
+.In Dv IN_ONESHOT
+Monitor the object for a single event, after which the watch is automatically
+removed.
+As part of removal, a
+.Dv IN_IGNORED
+event is generated.
+.In Dv IN_ONLYDIR
+When creating a watch, fail with
+.Er ENOTDIR
+if the path does not refer to a directory.
+.El
+.Sh SYSCTL VARIABLES
+The following variables are available as both
+.Xr sysctl 8
+variables and
+.Xr loader 8
+tunables:
+.Bl -tag -width 15
+.It Va vfs.inotify.max_events
+The maximum number of inotify records that can be queued for a single
+inotify descriptor.
+Records in excess of this limit are discarded, and a single event with
+mask equal to
+.Dv IN_Q_OVERFLOW
+will be present in the queue.
+.It Va vfs.inotify.max_user_instances
+The maximum number of inotify descriptors that can be created by a single
+user.
+.It Va vfs.inotify.max_user_watches
+The maximum number of inotify watches per user.
+.El
+.Sh EXAMPLES
+See the example program in
+.Pa /usr/share/examples/inotify/inotify.c .
+.Sh ERRORS
+The
+.Fn inotify_init
+and
+.Fn inotify_init1
+functions will fail if:
+.Bl -tag -width Er
+.It Bq Er ENFILE
+The system limit on the total number of open files has been reached.
+.It Bq Er EMFILE
+A per-process limit on the number of open files has been reached.
+.It Bq Er EMFILE
+The system limit on the number of inotify descriptors has been reached.
+.It Bq Er EINVAL
+An unrecognized flag was passed to
+.Fn inotify_init1 .
+.El
+.Pp
+The
+.Fn inotify_add_watch
+and
+.Fn inotify_add_watch_at
+system calls will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Ar fd
+parameter is not a valid file descriptor.
+.It Bq Er EINVAL
+The
+.Ar fd
+parameter is not an inotify descriptor.
+.It Bq Er EINVAL
+The
+.Ar mask
+parameter does not specify an event, or
+the
+.Dv IN_MASK_CREATE
+and
+.Dv IN_MASK_ADD
+flags are both set, or an unrecognized flag was passed.
+.It Bq Er ENOTDIR
+The
+.Ar pathname
+parameter refers to a file that is not a directory, and the
+.Dv IN_ONLYDIR
+flag was specified.
+.It Bq Er ENOSPC
+The per-user limit on the total number of inotify watches has been reached.
+.It Bq Er ECAPMODE
+The process is in capability mode and
+.Fn inotify_add_watch
+was called, or
+.Fn inotify_add_watch_at
+was called with
+.Dv AT_FDCWD
+as the directory file descriptor
+.Ar dfd .
+.It Bq Er ENOTCAPABLE
+The process is in capability mode and
+.Ar pathname
+contains a
+.Dq ..
+component leading to a directory outside the directory hierarchy specified
+by
+.Ar dfd .
+.El
+.Pp
+The
+.Fn inotify_rm_watch
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Ar fd
+parameter is not a valid file descriptor.
+.It Bq Er EINVAL
+The
+.Ar fd
+parameter is not an inotify descriptor.
+.It Bq Er EINVAL
+The
+.Ar wd
+parameter is not a valid watch descriptor.
+.El
+.Sh SEE ALSO
+.Xr kevent 2 ,
+.Xr capsicum 4
+.Sh STANDARDS
+The
+.Nm
+interface originates from Linux and is non-standard.
+This implementation aims to be compatible with that of Linux and is based
+on the documentation available at
+.Pa https://man7.org/linux/man-pages/man7/inotify.7.html .
+.Sh HISTORY
+The inotify system calls first appeared in
+.Fx 15.0 .
+.Sh BUGS
+If a file in a watched directory has multiple hard links,
+an access via any hard link for that file will generate an event, even
+if the accessed link belongs to an unwatched directory.
+This is not the case for the Linux implementation, where only accesses
+via the hard link in the watched directory will generate an event.
+.Pp
+If a watched directory contains multiple hard links of a file, an event
+on one of the hard links will generate an inotify record for each link
+in the directory.
+.Pp
+When a file is unlinked, no more events will be generated for that file,
+even if it continues to be accessed.
+By default, the Linux implementation will continue to generate events in
+this case.
+Thus, the
+.Fx
+implementation behaves as though
+.Dv IN_EXCL_UNLINK
+is always set.
diff --git a/lib/libsys/open.2 b/lib/libsys/open.2
index 84c4f02fce8a..a0e905a8f375 100644
--- a/lib/libsys/open.2
+++ b/lib/libsys/open.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 3, 2025
+.Dd May 17, 2025
.Dt OPEN 2
.Os
.Sh NAME
@@ -195,6 +195,9 @@ error if file is not a directory
.It Dv O_CLOEXEC
automatically close file on
.Xr execve 2
+.It Dv O_CLOFORK
+automatically close file on any child process created with
+.Fn fork 2
.It Dv O_VERIFY
verify the contents of the file with
.Xr mac_veriexec 4
@@ -360,6 +363,27 @@ may be used to set
.Dv FD_CLOEXEC
flag for the newly returned file descriptor.
.Pp
+.Dv O_CLOFORK
+may be used to set
+.Dv FD_CLOFORK
+flag for the newly returned file descriptor.
+The file will be closed on any child process created with
+.Fn fork 2 ,
+.Fn vfork 2
+or
+.Fn rfork 2
+with the
+.Dv RFFDG
+flag, remaining open in the parent.
+Both the
+.Dv O_CLOEXEC
+and
+.Dv O_CLOFORK
+flags can be modified with the
+.Dv F_SETFD
+.Fn fcntl 2
+command.
+.Pp
.Dv O_VERIFY
may be used to indicate to the kernel that the contents of the file should
be verified before allowing the open to proceed.
@@ -846,6 +870,9 @@ function was introduced in
appeared in 13.0.
.Dv O_NAMEDATTR
appeared in 15.0.
+.Dv O_CLOFORK
+appeared in
+.Fx 15.0 .
.Sh BUGS
The
.Fa mode
diff --git a/lib/libsys/pathconf.2 b/lib/libsys/pathconf.2
index 4c562b9c2c9a..79ac8310000d 100644
--- a/lib/libsys/pathconf.2
+++ b/lib/libsys/pathconf.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 3, 2025
+.Dd July 5, 2025
.Dt PATHCONF 2
.Os
.Sh NAME
@@ -179,6 +179,14 @@ otherwise 0.
Return 1 if named attributes are enabled for the file system, otherwise 0.
.It Li _PC_HAS_NAMEDATTR
Return 1 if one or more named attributes exist for the file, otherwise 0.
+.It Li _PC_HAS_HIDDENSYSTEM
+Return 1 if both
+.Dv UF_HIDDEN
+and
+.Dv UF_SYSTEM
+flags can be set by
+.Xr chflags 2 ,
+otherwise 0.
.El
.Sh RETURN VALUES
If the call to
@@ -255,6 +263,7 @@ An I/O error occurred while reading from or writing to the file system.
Corrupted data was detected while reading from the file system.
.El
.Sh SEE ALSO
+.Xr chflags 2 ,
.Xr lseek 2 ,
.Xr sysctl 3
.Sh HISTORY
diff --git a/lib/libsys/pipe.2 b/lib/libsys/pipe.2
index 9531c9717395..37d6eba420de 100644
--- a/lib/libsys/pipe.2
+++ b/lib/libsys/pipe.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 1, 2017
+.Dd May 17, 2025
.Dt PIPE 2
.Os
.Sh NAME
@@ -64,6 +64,8 @@ list, defined in
.Bl -tag -width ".Dv O_NONBLOCK"
.It Dv O_CLOEXEC
Set the close-on-exec flag for the new file descriptors.
+.It Dv O_CLOFORK
+Set the close-on-fork flag for the new file descriptors.
.It Dv O_NONBLOCK
Set the non-blocking flag for the ends of the pipe.
.El
@@ -173,3 +175,8 @@ function became a wrapper around
.Fn pipe2
in
.Fx 11.0 .
+.Pp
+The
+.Dv O_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/recv.2 b/lib/libsys/recv.2
index f3ee60b75663..b78cd70b8a1d 100644
--- a/lib/libsys/recv.2
+++ b/lib/libsys/recv.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 30, 2022
+.Dd May 17, 2025
.Dt RECV 2
.Os
.Sh NAME
@@ -164,6 +164,7 @@ one or more of the values:
.It Dv MSG_WAITALL Ta wait for full request or error
.It Dv MSG_DONTWAIT Ta do not block
.It Dv MSG_CMSG_CLOEXEC Ta set received fds close-on-exec
+.It Dv MSG_CMSG_CLOFORK Ta set received fds close-on-fork
.It Dv MSG_WAITFORONE Ta do not block after receiving the first message
(only for
.Fn recvmmsg
diff --git a/lib/libsys/socket.2 b/lib/libsys/socket.2
index a383cbcc4d80..b211611c6354 100644
--- a/lib/libsys/socket.2
+++ b/lib/libsys/socket.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 15, 2023
+.Dd May 17, 2025
.Dt SOCKET 2
.Os
.Sh NAME
@@ -121,6 +121,7 @@ argument:
.Pp
.Bd -literal -offset indent -compact
SOCK_CLOEXEC Set close-on-exec on the new descriptor,
+SOCK_CLOFORK Set close-on-fork on the new descriptor,
SOCK_NONBLOCK Set non-blocking mode on the new socket
.Ed
.Pp
@@ -331,7 +332,10 @@ argument of
.Fn socket .
The
.Dv SOCK_CLOEXEC
-flag is expected to conform to the next revision of the
+and
+.Dv SOCK_CLOFORK
+flags are expected to conform to
+.St -p1003.1-2024 .
.Tn POSIX
standard.
The
@@ -347,3 +351,8 @@ The
.Fn socket
system call appeared in
.Bx 4.2 .
+.Pp
+The
+.Dv SOCK_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/socketpair.2 b/lib/libsys/socketpair.2
index 5874a0791f4d..60dec74f9cc2 100644
--- a/lib/libsys/socketpair.2
+++ b/lib/libsys/socketpair.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 10, 2018
+.Dd May 17, 2025
.Dt SOCKETPAIR 2
.Os
.Sh NAME
@@ -56,7 +56,8 @@ and
The two sockets are indistinguishable.
.Pp
The
-.Dv SOCK_CLOEXEC
+.Dv SOCK_CLOEXEC ,
+.Dv SOCK_CLOFORK
and
.Dv SOCK_NONBLOCK
flags in the
diff --git a/lib/libsys/statfs.2 b/lib/libsys/statfs.2
index 49e8b5120558..ab65def11ebb 100644
--- a/lib/libsys/statfs.2
+++ b/lib/libsys/statfs.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 7, 2025
+.Dd July 20, 2025
.Dt STATFS 2
.Os
.Sh NAME
@@ -127,7 +127,7 @@ Mandatory Access Control (MAC) support for individual objects
.Xr mac 4 ) .
.It Dv MNT_NAMEDATTR
The file system supports named attributes as described in
-.Xr named_attribute 9 .
+.Xr named_attribute 7 .
.It Dv MNT_NFS4ACLS
ACLs in NFSv4 variant are supported.
.It Dv MNT_NOATIME
@@ -264,7 +264,7 @@ each file or directory name or disk label
.Sh SEE ALSO
.Xr fhstatfs 2 ,
.Xr getfsstat 2 ,
-.Xr named_attribute 9
+.Xr named_attribute 7
.Sh HISTORY
The
.Fn statfs
diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map
index 51be88203c17..69fce2ea7c63 100644
--- a/lib/libsys/syscalls.map
+++ b/lib/libsys/syscalls.map
@@ -809,4 +809,8 @@ FBSDprivate_1.0 {
__sys_setcred;
_exterrctl;
__sys_exterrctl;
+ _inotify_add_watch_at;
+ __sys_inotify_add_watch_at;
+ _inotify_rm_watch;
+ __sys_inotify_rm_watch;
};
diff --git a/lib/libsysdecode/Makefile b/lib/libsysdecode/Makefile
index b01877bb8bb8..ca020552a6e9 100644
--- a/lib/libsysdecode/Makefile
+++ b/lib/libsysdecode/Makefile
@@ -84,6 +84,7 @@ MLINKS+=sysdecode_mask.3 sysdecode_accessmode.3 \
sysdecode_mask.3 sysdecode_fileflags.3 \
sysdecode_mask.3 sysdecode_filemode.3 \
sysdecode_mask.3 sysdecode_flock_operation.3 \
+ sysdecode_mask.3 sysdecode_inotifyflags.3 \
sysdecode_mask.3 sysdecode_mlockall_flags.3 \
sysdecode_mask.3 sysdecode_mmap_flags.3 \
sysdecode_mask.3 sysdecode_mmap_prot.3 \
diff --git a/lib/libsysdecode/flags.c b/lib/libsysdecode/flags.c
index 32829d35dbe0..f8e26e6a9dae 100644
--- a/lib/libsysdecode/flags.c
+++ b/lib/libsysdecode/flags.c
@@ -23,7 +23,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define L2CAP_SOCKET_CHECKED
#include <sys/types.h>
@@ -31,6 +30,7 @@
#include <sys/capsicum.h>
#include <sys/event.h>
#include <sys/extattr.h>
+#include <sys/inotify.h>
#include <sys/linker.h>
#include <sys/mman.h>
#include <sys/mount.h>
@@ -196,7 +196,7 @@ sysdecode_vmprot(FILE *fp, int type, int *rem)
}
static struct name_table sockflags[] = {
- X(SOCK_CLOEXEC) X(SOCK_NONBLOCK) XEND
+ X(SOCK_CLOEXEC) X(SOCK_CLOFORK) X(SOCK_NONBLOCK) XEND
};
bool
@@ -206,16 +206,17 @@ sysdecode_socket_type(FILE *fp, int type, int *rem)
uintmax_t val;
bool printed;
- str = lookup_value(socktype, type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK));
+ str = lookup_value(socktype,
+ type & ~(SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK));
if (str != NULL) {
fputs(str, fp);
*rem = 0;
printed = true;
} else {
- *rem = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
+ *rem = type & ~(SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK);
printed = false;
}
- val = type & (SOCK_CLOEXEC | SOCK_NONBLOCK);
+ val = type & (SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK);
print_mask_part(fp, sockflags, &val, &printed);
return (printed);
}
@@ -351,6 +352,13 @@ sysdecode_getrusage_who(int who)
return (lookup_value(rusage, who));
}
+bool
+sysdecode_inotifyflags(FILE *fp, int flag, int *rem)
+{
+
+ return (print_mask_int(fp, inotifyflags, flag, rem));
+}
+
static struct name_table kevent_user_ffctrl[] = {
X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
XEND
@@ -556,7 +564,7 @@ sysdecode_nfssvc_flags(int flags)
}
static struct name_table pipe2flags[] = {
- X(O_CLOEXEC) X(O_NONBLOCK) XEND
+ X(O_CLOEXEC) X(O_CLOFORK) X(O_NONBLOCK) XEND
};
bool
@@ -866,7 +874,7 @@ sysdecode_fcntl_cmd(int cmd)
}
static struct name_table fcntl_fd_arg[] = {
- X(FD_CLOEXEC) X(0) XEND
+ X(FD_CLOEXEC) X(FD_CLOFORK) X(0) XEND
};
bool
diff --git a/lib/libsysdecode/mktables b/lib/libsysdecode/mktables
index 5d7be2aad3c8..6b4f79402660 100644
--- a/lib/libsysdecode/mktables
+++ b/lib/libsysdecode/mktables
@@ -98,6 +98,7 @@ gen_table "extattrns" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/
gen_table "fadvisebehav" "POSIX_FADV_[A-Z]+[[:space:]]+[0-9]+" "sys/fcntl.h"
gen_table "openflags" "O_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/fcntl.h" "O_RDONLY|O_RDWR|O_WRONLY"
gen_table "flockops" "LOCK_[A-Z]+[[:space:]]+0x[0-9]+" "sys/fcntl.h"
+gen_table "inotifyflags" "IN_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/inotify.h" "IN_CLOEXEC|IN_NONBLOCK"
gen_table "kldsymcmd" "KLDSYM_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h"
gen_table "kldunloadfflags" "LINKER_UNLOAD_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h"
gen_table "lio_listiomodes" "LIO_(NO)?WAIT[[:space:]]+[0-9]+" "aio.h"
diff --git a/lib/libsysdecode/sysdecode.h b/lib/libsysdecode/sysdecode.h
index 8dc0bbea6f0d..c95d7f71379b 100644
--- a/lib/libsysdecode/sysdecode.h
+++ b/lib/libsysdecode/sysdecode.h
@@ -61,6 +61,7 @@ const char *sysdecode_getfsstat_mode(int _mode);
const char *sysdecode_getrusage_who(int _who);
const char *sysdecode_idtype(int _idtype);
const char *sysdecode_ioctlname(unsigned long _val);
+bool sysdecode_inotifyflags(FILE *_fp, int _flags, int *_rem);
const char *sysdecode_ipproto(int _protocol);
void sysdecode_kevent_fflags(FILE *_fp, short _filter, int _fflags,
int _base);
diff --git a/lib/libsysdecode/sysdecode_fcntl_arg.3 b/lib/libsysdecode/sysdecode_fcntl_arg.3
index ee3a030a79e4..d5648ce0adc3 100644
--- a/lib/libsysdecode/sysdecode_fcntl_arg.3
+++ b/lib/libsysdecode/sysdecode_fcntl_arg.3
@@ -54,7 +54,8 @@ are determined by
.It Sy Command Ta Fa arg Sy Type Ta Sy Output Format
.It
.It Dv F_SETFD Ta Vt int Ta
-.Dq FD_CLOEXEC
+.Dq FD_CLOEXEC ,
+.Dq FD_CLOFORK
or the value of
.Fa arg
in the indicated
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
index 1c8dde03367b..3a5353a32dc3 100644
--- a/lib/libthr/pthread.map
+++ b/lib/libthr/pthread.map
@@ -136,7 +136,6 @@ FBSDprivate_1.0 {
__pthread_mutex_lock;
__pthread_mutex_timedlock;
__pthread_mutex_trylock;
- __pthread_distribute_static_tls;
_pthread_atfork;
_pthread_barrier_destroy;
_pthread_barrier_init;
diff --git a/lib/libthr/thread/thr_list.c b/lib/libthr/thread/thr_list.c
index 820766f6f5e0..cbf16179f619 100644
--- a/lib/libthr/thread/thr_list.c
+++ b/lib/libthr/thread/thr_list.c
@@ -363,41 +363,3 @@ _thr_find_thread(struct pthread *curthread, struct pthread *thread,
THREAD_LIST_UNLOCK(curthread);
return (ret);
}
-
-static void
-thr_distribute_static_tls(char *tlsbase, void *src, size_t len,
- size_t total_len)
-{
-
- memcpy(tlsbase, src, len);
- memset(tlsbase + len, 0, total_len - len);
-}
-
-void
-__pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
- struct pthread *curthread, *thrd;
- char *tlsbase;
-
- if (!_thr_is_inited()) {
-#ifdef TLS_VARIANT_I
- tlsbase = (char *)_tcb_get() + offset;
-#else
- tlsbase = (char *)_tcb_get() - offset;
-#endif
- thr_distribute_static_tls(tlsbase, src, len, total_len);
- return;
- }
- curthread = _get_curthread();
- THREAD_LIST_RDLOCK(curthread);
- TAILQ_FOREACH(thrd, &_thread_list, tle) {
-#ifdef TLS_VARIANT_I
- tlsbase = (char *)thrd->tcb + offset;
-#else
- tlsbase = (char *)thrd->tcb - offset;
-#endif
- thr_distribute_static_tls(tlsbase, src, len, total_len);
- }
- THREAD_LIST_UNLOCK(curthread);
-}
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index bca890829057..d7b889930365 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -986,8 +986,6 @@ void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info);
void _thr_tsd_unload(struct dl_phdr_info *phdr_info) __hidden;
void _thr_sigact_unload(struct dl_phdr_info *phdr_info) __hidden;
void _thr_stack_fix_protection(struct pthread *thrd);
-void __pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len);
int *__error_threaded(void) __hidden;
void __thr_interpose_libc(void) __hidden;
diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3
index a9a99f307a86..9dc752f0fd7b 100644
--- a/lib/libusb/libusb.3
+++ b/lib/libusb/libusb.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 12, 2025
+.Dd July 9, 2025
.Dt LIBUSB 3
.Os
.Sh NAME
@@ -106,6 +106,19 @@ Get the ASCII representation of the error given by the
argument.
This function does not return NULL.
.Pp
+.Ft int
+.Fn libusb_setlocale "const char *locale"
+Set locale for the error message when using
+.Fn libusb_strerror
+to
+.Ft locale .
+Note other
+.Nm
+implementations only support the first two bytes, that means
+.Ql en-US
+is equivalent to
+.Ql en-CA .
+.Pp
.Ft const char *
.Fn libusb_error_name "int code"
Get the ASCII representation of the error enum given by the
@@ -353,6 +366,23 @@ argument is non-zero the feature is enabled.
Else disabled.
Returns 0 on success and a LIBUSB_ERROR code on
failure.
+.Pp
+.Ft unsigned char *
+.Fn libusb_dev_mem_alloc "libusb_device_handle *devh"
+This function attempts to allocate a DMA memory block from the given
+.Fa devh
+so that we can enjoy the zero-copy transfer from kernel.
+This function is provided for compatibility and is currently unimplemented and always returns NULL.
+.Pp
+.Ft int
+.Fn libusb_dev_mem_free "libusb_device_handle *devh" "unsigned char *buffer" "size_t size"
+This function frees the DMA memory in
+.Fa devh
+from the given
+.Fa buffer
+with
+.Fa size .
+This function is unimplemented and always returns LIBUSB_ERROR_NOT_SUPPORTED.
.Sh USB DESCRIPTORS
.Ft int
.Fn libusb_get_device_descriptor "libusb_device *dev" "libusb_device_descriptor *desc"
@@ -762,6 +792,17 @@ argument can be either of LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED or LIBUSB_HOTPLUG_
.Ft void
.Fn libusb_hotplug_deregister_callback "libusb_context *ctx" "libusb_hotplug_callback_handle handle"
This function unregisters a hotplug filter.
+.Pp
+.Ft void
+.Fn libusb_free_pollfds "const struct libusb_pollfd **pollfds"
+This function releases the memory storage in
+.Fa pollfds ,
+and is safe to call when the argument is NULL.
+.Pp void *
+.Fn libusb_hotplug_get_user_data "struct libusb_context *ctx" "libusb_hotplug_callback_handle callback_handle"
+This function returns the user data from the opaque
+.Fa callback_handle ,
+or returns NULL if no matching handle is found.
.Sh LIBUSB VERSION 0.1 COMPATIBILITY
The library is also compliant with LibUSB version 0.1.12.
.Pp
diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h
index 0aad29aa4ecc..1803ff637738 100644
--- a/lib/libusb/libusb.h
+++ b/lib/libusb/libusb.h
@@ -122,6 +122,7 @@ enum libusb_transfer_type {
LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1,
LIBUSB_TRANSFER_TYPE_BULK = 2,
LIBUSB_TRANSFER_TYPE_INTERRUPT = 3,
+ LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4,
};
enum libusb_standard_request {
@@ -210,6 +211,8 @@ enum libusb_error {
LIBUSB_ERROR_OTHER = -99,
};
+#define LIBUSB_ERROR_COUNT 14
+
enum libusb_speed {
LIBUSB_SPEED_UNKNOWN = 0,
LIBUSB_SPEED_LOW = 1,
@@ -243,17 +246,6 @@ enum libusb_log_level {
LIBUSB_LOG_LEVEL_DEBUG
};
-/* XXX */
-/* libusb_set_debug should take parameters from libusb_log_level
- * above according to
- * https://libusb.sourceforge.io/api-1.0/group__libusb__lib.html
- */
-enum libusb_debug_level {
- LIBUSB_DEBUG_NO=0,
- LIBUSB_DEBUG_FUNCTION=1,
- LIBUSB_DEBUG_TRANSFER=2,
-};
-
#define LIBUSB_HOTPLUG_MATCH_ANY -1
typedef enum {
@@ -418,7 +410,10 @@ typedef struct libusb_bos_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
- uint8_t bNumDeviceCapabilities;
+#ifndef bNumDeviceCapabilities
+#define bNumDeviceCapabilities bNumDeviceCaps
+#endif
+ uint8_t bNumDeviceCaps;
struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap;
struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap;
struct libusb_bos_dev_capability_descriptor **dev_capability;
@@ -483,6 +478,7 @@ int libusb_init(libusb_context ** context);
int libusb_init_context(libusb_context **, const struct libusb_init_option [], int num_options);
void libusb_exit(struct libusb_context *ctx);
int libusb_has_capability(uint32_t capability);
+int libusb_setlocale(const char *locale);
/* Device handling and enumeration */
@@ -518,6 +514,9 @@ int libusb_detach_kernel_driver(libusb_device_handle * devh, int interface);
int libusb_attach_kernel_driver(libusb_device_handle * devh, int interface);
int libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable);
int libusb_set_interface_alt_setting(libusb_device_handle * devh, int interface_number, int alternate_setting);
+unsigned char *libusb_dev_mem_alloc(libusb_device_handle *devh);
+int libusb_dev_mem_free(libusb_device_handle *devh, unsigned char *buffer,
+ size_t size);
/* USB Descriptors */
@@ -578,7 +577,8 @@ int libusb_handle_events(libusb_context * ctx);
int libusb_handle_events_locked(libusb_context * ctx, struct timeval *tv);
int libusb_get_next_timeout(libusb_context * ctx, struct timeval *tv);
void libusb_set_pollfd_notifiers(libusb_context * ctx, libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, void *user_data);
-const struct libusb_pollfd **libusb_get_pollfds(libusb_context * ctx);
+const struct libusb_pollfd **libusb_get_pollfds(libusb_context *ctx);
+void libusb_free_pollfds(const struct libusb_pollfd **pollfds);
/* Synchronous device I/O */
@@ -598,6 +598,8 @@ typedef int (*libusb_hotplug_callback_fn)(libusb_context *ctx,
int libusb_hotplug_register_callback(libusb_context *ctx, libusb_hotplug_event events, libusb_hotplug_flag flags, int vendor_id, int product_id, int dev_class, libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *handle);
void libusb_hotplug_deregister_callback(libusb_context *ctx, libusb_hotplug_callback_handle handle);
+void *libusb_hotplug_get_user_data(struct libusb_context *ctx,
+ libusb_hotplug_callback_handle callback_handle);
/* Streams support */
diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c
index 3e81f234a735..5c116b39ea17 100644
--- a/lib/libusb/libusb10.c
+++ b/lib/libusb/libusb10.c
@@ -4,6 +4,7 @@
* Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
* Copyright (c) 2009-2023 Hans Petter Selasky
* Copyright (c) 2024 Aymeric Wibo
+ * Copyright (c) 2025 ShengYi Hung
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,10 +32,12 @@
#include LIBUSB_GLOBAL_INCLUDE_FILE
#else
#include <assert.h>
+#include <ctype.h>
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -48,6 +51,7 @@
#endif
#define libusb_device_handle libusb20_device
+#define LIBUSB_LOG_BUFFER_SIZE 1024
#include "libusb20.h"
#include "libusb20_desc.h"
@@ -82,6 +86,52 @@ static const struct libusb_version libusb_version = {
.describe = "https://www.freebsd.org"
};
+static const struct libusb_language_context libusb_language_ctx[] = {
+ {
+ .lang_name = "en",
+ .err_strs = {
+ [-LIBUSB_SUCCESS] = "Success",
+ [-LIBUSB_ERROR_IO] = "I/O error",
+ [-LIBUSB_ERROR_INVALID_PARAM] = "Invalid parameter",
+ [-LIBUSB_ERROR_ACCESS] = "Permissions error",
+ [-LIBUSB_ERROR_NO_DEVICE] = "No device",
+ [-LIBUSB_ERROR_NOT_FOUND] = "Not found",
+ [-LIBUSB_ERROR_BUSY] = "Device busy",
+ [-LIBUSB_ERROR_TIMEOUT] = "Timeout",
+ [-LIBUSB_ERROR_OVERFLOW] = "Overflow",
+ [-LIBUSB_ERROR_PIPE] = "Pipe error",
+ [-LIBUSB_ERROR_INTERRUPTED] = "Interrupted",
+ [-LIBUSB_ERROR_NO_MEM] = "Out of memory",
+ [-LIBUSB_ERROR_NOT_SUPPORTED] ="Not supported",
+ [LIBUSB_ERROR_COUNT - 1] = "Other error",
+ [LIBUSB_ERROR_COUNT] = "Unknown error",
+ }
+ },
+ {
+ .lang_name = "zh",
+ .err_strs = {
+ [-LIBUSB_SUCCESS] = "成功",
+ [-LIBUSB_ERROR_IO] = "I/O 錯誤",
+ [-LIBUSB_ERROR_INVALID_PARAM] = "不合法的參數",
+ [-LIBUSB_ERROR_ACCESS] = "權限錯誤",
+ [-LIBUSB_ERROR_NO_DEVICE] = "裝置不存在",
+ [-LIBUSB_ERROR_NOT_FOUND] = "不存在",
+ [-LIBUSB_ERROR_BUSY] = "裝置忙碌中",
+ [-LIBUSB_ERROR_TIMEOUT] = "逾時",
+ [-LIBUSB_ERROR_OVERFLOW] = "溢位",
+ [-LIBUSB_ERROR_PIPE] = "管道錯誤",
+ [-LIBUSB_ERROR_INTERRUPTED] = "被中斷",
+ [-LIBUSB_ERROR_NO_MEM] = "記憶體不足",
+ [-LIBUSB_ERROR_NOT_SUPPORTED] ="不支援",
+ [LIBUSB_ERROR_COUNT - 1] = "其他錯誤",
+ [LIBUSB_ERROR_COUNT] = "未知錯誤",
+ }
+ },
+};
+
+static const struct libusb_language_context *default_language_context =
+ &libusb_language_ctx[0];
+
const struct libusb_version *
libusb_get_version(void)
{
@@ -128,7 +178,7 @@ libusb_interrupt_event_handler(libusb_context *ctx)
err = eventfd_write(ctx->event, 1);
if (err < 0) {
/* ignore error, if any */
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "Waking up event loop failed!");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_ERROR, "Waking up event loop failed!");
}
}
@@ -253,7 +303,7 @@ libusb_init_context(libusb_context **context,
if (context)
*context = ctx;
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_INFO, "libusb_init complete");
signal(SIGPIPE, SIG_IGN);
@@ -625,7 +675,7 @@ libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
if (ctx == NULL)
return (NULL); /* be NULL safe */
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_open_device_with_vid_pid enter");
if ((i = libusb_get_device_list(ctx, &devs)) < 0)
return (NULL);
@@ -649,7 +699,7 @@ libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
}
libusb_free_device_list(devs, 1);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid leave");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_open_device_with_vid_pid leave");
return (pdev);
}
@@ -1480,6 +1530,7 @@ found:
libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy);
break;
case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy);
break;
@@ -1536,7 +1587,7 @@ libusb_submit_transfer(struct libusb_transfer *uxfer)
dev = libusb_get_device(uxfer->dev_handle);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter");
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_submit_transfer enter");
sxfer = (struct libusb_super_transfer *)(
(uint8_t *)uxfer - sizeof(*sxfer));
@@ -1571,7 +1622,7 @@ libusb_submit_transfer(struct libusb_transfer *uxfer)
CTX_UNLOCK(dev->ctx);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err);
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_submit_transfer leave %d", err);
return (err);
}
@@ -1600,7 +1651,7 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer)
dev = libusb_get_device(devh);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter");
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_cancel_transfer enter");
sxfer = (struct libusb_super_transfer *)(
(uint8_t *)uxfer - sizeof(*sxfer));
@@ -1661,7 +1712,7 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer)
CTX_UNLOCK(dev->ctx);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave");
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_cancel_transfer leave");
return (retval);
}
@@ -1726,38 +1777,26 @@ libusb_le16_to_cpu(uint16_t x)
const char *
libusb_strerror(int code)
{
- switch (code) {
- case LIBUSB_SUCCESS:
- return ("Success");
- case LIBUSB_ERROR_IO:
- return ("I/O error");
- case LIBUSB_ERROR_INVALID_PARAM:
- return ("Invalid parameter");
- case LIBUSB_ERROR_ACCESS:
- return ("Permissions error");
- case LIBUSB_ERROR_NO_DEVICE:
- return ("No device");
- case LIBUSB_ERROR_NOT_FOUND:
- return ("Not found");
- case LIBUSB_ERROR_BUSY:
- return ("Device busy");
- case LIBUSB_ERROR_TIMEOUT:
- return ("Timeout");
- case LIBUSB_ERROR_OVERFLOW:
- return ("Overflow");
- case LIBUSB_ERROR_PIPE:
- return ("Pipe error");
- case LIBUSB_ERROR_INTERRUPTED:
- return ("Interrupted");
- case LIBUSB_ERROR_NO_MEM:
- return ("Out of memory");
- case LIBUSB_ERROR_NOT_SUPPORTED:
- return ("Not supported");
- case LIBUSB_ERROR_OTHER:
- return ("Other error");
- default:
- return ("Unknown error");
- }
+ int entry = -code;
+
+ if (code == LIBUSB_ERROR_OTHER)
+ entry = LIBUSB_ERROR_COUNT - 1;
+ /*
+ * The libusb upstream considers all code out of range a
+ * LIBUSB_ERROR_OTHER. In FreeBSD, it is a special unknown error. We
+ * preserve the FreeBSD implementation as I think it make sense.
+ */
+ if (entry < 0 || entry >= LIBUSB_ERROR_COUNT)
+ entry = LIBUSB_ERROR_COUNT;
+
+ /*
+ * Fall back to English one as the translation may be unimplemented
+ * when adding new error code.
+ */
+ if (default_language_context->err_strs[entry] == NULL)
+ return (libusb_language_ctx[0].err_strs[entry]);
+
+ return (default_language_context->err_strs[entry]);
}
const char *
@@ -1811,3 +1850,71 @@ libusb_has_capability(uint32_t capability)
return (0);
}
}
+
+void
+libusb_log_va_args(struct libusb_context *ctx, enum libusb_log_level level,
+ const char *fmt, ...)
+{
+ static const char *log_prefix[5] = {
+ [LIBUSB_LOG_LEVEL_ERROR] = "LIBUSB_ERROR",
+ [LIBUSB_LOG_LEVEL_WARNING] = "LIBUSB_WARN",
+ [LIBUSB_LOG_LEVEL_INFO] = "LIBUSB_INFO",
+ [LIBUSB_LOG_LEVEL_DEBUG] = "LIBUSB_DEBUG",
+ };
+
+ char buffer[LIBUSB_LOG_BUFFER_SIZE];
+ char new_fmt[LIBUSB_LOG_BUFFER_SIZE];
+ va_list args;
+
+ ctx = GET_CONTEXT(ctx);
+
+ if (ctx->debug < level)
+ return;
+
+ va_start(args, fmt);
+
+ snprintf(new_fmt, sizeof(new_fmt), "%s: %s\n", log_prefix[level], fmt);
+ vsnprintf(buffer, sizeof(buffer), new_fmt, args);
+ fputs(buffer, stdout);
+
+ va_end(args);
+}
+
+/*
+ * Upstream code actually recognizes the first two characters to identify a
+ * language. We do so to provide API compatibility with setlocale.
+ */
+int
+libusb_setlocale(const char *locale)
+{
+ size_t idx;
+ const char *lang;
+
+ if (locale == NULL || strlen(locale) < 2 ||
+ (locale[2] != '\0' && strchr("-_.", locale[2]) == NULL))
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ for (idx = 0; idx < nitems(libusb_language_ctx); ++idx) {
+ lang = libusb_language_ctx[idx].lang_name;
+ if (tolower(locale[0]) == lang[0] &&
+ tolower(locale[1]) == lang[1]) {
+ default_language_context = &libusb_language_ctx[idx];
+ return (LIBUSB_SUCCESS);
+ }
+ }
+
+ return (LIBUSB_ERROR_INVALID_PARAM);
+}
+
+unsigned char *
+libusb_dev_mem_alloc(libusb_device_handle *devh)
+{
+ return (NULL);
+}
+
+int
+libusb_dev_mem_free(libusb_device_handle *devh, unsigned char *buffer,
+ size_t size)
+{
+ return (LIBUSB_ERROR_NOT_SUPPORTED);
+}
diff --git a/lib/libusb/libusb10.h b/lib/libusb/libusb10.h
index 70b5525df537..eced364ef857 100644
--- a/lib/libusb/libusb10.h
+++ b/lib/libusb/libusb10.h
@@ -29,6 +29,7 @@
#define __LIBUSB10_H__
#ifndef LIBUSB_GLOBAL_INCLUDE_FILE
+#include <sys/cdefs.h>
#include <sys/queue.h>
#include <netlink/netlink.h>
#include <netlink/netlink_generic.h>
@@ -46,24 +47,11 @@
#define HOTPLUG_LOCK(ctx) pthread_mutex_lock(&(ctx)->hotplug_lock)
#define HOTPLUG_UNLOCK(ctx) pthread_mutex_unlock(&(ctx)->hotplug_lock)
-#define DPRINTF(ctx, dbg, format, ...) do { \
- switch (dbg) { \
- case LIBUSB_DEBUG_FUNCTION: \
- if ((ctx)->debug & LIBUSB_DEBUG_FUNCTION) { \
- printf("LIBUSB_FUNCTION: " \
- format "\n", ## __VA_ARGS__); \
- } \
- break; \
- case LIBUSB_DEBUG_TRANSFER: \
- if ((ctx)->debug & LIBUSB_DEBUG_TRANSFER) { \
- printf("LIBUSB_TRANSFER: " \
- format "\n", ## __VA_ARGS__); \
- } \
- break; \
- default: \
- break; \
- } \
-} while (0)
+void libusb_log_va_args(struct libusb_context *ctx, enum libusb_log_level level,
+ const char *fmt, ...) __printflike(3, 4);
+
+#define DPRINTF(ctx, dbg, format, ...) \
+ libusb_log_va_args(ctx, dbg, format, ##__VA_ARGS__)
/* internal structures */
@@ -151,6 +139,12 @@ struct libusb_device {
struct libusb20_device *os_priv;
};
+struct libusb_language_context {
+ const char *lang_name;
+ /* All error Plus 1 UNKNOWN */
+ const char *err_strs[LIBUSB_ERROR_COUNT + 1];
+};
+
extern struct libusb_context *usbi_default_context;
void libusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd, struct libusb20_device *pdev, int fd, short events);
diff --git a/lib/libusb/libusb10_desc.c b/lib/libusb/libusb10_desc.c
index 3e36009cbb3a..5f4c46740688 100644
--- a/lib/libusb/libusb10_desc.c
+++ b/lib/libusb/libusb10_desc.c
@@ -470,10 +470,11 @@ libusb_parse_bos_descriptor(const void *buf, int len,
ptr->bDescriptorType = dtype;
ptr->wTotalLength = ((const uint8_t *)buf)[2] |
(((const uint8_t *)buf)[3] << 8);
- ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4];
+ ptr->bNumDeviceCaps = ((const uint8_t *)buf)[4];
ptr->usb_2_0_ext_cap = NULL;
ptr->ss_usb_cap = NULL;
- ptr->dev_capability = calloc(ptr->bNumDeviceCapabilities, sizeof(void *));
+ ptr->dev_capability = calloc(ptr->bNumDeviceCaps,
+ sizeof(void *));
if (ptr->dev_capability == NULL) {
free(ptr);
return (LIBUSB_ERROR_NO_MEM);
@@ -485,7 +486,7 @@ libusb_parse_bos_descriptor(const void *buf, int len,
if (dlen >= 3 &&
ptr != NULL &&
dtype == LIBUSB_DT_DEVICE_CAPABILITY) {
- if (index != ptr->bNumDeviceCapabilities) {
+ if (index != ptr->bNumDeviceCaps) {
ptr->dev_capability[index] = malloc(dlen);
if (ptr->dev_capability[index] == NULL) {
libusb_free_bos_descriptor(ptr);
@@ -542,7 +543,7 @@ libusb_parse_bos_descriptor(const void *buf, int len,
}
if (ptr != NULL) {
- ptr->bNumDeviceCapabilities = index;
+ ptr->bNumDeviceCaps = index;
return (0); /* success */
}
@@ -557,7 +558,7 @@ libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
if (bos == NULL)
return;
- for (i = 0; i != bos->bNumDeviceCapabilities; i++)
+ for (i = 0; i != bos->bNumDeviceCaps; i++)
free(bos->dev_capability[i]);
free(bos->dev_capability);
free(bos);
diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c
index 369539d4512e..9c46d4926bfa 100644
--- a/lib/libusb/libusb10_hotplug.c
+++ b/lib/libusb/libusb10_hotplug.c
@@ -414,3 +414,21 @@ void libusb_hotplug_deregister_callback(libusb_context *ctx,
free(handle);
}
+
+void *
+libusb_hotplug_get_user_data(struct libusb_context *ctx,
+ libusb_hotplug_callback_handle callback_handle)
+{
+ libusb_hotplug_callback_handle handle;
+
+ ctx = GET_CONTEXT(ctx);
+
+ HOTPLUG_LOCK(ctx);
+ TAILQ_FOREACH(handle, &ctx->hotplug_cbh, entry) {
+ if (handle == callback_handle)
+ break;
+ }
+ HOTPLUG_UNLOCK(ctx);
+
+ return (handle);
+}
diff --git a/lib/libusb/libusb10_io.c b/lib/libusb/libusb10_io.c
index f1e31c2a7416..c99586ff650d 100644
--- a/lib/libusb/libusb10_io.c
+++ b/lib/libusb/libusb10_io.c
@@ -108,7 +108,7 @@ libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
int i;
int err;
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb10_handle_events_sub enter");
nfds = 0;
i = 0;
@@ -230,7 +230,7 @@ do_done:
/* Wakeup other waiters */
pthread_cond_broadcast(&ctx->ctx_cond);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub complete");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb10_handle_events_sub complete");
return (err);
}
@@ -314,7 +314,7 @@ libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
int err;
ctx = GET_CONTEXT(ctx);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_wait_for_event enter");
if (tv == NULL) {
pthread_cond_wait(&ctx->ctx_cond,
@@ -358,7 +358,7 @@ libusb_handle_events_timeout_completed(libusb_context *ctx,
ctx = GET_CONTEXT(ctx);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_handle_events_timeout_completed enter");
libusb_lock_events(ctx);
@@ -374,7 +374,7 @@ libusb_handle_events_timeout_completed(libusb_context *ctx,
libusb_unlock_events(ctx);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed exit");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_handle_events_timeout_completed exit");
return (err);
}
@@ -523,7 +523,7 @@ libusb10_do_transfer_cb(struct libusb_transfer *transfer)
ctx = libusb10_get_context_by_device_handle(transfer->dev_handle);
- DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "sync I/O done");
pdone = transfer->user_data;
*pdone = 1;
@@ -613,12 +613,12 @@ libusb_bulk_transfer(libusb_device_handle *devh,
ctx = libusb10_get_context_by_device_handle(devh);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_bulk_transfer enter");
ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
timeout, LIBUSB_TRANSFER_TYPE_BULK);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_bulk_transfer leave");
return (ret);
}
@@ -632,12 +632,12 @@ libusb_interrupt_transfer(libusb_device_handle *devh,
ctx = libusb10_get_context_by_device_handle(devh);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_interrupt_transfer enter");
ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_interrupt_transfer leave");
return (ret);
}
@@ -781,6 +781,19 @@ libusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
}
void
+libusb_fill_bulk_stream_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *dev_handle, unsigned char endpoint,
+ uint32_t stream_id, unsigned char *buffer, int length,
+ libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
+{
+ libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer,
+ length, callback, user_data, timeout);
+ transfer->type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
+
+ libusb_transfer_set_stream_id(transfer, stream_id);
+}
+
+void
libusb_fill_iso_transfer(struct libusb_transfer *transfer,
libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
int length, int npacket, libusb_transfer_cb_fn callback,
@@ -842,3 +855,12 @@ libusb_transfer_get_stream_id(struct libusb_transfer *transfer)
/* get stream ID */
return (sxfer->stream_id);
}
+
+void
+libusb_free_pollfds(const struct libusb_pollfd **pollfds)
+{
+ if (pollfds == NULL)
+ return;
+
+ free(pollfds);
+}
diff --git a/lib/libusb/libusb20_desc.h b/lib/libusb/libusb20_desc.h
index 017148a34b1c..0f7c9294ebc8 100644
--- a/lib/libusb/libusb20_desc.h
+++ b/lib/libusb/libusb20_desc.h
@@ -298,11 +298,15 @@ LIBUSB20_MAKE_STRUCT(LIBUSB20_USB_20_DEVCAP_DESC);
LIBUSB20_MAKE_STRUCT(LIBUSB20_SS_USB_DEVCAP_DESC);
+#ifndef bNumDeviceCapabilities
+#define bNumDeviceCapabilities bNumDeviceCaps
+#endif
+
#define LIBUSB20_BOS_DESCRIPTOR(m,n) \
m(n, UINT8_T, bLength, ) \
m(n, UINT8_T, bDescriptorType, ) \
m(n, UINT16_T, wTotalLength, ) \
- m(n, UINT8_T, bNumDeviceCapabilities, ) \
+ m(n, UINT8_T, bNumDeviceCaps, ) \
LIBUSB20_MAKE_STRUCT(LIBUSB20_BOS_DESCRIPTOR);
diff --git a/lib/ncurses/tinfo/Makefile b/lib/ncurses/tinfo/Makefile
index 920bd6e5559c..476df54bb72a 100644
--- a/lib/ncurses/tinfo/Makefile
+++ b/lib/ncurses/tinfo/Makefile
@@ -259,10 +259,18 @@ term.h: MKterm.h.awk edit_cfg.sh Caps Caps-ncurses
sh ${NCURSES_DIR}/include/edit_cfg.sh ${NCURSES_CFG_H} $@.new
mv -f $@.new $@
+# Avoid hard-coding absolute source paths if requested.
+.if ${MK_REPRODUCIBLE_BUILD} != "no"
+NCURSES_SRCTOP=/usr/src
+.else
+NCURSES_SRCTOP=${SRCTOP}
+.endif
+
curses.h: curses.head MKkey_defs.sh Caps Caps-ncurses
cat curses.head > $@.new
AWK=${AWK} _POSIX2_VERSION=199209 sh ${NCURSES_DIR}/include/MKkey_defs.sh \
${NCURSES_DIR}/include/Caps ${NCURSES_DIR}/include/Caps-ncurses >> $@.new
+ sed -i '' 's|${SRCTOP}|${NCURSES_SRCTOP}|g' $@.new
cat ${NCURSES_DIR}/include/curses.wide >> $@.new
cat ${NCURSES_DIR}/include/curses.tail >> $@.new
mv -f $@.new $@
@@ -387,6 +395,7 @@ unctrl.h: unctrl.h.in
terminfo.5: MKterminfo.sh terminfo.head Caps
sh ${NCURSES_DIR}/man/MKterminfo.sh ${NCURSES_DIR}/man/terminfo.head \
${NCURSES_DIR}/include/Caps ${NCURSES_DIR}/man/terminfo.tail >$@
+ sed -i '' 's|${SRCTOP}|${NCURSES_SRCTOP}|g' $@
CLEANFILES+= terminfo.5
diff --git a/libexec/flua/linit_flua.c b/libexec/flua/linit_flua.c
index 8eaa4af1ffca..b466b7872158 100644
--- a/libexec/flua/linit_flua.c
+++ b/libexec/flua/linit_flua.c
@@ -57,18 +57,11 @@ static const luaL_Reg loadedlibs[] = {
#endif
/* FreeBSD Extensions */
{"lfs", luaopen_lfs},
- {"posix.fnmatch", luaopen_posix_fnmatch},
- {"posix.libgen", luaopen_posix_libgen},
- {"posix.stdlib", luaopen_posix_stdlib},
- {"posix.sys.stat", luaopen_posix_sys_stat},
- {"posix.sys.utsname", luaopen_posix_sys_utsname},
- {"posix.sys.wait", luaopen_posix_sys_wait},
- {"posix.unistd", luaopen_posix_unistd},
+ {"posix", luaopen_posix},
{"fbsd", luaopen_fbsd},
{NULL, NULL}
};
-
LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib;
/* "require" functions from 'loadedlibs' and set results to global table */
@@ -77,4 +70,3 @@ LUALIB_API void luaL_openlibs (lua_State *L) {
lua_pop(L, 1); /* remove lib */
}
}
-
diff --git a/libexec/flua/modules/lfbsd.c b/libexec/flua/modules/lfbsd.c
index 30cafcc7309e..ef660ba9fd77 100644
--- a/libexec/flua/modules/lfbsd.c
+++ b/libexec/flua/modules/lfbsd.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2023 Baptiste Daroussin <bapt@FreeBSD.org>
+ * Copyright (C) 2025 Kyle Evans <kevans@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions~
@@ -30,6 +31,7 @@
#include <errno.h>
#include <fcntl.h>
#include <spawn.h>
+#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
@@ -38,6 +40,14 @@
#include "lauxlib.h"
#include "lfbsd.h"
+#define FBSD_PROCESSHANDLE "fbsd_process_t*"
+
+struct fbsd_process {
+ int pid;
+ int stdin_fileno;
+ int stdout_fileno;
+};
+
extern char **environ;
static const char**
@@ -62,39 +72,105 @@ luaL_checkarraystrings(lua_State *L, int arg)
return ret;
}
+static void
+close_pipes(int pipes[2])
+{
+
+ if (pipes[0] != -1)
+ close(pipes[0]);
+ if (pipes[1] != -1)
+ close(pipes[1]);
+}
+
static int
lua_exec(lua_State *L)
{
- int r, pstat;
+ struct fbsd_process *proc;
+ int r;
posix_spawn_file_actions_t action;
int stdin_pipe[2] = {-1, -1};
+ int stdout_pipe[2] = {-1, -1};
pid_t pid;
const char **argv;
int n = lua_gettop(L);
- luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
- "fbsd.exec takes exactly one argument");
+ bool capture_stdout;
+ luaL_argcheck(L, n > 0 && n <= 2, n >= 2 ? 2 : n,
+ "fbsd.exec takes exactly one or two arguments");
+ capture_stdout = lua_toboolean(L, 2);
if (pipe(stdin_pipe) < 0) {
lua_pushnil(L);
lua_pushstring(L, strerror(errno));
lua_pushinteger(L, errno);
return (3);
}
+ if (capture_stdout && pipe(stdout_pipe) < 0) {
+ close_pipes(stdin_pipe);
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ lua_pushinteger(L, errno);
+ return (3);
+ }
+ proc = lua_newuserdata(L, sizeof(*proc));
+ proc->stdin_fileno = stdin_pipe[1];
+ proc->stdout_fileno = stdout_pipe[1];
posix_spawn_file_actions_init(&action);
posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
+ if (stdin_pipe[0] != STDIN_FILENO)
+ posix_spawn_file_actions_addclose(&action, stdin_pipe[0]);
+
+ /*
+ * Setup stdout to be captured if requested. Otherwise, we just let it
+ * go to our own stdout.
+ */
+ if (stdout_pipe[0] != -1) {
+ posix_spawn_file_actions_adddup2(&action, stdout_pipe[0],
+ STDOUT_FILENO);
+ posix_spawn_file_actions_addclose(&action, stdout_pipe[1]);
+ if (stdout_pipe[0] != STDOUT_FILENO) {
+ posix_spawn_file_actions_addclose(&action,
+ stdout_pipe[0]);
+ }
+ }
argv = luaL_checkarraystrings(L, 1);
if (0 != (r = posix_spawnp(&pid, argv[0], &action, NULL,
(char*const*)argv, environ))) {
+ close_pipes(stdin_pipe);
+ close_pipes(stdout_pipe);
+ posix_spawn_file_actions_destroy(&action);
+ lua_pop(L, 2); /* Pop off the process handle and args. */
+
lua_pushnil(L);
lua_pushstring(L, strerror(r));
lua_pushinteger(L, r);
return (3);
}
- while (waitpid(pid, &pstat, 0) == -1) {
- if (errno != EINTR) {
+
+ lua_pop(L, 1);
+
+ close(stdin_pipe[0]);
+ if (stdout_pipe[0] != -1)
+ close(stdout_pipe[0]);
+ posix_spawn_file_actions_destroy(&action);
+
+ proc->pid = pid;
+ luaL_setmetatable(L, FBSD_PROCESSHANDLE);
+
+ return (1);
+}
+
+static int
+lua_process_close(lua_State *L)
+{
+ struct fbsd_process *proc;
+ int pstat, r;
+
+ proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE);
+ while (waitpid(proc->pid, &pstat, 0) == -1) {
+ if ((r = errno) != EINTR) {
lua_pushnil(L);
lua_pushstring(L, strerror(r));
lua_pushinteger(L, r);
@@ -102,23 +178,89 @@ lua_exec(lua_State *L)
}
}
- if (WEXITSTATUS(pstat) != 0) {
+ if (!WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) {
lua_pushnil(L);
lua_pushstring(L, "Abnormal termination");
+ return (2);
+ }
+
+ if (proc->stdin_fileno >= 0) {
+ close(proc->stdin_fileno);
+ proc->stdin_fileno = -1;
+ }
+
+ if (proc->stdout_fileno >= 0) {
+ close(proc->stdout_fileno);
+ proc->stdout_fileno = -1;
+ }
+
+ lua_pushboolean(L, 1);
+ return (1);
+}
+
+static int
+lua_process_makestdio(lua_State *L, int fd, const char *mode)
+{
+ luaL_Stream *p;
+ FILE *fp;
+ int r;
+
+ if (fd == -1) {
+ lua_pushnil(L);
+ lua_pushstring(L, "Stream not captured");
+ return (2);
+ }
+
+ fp = fdopen(fd, mode);
+ if (fp == NULL) {
+ r = errno;
+
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(r));
lua_pushinteger(L, r);
return (3);
}
- posix_spawn_file_actions_destroy(&action);
+ p = lua_newuserdata(L, sizeof(*p));
+ p->closef = &lua_process_close;
+ p->f = fp;
+ luaL_setmetatable(L, LUA_FILEHANDLE);
+ return (1);
+}
+
+static int
+lua_process_stdin(lua_State *L)
+{
+ struct fbsd_process *proc;
+
+ proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE);
+ return (lua_process_makestdio(L, proc->stdin_fileno, "w"));
+}
- if (stdin_pipe[0] != -1)
- close(stdin_pipe[0]);
- if (stdin_pipe[1] != -1)
- close(stdin_pipe[1]);
- lua_pushinteger(L, pid);
- return 1;
+static int
+lua_process_stdout(lua_State *L)
+{
+ struct fbsd_process *proc;
+
+ proc = luaL_checkudata(L, 1, FBSD_PROCESSHANDLE);
+ return (lua_process_makestdio(L, proc->stdout_fileno, "r"));
}
+#define PROCESS_SIMPLE(n) { #n, lua_process_ ## n }
+static const struct luaL_Reg fbsd_process[] = {
+ PROCESS_SIMPLE(close),
+ PROCESS_SIMPLE(stdin),
+ PROCESS_SIMPLE(stdout),
+ { NULL, NULL },
+};
+
+static const struct luaL_Reg fbsd_process_meta[] = {
+ { "__index", NULL },
+ { "__gc", lua_process_close },
+ { "__close", lua_process_close },
+ { NULL, NULL },
+};
+
#define REG_SIMPLE(n) { #n, lua_ ## n }
static const struct luaL_Reg fbsd_lib[] = {
REG_SIMPLE(exec),
@@ -130,5 +272,14 @@ int
luaopen_fbsd(lua_State *L)
{
luaL_newlib(L, fbsd_lib);
+
+ luaL_newmetatable(L, FBSD_PROCESSHANDLE);
+ luaL_setfuncs(L, fbsd_process_meta, 0);
+
+ luaL_newlibtable(L, fbsd_process);
+ luaL_setfuncs(L, fbsd_process, 0);
+ lua_setfield(L, -2, "__index");
+ lua_pop(L, 1);
+
return (1);
}
diff --git a/libexec/flua/modules/lposix.c b/libexec/flua/modules/lposix.c
index 816d4bc688d2..75cdd345aeaa 100644
--- a/libexec/flua/modules/lposix.c
+++ b/libexec/flua/modules/lposix.c
@@ -88,18 +88,23 @@ static int
lua_chown(lua_State *L)
{
const char *path;
- uid_t owner = (uid_t) -1;
- gid_t group = (gid_t) -1;
+ uid_t owner = (uid_t)-1;
+ gid_t group = (gid_t)-1;
+ int error;
enforce_max_args(L, 3);
path = luaL_checkstring(L, 1);
if (lua_isinteger(L, 2))
- owner = (uid_t) lua_tointeger(L, 2);
+ owner = (uid_t)lua_tointeger(L, 2);
else if (lua_isstring(L, 2)) {
- struct passwd *p = getpwnam(lua_tostring(L, 2));
- if (p != NULL)
- owner = p->pw_uid;
+ char buf[4096];
+ struct passwd passwd, *pwd;
+
+ error = getpwnam_r(lua_tostring(L, 2), &passwd,
+ buf, sizeof(buf), &pwd);
+ if (error == 0)
+ owner = pwd->pw_uid;
else
return (luaL_argerror(L, 2,
lua_pushfstring(L, "unknown user %s",
@@ -112,11 +117,15 @@ lua_chown(lua_State *L)
}
if (lua_isinteger(L, 3))
- group = (gid_t) lua_tointeger(L, 3);
+ group = (gid_t)lua_tointeger(L, 3);
else if (lua_isstring(L, 3)) {
- struct group *g = getgrnam(lua_tostring(L, 3));
- if (g != NULL)
- group = g->gr_gid;
+ char buf[4096];
+ struct group gr, *grp;
+
+ error = getgrnam_r(lua_tostring(L, 3), &gr, buf, sizeof(buf),
+ &grp);
+ if (error == 0)
+ group = grp->gr_gid;
else
return (luaL_argerror(L, 3,
lua_pushfstring(L, "unknown group %s",
@@ -581,21 +590,21 @@ static const struct luaL_Reg unistdlib[] = {
#undef REG_SIMPLE
#undef REG_DEF
-int
+static int
luaopen_posix_libgen(lua_State *L)
{
luaL_newlib(L, libgenlib);
return (1);
}
-int
+static int
luaopen_posix_stdlib(lua_State *L)
{
luaL_newlib(L, stdliblib);
return (1);
}
-int
+static int
luaopen_posix_fnmatch(lua_State *L)
{
luaL_newlib(L, fnmatchlib);
@@ -613,14 +622,21 @@ luaopen_posix_fnmatch(lua_State *L)
return 1;
}
-int
+static int
luaopen_posix_sys_stat(lua_State *L)
{
luaL_newlib(L, sys_statlib);
return (1);
}
-int
+static int
+luaopen_posix_sys_utsname(lua_State *L)
+{
+ luaL_newlib(L, sys_utsnamelib);
+ return 1;
+}
+
+static int
luaopen_posix_sys_wait(lua_State *L)
{
luaL_newlib(L, sys_waitlib);
@@ -646,16 +662,38 @@ luaopen_posix_sys_wait(lua_State *L)
return (1);
}
-int
-luaopen_posix_sys_utsname(lua_State *L)
+static int
+luaopen_posix_unistd(lua_State *L)
{
- luaL_newlib(L, sys_utsnamelib);
- return 1;
+ luaL_newlib(L, unistdlib);
+ return (1);
}
int
-luaopen_posix_unistd(lua_State *L)
+luaopen_posix(lua_State *L)
{
- luaL_newlib(L, unistdlib);
+ lua_newtable(L); /* posix */
+
+ luaL_requiref(L, "posix.fnmatch", luaopen_posix_fnmatch, 0);
+ lua_setfield(L, -2, "fnmatch");
+
+ luaL_requiref(L, "posix.libgen", luaopen_posix_libgen, 0);
+ lua_setfield(L, -2, "libgen");
+
+ luaL_requiref(L, "posix.stdlib", luaopen_posix_stdlib, 0);
+ lua_setfield(L, -2, "stdlib");
+
+ lua_newtable(L); /* posix.sys */
+ luaL_requiref(L, "posix.sys.stat", luaopen_posix_sys_stat, 0);
+ lua_setfield(L, -2, "stat");
+ luaL_requiref(L, "posix.sys.utsname", luaopen_posix_sys_utsname, 0);
+ lua_setfield(L, -2, "utsname");
+ luaL_requiref(L, "posix.sys.wait", luaopen_posix_sys_wait, 0);
+ lua_setfield(L, -2, "wait");
+ lua_setfield(L, -2, "sys");
+
+ luaL_requiref(L, "posix.unistd", luaopen_posix_unistd, 0);
+ lua_setfield(L, -2, "unistd");
+
return (1);
}
diff --git a/libexec/flua/modules/lposix.h b/libexec/flua/modules/lposix.h
index da7079056826..1aa33f042571 100644
--- a/libexec/flua/modules/lposix.h
+++ b/libexec/flua/modules/lposix.h
@@ -7,10 +7,4 @@
#include <lua.h>
-int luaopen_posix_fnmatch(lua_State *L);
-int luaopen_posix_libgen(lua_State *L);
-int luaopen_posix_stdlib(lua_State *L);
-int luaopen_posix_sys_stat(lua_State *L);
-int luaopen_posix_sys_utsname(lua_State *L);
-int luaopen_posix_sys_wait(lua_State *L);
-int luaopen_posix_unistd(lua_State *L);
+int luaopen_posix(lua_State *L);
diff --git a/libexec/nuageinit/nuage.lua b/libexec/nuageinit/nuage.lua
index 11958e8b5cc2..493ae11d6ca7 100644
--- a/libexec/nuageinit/nuage.lua
+++ b/libexec/nuageinit/nuage.lua
@@ -56,6 +56,21 @@ local function errmsg(str, prepend)
os.exit(1)
end
+local function chmod(path, mode)
+ local mode = tonumber(mode, 8)
+ local _, err, msg = sys_stat.chmod(path, mode)
+ if err then
+ errmsg("chmod(" .. path .. ", " .. mode .. ") failed: " .. msg)
+ end
+end
+
+local function chown(path, owner, group)
+ local _, err, msg = unistd.chown(path, owner, group)
+ if err then
+ errmsg("chown(" .. path .. ", " .. owner .. ", " .. group .. ") failed: " .. msg)
+ end
+end
+
local function dirname(oldpath)
if not oldpath then
return nil
@@ -252,12 +267,12 @@ local function addsshkey(homedir, key)
f:write(key .. "\n")
f:close()
if chownak then
- sys_stat.chmod(ak_path, 384)
- unistd.chown(ak_path, dirattrs.uid, dirattrs.gid)
+ chmod(ak_path, "0600")
+ chown(ak_path, dirattrs.uid, dirattrs.gid)
end
if chowndotssh then
- sys_stat.chmod(dotssh_path, 448)
- unistd.chown(dotssh_path, dirattrs.uid, dirattrs.gid)
+ chmod(dotssh_path, "0700")
+ chown(dotssh_path, dirattrs.uid, dirattrs.gid)
end
end
@@ -296,10 +311,10 @@ local function addsudo(pwd)
end
f:close()
if chmodsudoers then
- sys_stat.chmod(sudoers, 416)
+ chmod(sudoers, "0640")
end
if chmodsudoersd then
- sys_stat.chmod(sudoers, 480)
+ chmod(sudoers, "0740")
end
end
@@ -521,16 +536,14 @@ local function addfile(file, defer)
end
f:close()
if file.permissions then
- -- convert from octal to decimal
- local perm = tonumber(file.permissions, 8)
- sys_stat.chmod(filepath, perm)
+ chmod(filepath, file.permissions)
end
if file.owner then
local owner, group = string.match(file.owner, "([^:]+):([^:]+)")
if not owner then
owner = file.owner
end
- unistd.chown(filepath, owner, group)
+ chown(filepath, owner, group)
end
return true
end
@@ -538,6 +551,8 @@ end
local n = {
warn = warnmsg,
err = errmsg,
+ chmod = chmod,
+ chown = chown,
dirname = dirname,
mkdir_p = mkdir_p,
sethostname = sethostname,
diff --git a/libexec/nuageinit/nuageinit b/libexec/nuageinit/nuageinit
index 84133d4373c5..0fcdc7274db3 100755
--- a/libexec/nuageinit/nuageinit
+++ b/libexec/nuageinit/nuageinit
@@ -7,7 +7,6 @@
local nuage = require("nuage")
local ucl = require("ucl")
local yaml = require("lyaml")
-local sys_stat = require("posix.sys.stat")
if #arg ~= 2 then
nuage.err("Usage: " .. arg[0] .. " <cloud-init-directory> (<config-2> | <nocloud>)", false)
@@ -157,7 +156,7 @@ local function ssh_keys(obj)
sshkey:close()
end
if keytype == "private" then
- sys_stat.chmod(path, 384)
+ nuage.chmod(path, "0600")
end
end
end
@@ -281,7 +280,7 @@ local function runcmd(obj)
end
if f ~= nil then
f:close()
- sys_stat.chmod(root .. "/var/cache/nuageinit/runcmds", 493)
+ nuage.chmod(root .. "/var/cache/nuageinit/runcmds", "0755")
end
end
@@ -503,5 +502,5 @@ if line == "#cloud-config" then
end
elseif line:sub(1, 2) == "#!" then
-- delay for execution at rc.local time --
- sys_stat.chmod(root .. "/var/cache/nuageinit/user_data", 493)
+ nuage.chmod(root .. "/var/cache/nuageinit/user_data", "0755")
end
diff --git a/libexec/rc/rc b/libexec/rc/rc
index 5ed47d6eac20..db3c3e20ab44 100644
--- a/libexec/rc/rc
+++ b/libexec/rc/rc
@@ -83,9 +83,9 @@ fi
trap "_rc_conf_loaded=false; load_rc_config" ALRM
skip="-s nostart"
-if [ `/sbin/sysctl -n security.jail.jailed` -eq 1 ]; then
+if check_jail jailed; then
skip="$skip -s nojail"
- if [ `/sbin/sysctl -n security.jail.vnet` -ne 1 ]; then
+ if ! check_jail vnet; then
skip="$skip -s nojailvnet"
fi
fi
diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf
index 00f4b718bfad..d502361eca37 100644
--- a/libexec/rc/rc.conf
+++ b/libexec/rc/rc.conf
@@ -694,7 +694,7 @@ entropy_file="/entropy" # Set to NO to disable late (used when going multi-user)
entropy_dir="/var/db/entropy" # Set to NO to disable caching entropy via cron.
entropy_save_sz="4096" # Size of the entropy cache files.
entropy_save_num="8" # Number of entropy cache files to save.
-harvest_mask="511" # Entropy device harvests all but the very invasive sources.
+harvest_mask="4607" # Entropy device harvests all but the very invasive sources.
# (See 'sysctl kern.random.harvest' and random(4))
osrelease_enable="YES" # Update /var/run/os-release on boot (or NO).
osrelease_file="/var/run/os-release" # File to update for os-release.
diff --git a/libexec/rc/rc.d/hostname b/libexec/rc/rc.d/hostname
index 8b26c4f60633..0bc31ccd787e 100755
--- a/libexec/rc/rc.d/hostname
+++ b/libexec/rc/rc.d/hostname
@@ -42,8 +42,8 @@ hostname_start()
# If we are not inside a jail, set the host name.
# If we are inside a jail, set the host name if it is permitted.
#
- if [ `$SYSCTL_N security.jail.jailed` -eq 1 ]; then
- if [ `$SYSCTL_N security.jail.set_hostname_allowed` -eq 0 ]; then
+ if check_jail jailed; then
+ if ! check_jail set_hostname_allowed; then
return
fi
else
diff --git a/libexec/rc/rc.d/pf b/libexec/rc/rc.d/pf
index 0b4c086db22b..46fb085e5175 100755
--- a/libexec/rc/rc.d/pf
+++ b/libexec/rc/rc.d/pf
@@ -38,7 +38,7 @@ pf_fallback()
$pf_program -f "$pf_fallback_rules_file" $pf_flags
else
warn "Loading fallback rules: $pf_fallback_rules"
- echo $pf_fallback_rules | $pf_program -f - $pf_flags
+ echo "$pf_fallback_rules" | $pf_program -f - $pf_flags
fi
}
diff --git a/libexec/rc/rc.d/routing b/libexec/rc/rc.d/routing
index 893acb83cf4a..dd75604125a3 100755
--- a/libexec/rc/rc.d/routing
+++ b/libexec/rc/rc.d/routing
@@ -331,7 +331,7 @@ _check_dynamicrouting()
# copied from /etc/rc
skip="-s nostart"
- if [ `/sbin/sysctl -n security.jail.jailed` -eq 1 ]; then
+ if check_jail jailed; then
skip="$skip -s nojail"
fi
[ -n "$local_startup" ] && find_local_scripts_new
diff --git a/libexec/rc/rc.d/zfs b/libexec/rc/rc.d/zfs
index 26bf3046444b..f88f65c2ec18 100755
--- a/libexec/rc/rc.d/zfs
+++ b/libexec/rc/rc.d/zfs
@@ -18,7 +18,7 @@ required_modules="zfs"
zfs_start_jail()
{
- if [ `$SYSCTL_N security.jail.mount_allowed` -eq 1 ]; then
+ if check_jail mount_allowed; then
zfs mount -a
fi
}
@@ -34,7 +34,7 @@ zfs_start_main()
zfs_start()
{
- if [ `$SYSCTL_N security.jail.jailed` -eq 1 ]; then
+ if check_jail jailed; then
zfs_start_jail
else
zfs_start_main
@@ -54,7 +54,7 @@ zfs_poststart()
zfs_stop_jail()
{
- if [ `$SYSCTL_N security.jail.mount_allowed` -eq 1 ]; then
+ if check_jail mount_allowed; then
zfs unmount -a
fi
}
@@ -67,7 +67,7 @@ zfs_stop_main()
zfs_stop()
{
- if [ `$SYSCTL_N security.jail.jailed` -eq 1 ]; then
+ if check_jail jailed; then
zfs_stop_jail
else
zfs_stop_main
diff --git a/libexec/rc/rc.d/zfsbe b/libexec/rc/rc.d/zfsbe
index f61f3bf097f0..22d53f219679 100755
--- a/libexec/rc/rc.d/zfsbe
+++ b/libexec/rc/rc.d/zfsbe
@@ -64,7 +64,7 @@ activate_bootonce()
be_start()
{
- if [ `$SYSCTL_N security.jail.jailed` -eq 1 ]; then
+ if check_jail jailed; then
:
else
mount -p | while read _dev _mp _type _rest; do
diff --git a/libexec/rc/rc.shutdown b/libexec/rc/rc.shutdown
index 18f67f5ca124..3dfd7a7e0936 100644
--- a/libexec/rc/rc.shutdown
+++ b/libexec/rc/rc.shutdown
@@ -83,9 +83,9 @@ fi
# and perform the operation
#
rcorder_opts="-k shutdown"
-if [ `/sbin/sysctl -n security.jail.jailed` -eq 1 ]; then
+if check_jail jailed; then
rcorder_opts="$rcorder_opts -s nojail"
- if [ `/sbin/sysctl -n security.jail.vnet` -ne 1 ]; then
+ if ! check_jail vnet; then
rcorder_opts="$rcorder_opts -s nojailvnet"
fi
fi
diff --git a/libexec/rc/rc.subr b/libexec/rc/rc.subr
index 2eaf336b5220..a2e2e98a5087 100644
--- a/libexec/rc/rc.subr
+++ b/libexec/rc/rc.subr
@@ -1689,7 +1689,7 @@ $_cpusetcmd $command $rc_flags $command_args"
start)
# We cannot use protect(1) inside jails.
if [ -n "$_oomprotect" ] && [ -f "${PROTECT}" ] &&
- [ "$(sysctl -n security.jail.jailed)" -eq 0 ]; then
+ ! check_jail jailed; then
[ -z "${rc_pid}" ] && eval $_pidcmd
case $_oomprotect in
[Aa][Ll][Ll])
@@ -2671,7 +2671,7 @@ check_required_after()
}
# check_jail mib
-# Return true if security.jail.$mib exists and set to 1.
+# Return true if security.jail.$mib exists and is set to 1.
check_jail()
{
diff --git a/libexec/rc/tests/rc_subr_test.sh b/libexec/rc/tests/rc_subr_test.sh
index 60f77c2c2de3..9931389e7a02 100644
--- a/libexec/rc/tests/rc_subr_test.sh
+++ b/libexec/rc/tests/rc_subr_test.sh
@@ -52,7 +52,7 @@ oomprotect_all_body()
_rc_arg="$4"
setvar "${name}_oomprotect" all
command="/usr/sbin/daemon"
- command_args="-P $pidfile -p $_childpidfile -- /bin/sleep 5"
+ command_args="-P $pidfile -p $_childpidfile -- /bin/sleep 60"
run_rc_command "$_rc_arg"
LITERAL
@@ -92,7 +92,7 @@ oomprotect_yes_body()
setvar "${name}_oomprotect" yes
procname="/bin/sleep"
command="/usr/sbin/daemon"
- command_args="-p $pidfile -- $procname 5"
+ command_args="-p $pidfile -- $procname 60"
run_rc_command "$_rc_arg"
LITERAL
diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c
index 2b64b48585db..62d664f8fb80 100644
--- a/libexec/rtld-elf/aarch64/reloc.c
+++ b/libexec/rtld-elf/aarch64/reloc.c
@@ -37,13 +37,6 @@
#include "rtld_printf.h"
/*
- * It is possible for the compiler to emit relocations for unaligned data.
- * We handle this situation with these inlines.
- */
-#define RELOC_ALIGNED_P(x) \
- (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
-
-/*
* This is not the correct prototype, but we only need it for
* a function pointer to a simple asm function.
*/
diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
index 04d17072af77..c6a98b50a165 100644
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -337,7 +337,7 @@ map_object(int fd, const char *path, const struct stat *sb, bool ismain)
obj->tlsalign = phtls->p_align;
obj->tlspoffset = phtls->p_offset;
obj->tlsinitsize = phtls->p_filesz;
- obj->tlsinit = mapbase + phtls->p_vaddr;
+ obj->tlsinit = obj->relocbase + phtls->p_vaddr;
}
obj->stack_flags = stack_flags;
if (note_start < note_end)
diff --git a/libexec/rtld-elf/riscv/reloc.c b/libexec/rtld-elf/riscv/reloc.c
index 390e8c458c28..25c0befb774e 100644
--- a/libexec/rtld-elf/riscv/reloc.c
+++ b/libexec/rtld-elf/riscv/reloc.c
@@ -40,13 +40,6 @@
#include "rtld.h"
#include "rtld_printf.h"
-/*
- * It is possible for the compiler to emit relocations for unaligned data.
- * We handle this situation with these inlines.
- */
-#define RELOC_ALIGNED_P(x) \
- (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
-
uint64_t
set_gp(Obj_Entry *obj)
{
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 1459b38f3720..17196f55c271 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -82,9 +82,15 @@ struct dlerror_save {
char *msg;
};
+struct tcb_list_entry {
+ TAILQ_ENTRY(tcb_list_entry) next;
+};
+
/*
* Function declarations.
*/
+static bool allocate_tls_offset_common(size_t *offp, size_t tlssize,
+ size_t tlsalign, size_t tlspoffset);
static const char *basename(const char *);
static void digest_dynamic1(Obj_Entry *, int, const Elf_Dyn **,
const Elf_Dyn **, const Elf_Dyn **);
@@ -92,7 +98,7 @@ static bool digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *,
const Elf_Dyn *);
static bool digest_dynamic(Obj_Entry *, int);
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
-static void distribute_static_tls(Objlist *, RtldLockState *);
+static void distribute_static_tls(Objlist *);
static Obj_Entry *dlcheck(void *);
static int dlclose_locked(void *, RtldLockState *);
static Obj_Entry *dlopen_object(const char *name, int fd, Obj_Entry *refobj,
@@ -303,6 +309,10 @@ static size_t tls_static_max_align;
Elf_Addr tls_dtv_generation = 1; /* Used to detect when dtv size changes */
int tls_max_index = 1; /* Largest module index allocated */
+static TAILQ_HEAD(, tcb_list_entry) tcb_list =
+ TAILQ_HEAD_INITIALIZER(tcb_list);
+static size_t tcb_list_entry_offset;
+
static bool ld_library_path_rpath = false;
bool ld_fast_sigblock = false;
@@ -929,6 +939,19 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
allocate_tls_offset(entry->obj);
}
+ if (!allocate_tls_offset_common(&tcb_list_entry_offset,
+ sizeof(struct tcb_list_entry), _Alignof(struct tcb_list_entry),
+ 0)) {
+ /*
+ * This should be impossible as the static block size is not
+ * yet fixed, but catch and diagnose it failing if that ever
+ * changes or somehow turns out to be false.
+ */
+ _rtld_error("Could not allocate offset for tcb_list_entry");
+ rtld_die();
+ }
+ dbg("tcb_list_entry_offset %zu", tcb_list_entry_offset);
+
if (relocate_objects(obj_main,
ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld,
SYMLOOK_EARLY, NULL) == -1)
@@ -3973,7 +3996,7 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
if ((lo_flags & RTLD_LO_EARLY) == 0) {
map_stacks_exec(lockstate);
if (obj != NULL)
- distribute_static_tls(&initlist, lockstate);
+ distribute_static_tls(&initlist);
}
if (initlist_objects_ifunc(&initlist, (mode & RTLD_MODEMASK) ==
@@ -5400,6 +5423,44 @@ tls_get_addr_common(struct tcb *tcb, int index, size_t offset)
return (tls_get_addr_slow(tcb, index, offset, false));
}
+static struct tcb *
+tcb_from_tcb_list_entry(struct tcb_list_entry *tcbelm)
+{
+#ifdef TLS_VARIANT_I
+ return ((struct tcb *)((char *)tcbelm - tcb_list_entry_offset));
+#else
+ return ((struct tcb *)((char *)tcbelm + tcb_list_entry_offset));
+#endif
+}
+
+static struct tcb_list_entry *
+tcb_list_entry_from_tcb(struct tcb *tcb)
+{
+#ifdef TLS_VARIANT_I
+ return ((struct tcb_list_entry *)((char *)tcb + tcb_list_entry_offset));
+#else
+ return ((struct tcb_list_entry *)((char *)tcb - tcb_list_entry_offset));
+#endif
+}
+
+static void
+tcb_list_insert(struct tcb *tcb)
+{
+ struct tcb_list_entry *tcbelm;
+
+ tcbelm = tcb_list_entry_from_tcb(tcb);
+ TAILQ_INSERT_TAIL(&tcb_list, tcbelm, next);
+}
+
+static void
+tcb_list_remove(struct tcb *tcb)
+{
+ struct tcb_list_entry *tcbelm;
+
+ tcbelm = tcb_list_entry_from_tcb(tcb);
+ TAILQ_REMOVE(&tcb_list, tcbelm, next);
+}
+
#ifdef TLS_VARIANT_I
/*
@@ -5513,6 +5574,7 @@ allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign)
}
}
+ tcb_list_insert(tcb);
return (tcb);
}
@@ -5524,6 +5586,8 @@ free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused)
size_t post_size;
size_t i, tls_init_align __unused;
+ tcb_list_remove(tcb);
+
assert(tcbsize >= TLS_TCB_SIZE);
tls_init_align = MAX(obj_main->tlsalign, 1);
@@ -5624,6 +5688,7 @@ allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign)
}
}
+ tcb_list_insert(tcb);
return (tcb);
}
@@ -5635,6 +5700,8 @@ free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
size_t i;
uintptr_t tlsstart, tlsend;
+ tcb_list_remove(tcb);
+
/*
* Figure out the size of the initial TLS block so that we can
* find stuff which ___tls_get_addr() allocated dynamically.
@@ -5698,32 +5765,22 @@ allocate_module_tls(struct tcb *tcb, int index)
return (p);
}
-bool
-allocate_tls_offset(Obj_Entry *obj)
+static bool
+allocate_tls_offset_common(size_t *offp, size_t tlssize, size_t tlsalign,
+ size_t tlspoffset __unused)
{
size_t off;
- if (obj->tls_dynamic)
- return (false);
-
- if (obj->tls_static)
- return (true);
-
- if (obj->tlssize == 0) {
- obj->tls_static = true;
- return (true);
- }
-
if (tls_last_offset == 0)
- off = calculate_first_tls_offset(obj->tlssize, obj->tlsalign,
- obj->tlspoffset);
+ off = calculate_first_tls_offset(tlssize, tlsalign,
+ tlspoffset);
else
off = calculate_tls_offset(tls_last_offset, tls_last_size,
- obj->tlssize, obj->tlsalign, obj->tlspoffset);
+ tlssize, tlsalign, tlspoffset);
- obj->tlsoffset = off;
+ *offp = off;
#ifdef TLS_VARIANT_I
- off += obj->tlssize;
+ off += tlssize;
#endif
/*
@@ -5735,12 +5792,34 @@ allocate_tls_offset(Obj_Entry *obj)
if (tls_static_space != 0) {
if (off > tls_static_space)
return (false);
- } else if (obj->tlsalign > tls_static_max_align) {
- tls_static_max_align = obj->tlsalign;
+ } else if (tlsalign > tls_static_max_align) {
+ tls_static_max_align = tlsalign;
}
tls_last_offset = off;
- tls_last_size = obj->tlssize;
+ tls_last_size = tlssize;
+
+ return (true);
+}
+
+bool
+allocate_tls_offset(Obj_Entry *obj)
+{
+ if (obj->tls_dynamic)
+ return (false);
+
+ if (obj->tls_static)
+ return (true);
+
+ if (obj->tlssize == 0) {
+ obj->tls_static = true;
+ return (true);
+ }
+
+ if (!allocate_tls_offset_common(&obj->tlsoffset, obj->tlssize,
+ obj->tlsalign, obj->tlspoffset))
+ return (false);
+
obj->tls_static = true;
return (true);
@@ -6124,25 +6203,29 @@ map_stacks_exec(RtldLockState *lockstate)
}
static void
-distribute_static_tls(Objlist *list, RtldLockState *lockstate)
+distribute_static_tls(Objlist *list)
{
- Objlist_Entry *elm;
+ struct tcb_list_entry *tcbelm;
+ Objlist_Entry *objelm;
+ struct tcb *tcb;
Obj_Entry *obj;
- void (*distrib)(size_t, void *, size_t, size_t);
+ char *tlsbase;
- distrib = (void (*)(size_t, void *, size_t, size_t))(
- uintptr_t)get_program_var_addr("__pthread_distribute_static_tls",
- lockstate);
- if (distrib == NULL)
- return;
- STAILQ_FOREACH(elm, list, link) {
- obj = elm->obj;
+ STAILQ_FOREACH(objelm, list, link) {
+ obj = objelm->obj;
if (obj->marker || !obj->tls_static || obj->static_tls_copied)
continue;
- lock_release(rtld_bind_lock, lockstate);
- distrib(obj->tlsoffset, obj->tlsinit, obj->tlsinitsize,
- obj->tlssize);
- wlock_acquire(rtld_bind_lock, lockstate);
+ TAILQ_FOREACH(tcbelm, &tcb_list, next) {
+ tcb = tcb_from_tcb_list_entry(tcbelm);
+#ifdef TLS_VARIANT_I
+ tlsbase = (char *)tcb + obj->tlsoffset;
+#else
+ tlsbase = (char *)tcb - obj->tlsoffset;
+#endif
+ memcpy(tlsbase, obj->tlsinit, obj->tlsinitsize);
+ memset(tlsbase + obj->tlsinitsize, 0,
+ obj->tlssize - obj->tlsinitsize);
+ }
obj->static_tls_copied = true;
}
}
diff --git a/release/Makefile b/release/Makefile
index 84f29983b6c7..b6a9aa42c2e2 100644
--- a/release/Makefile
+++ b/release/Makefile
@@ -162,7 +162,8 @@ kernel.txz: # Also (if enabled) kernel-dbg.txz.
src.txz:
mkdir -p ${DISTDIR}/usr
- ln -fs ${WORLDDIR} ${DISTDIR}/usr/src
+ rm -f ${DISTDIR}/usr/src
+ ln -s ${WORLDDIR} ${DISTDIR}/usr/src
( cd ${DISTDIR} && ${TAR_XZ_CMD} -cLvf ${.OBJDIR}/src.txz \
--exclude .svn --exclude .zfs \
--exclude .git --exclude @ --exclude usr/src/release/dist \
@@ -170,7 +171,8 @@ src.txz:
ports.txz:
mkdir -p ${DISTDIR}/usr
- ln -fs ${PORTSDIR} ${DISTDIR}/usr/ports
+ rm -f ${DISTDIR}/usr/ports
+ ln -s ${PORTSDIR} ${DISTDIR}/usr/ports
( cd ${DISTDIR} && ${TAR_XZ_CMD} -cLvf ${.OBJDIR}/ports.txz \
--exclude .git --exclude .svn \
--exclude usr/ports/distfiles --exclude usr/ports/packages \
@@ -276,6 +278,7 @@ bootonly:
.if ${.MAKE.OS} == "FreeBSD" && (!defined(NOPKG) || empty(NOPKG))
# Install packages onto release media.
${PKG_INSTALL} pkg || true
+ ${PKG_INSTALL} wifi-firmware-iwlwifi-kmod wifi-firmware-rtw88-kmod || true
${PKG_CLEAN} || true
.endif
# Set up installation environment
@@ -340,8 +343,8 @@ dvd: ${PKGBASE_REPO}
echo hostid_enable=\"NO\" >> ${.TARGET}/etc/rc.conf
echo debug.witness.trace=0 >> ${.TARGET}/etc/sysctl.conf
echo vfs.mountroot.timeout=\"10\" >> ${.TARGET}/boot/loader.conf
- echo loader_brand=\"install\" >> ${.TARGET}/boot/loader.conf
echo kernels_autodetect=\"NO\" >> ${.TARGET}/boot/loader.conf
+ echo loader_brand=\"install\" >> ${.TARGET}/boot/loader.conf
echo loader_menu_multi_user_prompt=\"Installer\" >> ${.TARGET}/boot/loader.conf
cp ${.CURDIR}/rc.local ${.TARGET}/etc
echo "./etc/resolv.conf type=link uname=root gname=wheel mode=0644 link=/tmp/bsdinstall_etc/resolv.conf" >> ${.TARGET}/METALOG
diff --git a/release/amd64/make-memstick.sh b/release/amd64/make-memstick.sh
index cbb80e971343..cec4b27b5b96 100755
--- a/release/amd64/make-memstick.sh
+++ b/release/amd64/make-memstick.sh
@@ -12,6 +12,7 @@
set -e
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
if [ "$(uname -s)" = "FreeBSD" ]; then
@@ -51,7 +52,7 @@ if [ -n "${METALOG}" ]; then
echo "./etc/rc.conf.local type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
rm ${BASEBITSDIR}/etc/fstab
rm ${BASEBITSDIR}/etc/rc.conf.local
if [ -n "${METALOG}" ]; then
@@ -67,10 +68,10 @@ else
make_esp_file ${espfilename} ${fat32min} ${BASEBITSDIR}/boot/loader.efi
fi
-mkimg -s mbr \
+${MKIMG} -s mbr \
-b ${BASEBITSDIR}/boot/mbr \
-p efi:=${espfilename} \
- -p freebsd:-"mkimg -s bsd -b ${BASEBITSDIR}/boot/boot -p freebsd-ufs:=${2}.part" \
+ -p freebsd:-"${MKIMG} -s bsd -b ${BASEBITSDIR}/boot/boot -p freebsd-ufs:=${2}.part" \
-a 2 \
-o ${2}
rm ${espfilename}
diff --git a/release/amd64/mkisoimages.sh b/release/amd64/mkisoimages.sh
index 245beb660c3f..8f7163e05261 100644
--- a/release/amd64/mkisoimages.sh
+++ b/release/amd64/mkisoimages.sh
@@ -25,20 +25,9 @@
set -e
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
-if [ -z $ETDUMP ]; then
- ETDUMP=etdump
-fi
-
-if [ -z $MAKEFS ]; then
- MAKEFS=makefs
-fi
-
-if [ -z $MKIMG ]; then
- MKIMG=mkimg
-fi
-
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
diff --git a/release/arm64/make-memstick.sh b/release/arm64/make-memstick.sh
index 90ff98b394c7..0da59c29635b 100755
--- a/release/arm64/make-memstick.sh
+++ b/release/arm64/make-memstick.sh
@@ -17,6 +17,7 @@ if [ "$(uname -s)" = "FreeBSD" ]; then
fi
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
if [ $# -ne 2 ]; then
@@ -51,7 +52,7 @@ if [ -n "${METALOG}" ]; then
echo "./etc/rc.conf.local type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
rm ${BASEBITSDIR}/etc/fstab
rm ${BASEBITSDIR}/etc/rc.conf.local
if [ -n "${METALOG}" ]; then
@@ -62,7 +63,7 @@ fi
espfilename=$(mktemp /tmp/efiboot.XXXXXX)
make_esp_file ${espfilename} ${fat32min} ${BASEBITSDIR}/boot/loader.efi
-mkimg -s gpt \
+${MKIMG} -s gpt \
-p efi:=${espfilename} \
-p freebsd-ufs:=${2}.part \
-o ${2}
diff --git a/release/arm64/mkisoimages.sh b/release/arm64/mkisoimages.sh
index cb58178ed4b9..46b16f0ce08d 100644
--- a/release/arm64/mkisoimages.sh
+++ b/release/arm64/mkisoimages.sh
@@ -21,20 +21,9 @@
set -e
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
-if [ -z $ETDUMP ]; then
- ETDUMP=etdump
-fi
-
-if [ -z $MAKEFS ]; then
- MAKEFS=makefs
-fi
-
-if [ -z $MKIMG ]; then
- MKIMG=mkimg
-fi
-
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
diff --git a/release/i386/make-memstick.sh b/release/i386/make-memstick.sh
index 7a20be20c026..ad2126b0a8f8 100755
--- a/release/i386/make-memstick.sh
+++ b/release/i386/make-memstick.sh
@@ -11,6 +11,9 @@
set -e
+scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
+
if [ "$(uname -s)" = "FreeBSD" ]; then
PATH=/bin:/usr/bin:/sbin:/usr/sbin
export PATH
@@ -48,16 +51,16 @@ if [ -n "${METALOG}" ]; then
echo "./etc/rc.conf.local type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
rm ${BASEBITSDIR}/etc/fstab
rm ${BASEBITSDIR}/etc/rc.conf.local
if [ -n "${METALOG}" ]; then
rm ${metalogfilename}
fi
-mkimg -s mbr \
+${MKIMG} -s mbr \
-b ${BASEBITSDIR}/boot/mbr \
- -p freebsd:-"mkimg -s bsd -b ${BASEBITSDIR}/boot/boot -p freebsd-ufs:=${2}.part" \
+ -p freebsd:-"${MKIMG} -s bsd -b ${BASEBITSDIR}/boot/boot -p freebsd-ufs:=${2}.part" \
-o ${2}
rm ${2}.part
diff --git a/release/i386/mkisoimages.sh b/release/i386/mkisoimages.sh
index 8f000aae3b17..1918b36eeb44 100644
--- a/release/i386/mkisoimages.sh
+++ b/release/i386/mkisoimages.sh
@@ -24,6 +24,9 @@
set -e
+scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
+
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
@@ -67,7 +70,7 @@ if [ -n "${METALOG}" ]; then
echo "./etc/fstab type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$MAKEFSARG" "$@"
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$MAKEFSARG" "$@"
rm -f "$BASEBITSDIR/etc/fstab"
if [ -n "${METALOG}" ]; then
rm ${metalogfilename}
diff --git a/release/packages/Makefile.package b/release/packages/Makefile.package
deleted file mode 100644
index c2427aa16945..000000000000
--- a/release/packages/Makefile.package
+++ /dev/null
@@ -1,193 +0,0 @@
-#
-#
-
-acct_COMMENT= System Accounting Utilities
-acct_DESC= System Accounting Utilities
-acpi_COMMENT= ACPI Utilities
-acpi_DESC= ACPI Utilities
-amd_COMMENT= AMD Utilities
-amd_DESC= AMD Utilities
-apm_COMMENT= APM Utilities
-apm_DESC= APM Utilities
-at_COMMENT= AT Utilities
-at_DESC= AT Utilities
-audit_COMMENT= OpenBSM auditing utilities
-audit_DESC= OpenBSM auditing utilities
-autofs_COMMENT= Autofs Utilities
-autofs_DESC= Autofs Utilities
-bhyve_COMMENT= Bhyve Utilities
-bhyve_DESC= Bhyve Utilities
-blocklist_COMMENT= Blocklist Utilities
-blocklist_DESC= Blocklist Utilities
-bluetooth_COMMENT= Bluetooth Utilities
-bluetooth_DESC= Bluetooth Utilities
-bootloader_COMMENT= Bootloader
-bootloader_DESC= Bootloader and configuration files
-bsdinstall_COMMENT= BSDInstall Utilities
-bsdinstall_DESC= BSDInstall Utilities
-bsnmp_COMMENT= BSNMP Utilities
-bsnmp_DESC= BSNMP Utilities
-caroot_COMMENT= SSL Certificates
-caroot_DESC= SSL Certificates
-clang_COMMENT= Clang Utilities
-clang_DESC= Clang Utilities
-clibs_COMMENT= Core C Libraries
-clibs_DESC= Core C Libraries
-certctl_COMMENT= SSL Certificate Utility
-certctl_DESC= SSL Certificate Utility
-console-tools_COMMENT= Console Utilities
-console-tools_DESC= Console Utilities
-cron_COMMENT= cron(8) and crontab(1)
-cron_DESC= cron(8) and crontab(1)
-csh_COMMENT= C Shell
-csh_DESC= C Shell
-ctf-tools_COMMENT= CTF Utilities
-ctf-tools_DESC= CTF Utilities
-cxgbe-tools_COMMENT= Chelsio cxbge Utilities
-cxgbe-tools_DESC= Chelsio cxbge Utilities
-devd_COMMENT= Devd Utility and scripts
-devd_DESC= Devd Utility and scripts
-devmatch_COMMENT= Devmatch Utility
-devmatch_DESC= Devmatch Utility
-dhclient_COMMENT= DHCP Client
-dhclient_DESC= DHCP Client
-dma_COMMENT= DMA Mail Agent Utilities
-dma_DESC= DMA Mail Agent Utilities
-docs_COMMENT= Documentation
-docs_DESC= Documentation
-dtrace_COMMENT= Dtrace Utilities
-dtrace_DESC= Dtrace Utilities
-dwatch_COMMENT= Dwatch Utilities
-dwatch_DESC= Dwatch Utilities
-ee_COMMENT= Easy Editor Utilities
-ee_DESC= Easy Editor Utilities
-efi-tools_COMMENT= UEFI Utilities
-efi-tools_DESC= UEFI Utilities
-examples_COMMENT= Examples in /usr/share/examples
-examples_DESC= Examples in /usr/share/examples
-fd_COMMENT= Floppy disk support
-fd_DESC= Floppy disk support
-fetch_COMMENT= Fetch Utility
-fetch_DESC= Fetch Utility
-firmware-iwm_DESC= iwm(4) firmwares
-firmware-iwm_COMMENT= iwm(4) firmwares
-ftp_COMMENT= FTP Utilities
-ftp_DESC= FTP Utilities
-ftpd_COMMENT= FTP Daemon
-ftpd_DESC= FTP Daemon
-fwget_COMMENT= FWGET Utility
-fwget_DESC= FWGET Utility
-games_COMMENT= Games
-games_DESC= Games
-geom_COMMENT= GEOM Utilitites
-geom_DESC= GEOM Utilitites
-ggate_COMMENT= GEOM Gate Utilities
-ggate_DESC= GEOM Gate Utilities
-hast_COMMENT= Highly Available Storage daemon
-hast_DESC= Highly Available Storage daemon
-hostapd_COMMENT= 802.11 Access Point Daemon an Utilities
-hostapd_DESC= 802.11 Access Point Daemon an Utilities
-hyperv-tools_COMMENT= Microsoft HyperV Utilities
-hyperv-tools_DESC= Microsoft HyperV Utilities
-inetd_COMMENT= Internet super-server
-inetd_DESC= Internet super-server
-jail_COMMENT= Jail Utilities
-jail_DESC= Jail Utilities
-jail-debug_DESCR= Debugging Symbols
-jail-development_DESCR=Development Files
-jail-profile_DESCR= Profiling Libraries
-jail-lib32_DESCR= 32-bit Libraries
-jail-lib32-debug_DESCR=32-bit Debugging Symbols
-jail-lib32-development_DESCR=32-bit Development Files
-jail-lib32-profile_DESCR=32-bit Profiling Libraries
-kerberos_COMMENT= Kerberos Utilities
-kerberos_DESC= Kerberos Utilities
-kerberos-lib_COMMENT= Kerberos Libraries
-kerberos-lib_DESC= Kerberos Libraries
-kernel_COMMENT= FreeBSD Kernel
-kernel_DESC= FreeBSD Kernel
-lp_COMMENT= Printer subsystem
-lp_DESC= Printer subsystem
-manuals_COMMENT= Manual Pages
-manuals_DESC= Manual Pages
-mlx-tools_COMMENT= Mellanox Utilities
-mlx-tools_DESC= Mellanox Utilities
-mtree_COMMENT= MTREE Files
-mtree_DESC= MTREE Files
-netmap_COMMENT= Netmap Library and Utilities
-netmap_DESC= Netmap Library and Utilities
-newsyslog_COMMENT= Newsyslog Utility
-newsyslog_DESC= Newsyslog Utility
-nfs_COMMENT= NFS Utilities
-nfs_DESC= NFS Utilities
-ntp_COMMENT= Network Time Protocol server and client
-ntp_DESC= Network Time Protocol server and client
-nuageinit_COMMENT= CloudInit support scripts
-nuageinit_DESC= CloudInit support scripts
-nvme-tools_COMMENT= NVME Utilities
-nvme-tools_DESC= NVME Utilities
-openssl_COMMENT= OpenSSL Utility
-openssl_DESC= OpenSSL Utility
-openssl-lib_COMMENT= OpenSSL Libraries
-openssl-lib_DESC= OpenSSL Libraries
-pkg-bootstrap_COMMENT= pkg bootstrap Utility
-pkg-bootstrap_DESC= pkg bootstrap Utility
-periodic_COMMENT= Periodic Utility
-periodic_DESC= Periodic Utility
-rc_COMMENT= RC Scripts
-rc_DESC= RC Scripts
-rcmds_COMMENT= BSD/SunOS remote status commands
-rcmds_DESC=\
-The BSD/SunOS remote status commands, which can be used to query or interact\
-with remote hosts over the network. This includes the command-line utilities\
-rwho, ruptime, rup, rusers and rwall and the daemons rwhod, rpc.rstatd,\
-rpc.rusersd, and rpc.rwalld.
-rdma_COMMENT= RDMA Utilities
-rdma_DESC= RDMA Utilities
-rescue_COMMENT= Rescue Utilities
-rescue_DESC= Rescue Utilities
-resolvconf_COMMENT= Resolvconf Utility and scripts
-resolvconf_DESC= Resolvconf Utility and scripts
-runtime_COMMENT= FreeBSD Base System
-runtime_DESC= FreeBSD Base System
-runtime-debug_DESCR= Debugging Symbols
-runtime-development_DESCR=Development Files
-runtime-profile_DESCR= Profiling Libraries
-runtime-lib32_DESCR= 32-bit Libraries
-runtime-lib32-debug_DESCR=32-bit Debugging Symbols
-runtime-lib32-development_DESCR=32-bit Development Files
-runtime-lib32-profile_DESCR=32-bit Profiling Libraries
-sendmail_COMMENT= Sendmail Utilities
-sendmail_DESC= Sendmail Utilities
-smbutils_COMMENT= SMB Utilities
-smbutils_DESC= SMB Utilities
-ssh_COMMENT= Secure Shell Utilities
-ssh_DESC= Secure Shell Utilities
-syscons_COMMENT= Syscons Console
-syscons_DESC= Syscons Console
-syslogd_COMMENT= Syslog Daemon
-syslogd_DESC= Syslog Daemon
-tcpd_COMMENT= TCP Wrapper utilities
-tcpd_DESC= TCP Wrapper utilities
-telnet_COMMENT= Telnet client
-telnet_DESC= Telnet client
-tests_COMMENT= Test Suite
-tests_DESC= Test Suite
-toolchain_COMMENT= Utilities for program development
-toolchain_DESC= Utilities for program development
-ufs_COMMENT= UFS Libraries and Utilities
-ufs_DESC= UFS Libraries and Utilities
-unbound_COMMENT= Unbound DNS Resolver
-unbound_DESC= Unbound DNS Resolver
-utilities_COMMENT= Non-vital programs and libraries
-utilities_DESC= Non-vital programs and libraries
-vi_COMMENT= Vi Editor
-vi_DESC= Vi Editor
-vt_COMMENT= VT fonts and keyboard files
-vt_DESC= VT fonts and keyboard files
-wpa_COMMENT= 802.11 Supplicant
-wpa_DESC= 802.11 Supplicant
-yp_COMMENT= Yellow Pages programs
-yp_DESC= Yellow Pages programs
-zfs_COMMENT= ZFS Libraries and Utilities
-zfs_DESC= ZFS Libraries and Utilities
diff --git a/release/packages/certctl.ucl b/release/packages/certctl.ucl
deleted file mode 100644
index 664a6d139585..000000000000
--- a/release/packages/certctl.ucl
+++ /dev/null
@@ -1,9 +0,0 @@
-scripts: {
- # XXX If pkg picks up a mechanism to detect in the post-install script
- # files being added or removed, we should use it instead to gate the
- # rehash.
- post-install = <<EOD
- [ -x /usr/sbin/certctl ] && env DESTDIR=${PKG_ROOTDIR} \
- /usr/sbin/certctl rehash
-EOD
-}
diff --git a/release/packages/clang-all.ucl b/release/packages/clang-all.ucl
deleted file mode 100644
index 41a697ebe53d..000000000000
--- a/release/packages/clang-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ NCSA ]
diff --git a/release/packages/generate-ucl.lua b/release/packages/generate-ucl.lua
index ae6ee58dd84a..3d91d11bc42f 100755
--- a/release/packages/generate-ucl.lua
+++ b/release/packages/generate-ucl.lua
@@ -3,33 +3,174 @@
--[[ usage:
generare-ucl.lua [<variablename> <variablevalue>]... <sourceucl> <destucl>
-In the <destucl> files the variable <variablename> (in the form ${variablename}
-in the <sourceucl>) will be expanded to <variablevalue>.
-
-The undefined variables will reamin unmofifier "${variablename}"
+Build a package's UCL configuration by loading the template UCL file
+<sourceucl>, replacing any $VARIABLES in the UCL based on the provided
+variables, then writing the result to <destucl>.
]]--
local ucl = require("ucl")
+-- Give subpackages a special comment and description suffix to indicate what
+-- they contain, so e.g. "foo-man" has " (manual pages)" appended to its
+-- comment. This avoids having to create a separate ucl files for every
+-- subpackage just to set this.
+--
+-- Note that this is not a key table because the order of the pattern matches
+-- is important.
+pkg_suffixes = {
+ {
+ "%-dev%-lib32$", "(32-bit development files)",
+ "This package contains development files for compiling "..
+ "32-bit applications on a 64-bit host."
+ },
+ {
+ "%-dbg%-lib32$", "(32-bit debugging symbols)",
+ "This package contains 32-bit external debugging symbols "..
+ "for use with a source-level debugger.",
+ },
+ {
+ "%-man%-lib32$", "(32-bit manual pages)",
+ "This package contains the online manual pages for 32-bit "..
+ "components on a 64-bit host.",
+ },
+ {
+ "%-lib32$", "(32-bit libraries)",
+ "This package contains 32-bit libraries for running 32-bit "..
+ "applications on a 64-bit host.",
+ },
+ {
+ "%-dev$", "(development files)",
+ "This package contains development files for "..
+ "compiling applications."
+ },
+ {
+ "%-man$", "(manual pages)",
+ "This package contains the online manual pages."
+ },
+ {
+ "%-dbg$", "(debugging symbols)",
+ "This package contains external debugging symbols for use "..
+ "with a source-level debugger.",
+ },
+}
+
+function add_suffixes(obj)
+ local pkgname = obj["name"]
+ for _,pattern in pairs(pkg_suffixes) do
+ if pkgname:match(pattern[1]) ~= nil then
+ obj["comment"] = obj["comment"] .. " " .. pattern[2]
+ obj["desc"] = obj["desc"] .. "\n\n" .. pattern[3]
+ return
+ end
+ end
+end
+
+-- Hardcode a list of packages which don't get the automatic pkggenname
+-- dependency because the base package doesn't exist. We should have a better
+-- way to handle this.
+local no_gen_deps = {
+ ["libcompat-dev"] = true,
+ ["libcompat-dev-lib32"] = true,
+ ["libcompat-man"] = true,
+ ["libcompiler_rt-dev"] = true,
+ ["libcompiler_rt-dev-lib32"] = true,
+ ["liby-dev"] = true,
+ ["liby-dev-lib32"] = true,
+}
+
+-- Return true if the package 'pkgname' should have a dependency on the package
+-- pkggenname.
+function add_gen_dep(pkgname, pkggenname)
+ if pkgname == pkggenname then
+ return false
+ end
+ if pkgname == nil or pkggenname == nil then
+ return false
+ end
+ if no_gen_deps[pkgname] ~= nil then
+ return false
+ end
+ if pkggenname == "kernel" then
+ return false
+ end
+
+ return true
+end
+
+local pkgname = nil
+local pkggenname = nil
+local pkgprefix = nil
+local pkgversion = nil
+
+-- This parser is the output UCL we want to build.
+local parser = ucl.parser()
+
+-- Set any $VARIABLES from the command line in the parser. This causes ucl to
+-- automatically replace them when we load the source ucl.
if #arg < 2 or #arg % 2 ~= 0 then
io.stderr:write(arg[0] .. ": expected an even number of arguments, got " .. #arg)
os.exit(1)
end
-local parser = ucl.parser()
for i = 2, #arg - 2, 2 do
- parser:register_variable(arg[i - 1], arg[i])
+ local varname = arg[i - 1]
+ local varvalue = arg[i]
+
+ if varname == "PKGNAME" and #varvalue > 0 then
+ pkgname = varvalue
+ elseif varname == "PKGGENNAME" and #varvalue > 0 then
+ pkggenname = varvalue
+ elseif varname == "VERSION" and #varvalue > 0 then
+ pkgversion = varvalue
+ elseif varname == "PKG_NAME_PREFIX" and #varvalue > 0 then
+ pkgprefix = varvalue
+ end
+
+ parser:register_variable(varname, varvalue)
end
+
+-- Load the source ucl file.
local res,err = parser:parse_file(arg[#arg - 1])
if not res then
io.stderr:write(arg[0] .. ": fail to parse("..arg[#arg - 1].."): "..err)
os.exit(1)
end
+
+local obj = parser:get_object()
+
+-- If pkgname is different from pkggenname, add a dependency on pkggenname.
+-- This means that e.g. -dev packages depend on their respective base package.
+if add_gen_dep(pkgname, pkggenname) then
+ if obj["deps"] == nil then
+ obj["deps"] = {}
+ end
+ obj["deps"][pkggenname] = {
+ ["version"] = pkgversion,
+ ["origin"] = "base"
+ }
+end
+
+-- If PKG_NAME_PREFIX is provided, rewrite the names of dependency packages.
+-- We can't do this in UCL since variable substitution doesn't work in array
+-- keys.
+if pkgprefix ~= nil and obj["deps"] ~= nil then
+ newdeps = {}
+ for dep, opts in pairs(obj["deps"]) do
+ local newdep = pkgprefix .. "-" .. dep
+ newdeps[newdep] = opts
+ end
+ obj["deps"] = newdeps
+end
+
+-- Add comment and desc suffix.
+add_suffixes(obj)
+
+-- Write the output file.
local f,err = io.open(arg[#arg], "w")
if not f then
io.stderr:write(arg[0] .. ": fail to open("..arg[#arg].."): ".. err)
os.exit(1)
end
-local obj = parser:get_object()
+
f:write(ucl.to_format(obj, 'ucl', true))
f:close()
diff --git a/release/packages/generate-ucl.sh b/release/packages/generate-ucl.sh
index b7d7bad35023..3078185a3c4e 100755
--- a/release/packages/generate-ucl.sh
+++ b/release/packages/generate-ucl.sh
@@ -3,8 +3,8 @@
#
main() {
- desc=
- comment=
+ outname=""
+ origname=""
debug=
uclsource=
while getopts "do:s:u:" arg; do
@@ -31,73 +31,26 @@ main() {
shift $(( ${OPTIND} - 1 ))
case "${outname}" in
- bootloader)
- pkgdeps=""
- ;;
- certctl)
- pkgdeps="caroot openssl"
- ;;
- clang)
- pkgdeps="lld libcompiler_rt-dev"
- ;;
- periodic)
- pkgdeps="cron"
- ;;
- rcmds)
- # the RPC daemons require rpcbind
- pkgdeps="utilities"
- ;;
-
- # -dev packages that have no corresponding non-dev package
- # as a dependency.
- libcompat-dev|libcompiler_rt-dev|liby-dev)
- outname=${outname%%-dev}
- _descr="Development Files"
- ;;
- libcompat-lib32_dev|libcompiler_rt-lib32_dev|liby-lib32_dev)
- outname=${outname%%-lib32_dev}
- _descr="32-bit Libraries, Development Files"
- ;;
- libcompat-man|libelftc-man)
- outname=${outname%%-man}
- _descr="Manual Pages"
+ *-dev)
+ outname="${outname%%-dev}"
;;
- utilities)
- uclfile="${uclfile}"
+ *-dbg)
+ outname="${outname%%-dbg}"
;;
- runtime)
- outname="runtime"
- _descr="$(make -C ${srctree}/release/packages -f Makefile.package -V ${outname}_DESCR)"
+ *-dev-lib32)
+ outname="${outname%%-dev-lib32}"
;;
- *-lib32_dev)
- outname="${outname%%-lib32_dev}"
- _descr="32-bit Libraries, Development Files"
- pkgdeps="${outname}"
+ *-dbg-lib32)
+ outname="${outname%%-dbg-lib32}"
;;
- *-lib32_dbg)
- outname="${outname%%-lib32_dbg}"
- _descr="32-bit Libraries, Debugging Symbols"
- pkgdeps="${outname}"
+ *-man-lib32)
+ outname="${outname%%-man-lib32}"
;;
*-lib32)
outname="${outname%%-lib32}"
- _descr="32-bit Libraries"
- pkgdeps="${outname}"
- ;;
- *-dev)
- outname="${outname%%-dev}"
- _descr="Development Files"
- pkgdeps="${outname}"
- ;;
- *-dbg)
- outname="${outname%%-dbg}"
- _descr="Debugging Symbols"
- pkgdeps="${outname}"
;;
*-man)
outname="${outname%%-man}"
- _descr="Manual Pages"
- pkgdeps="${outname}"
;;
${origname})
;;
@@ -107,22 +60,16 @@ main() {
;;
esac
- desc="$(make -C ${srctree}/release/packages -f Makefile.package -V ${outname}_DESC)"
- comment="$(make -C ${srctree}/release/packages -f Makefile.package -V ${outname}_COMMENT)"
-
uclsource="${srctree}/release/packages/template.ucl"
if [ -n "${debug}" ]; then
echo ""
echo "==============================================================="
echo "DEBUG:"
- echo "_descr=${_descr}"
echo "outname=${outname}"
echo "origname=${origname}"
echo "srctree=${srctree}"
echo "uclfile=${uclfile}"
- echo "desc=${desc}"
- echo "comment=${comment}"
echo "vital=${vital}"
echo "cp ${uclsource} -> ${uclfile}"
echo "==============================================================="
@@ -131,38 +78,17 @@ main() {
echo ""
fi
- [ -z "${comment}" ] && comment="${outname} package"
- [ -n "${_descr}" ] && comment="${comment} (${_descr})"
- [ -z "${desc}" ] && desc="${outname} package"
-
- cp "${uclsource}" "${uclfile}"
- if [ -n "${pkgdeps}" ]; then
- echo 'deps: {' >> ${uclfile}
- for dep in ${pkgdeps}; do
- cat <<EOF >> ${uclfile}
- ${PKG_NAME_PREFIX}-${dep}: {
- origin: "base",
- version: "${PKG_VERSION}"
- }
-EOF
- done
- echo '}' >> ${uclfile}
- fi
cap_arg="$( make -f ${srctree}/share/mk/bsd.endian.mk -VCAP_MKDB_ENDIAN )"
${srctree}/release/packages/generate-ucl.lua \
VERSION "${PKG_VERSION}" \
PKGNAME "${origname}" \
PKGGENNAME "${outname}" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
- COMMENT "${comment}" \
- DESC "${desc}" \
CAP_MKDB_ENDIAN "${cap_arg}" \
PKG_WWW "${PKG_WWW}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
- UCLFILES "${srctree}/release/packages/" \
- ${uclfile} ${uclfile}
-
- return 0
+ UCLFILES "${srctree}/release/packages/ucl" \
+ ${uclsource} ${uclfile}
}
main "${@}"
diff --git a/release/packages/lld-all.ucl b/release/packages/lld-all.ucl
deleted file mode 100644
index 41a697ebe53d..000000000000
--- a/release/packages/lld-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ NCSA ]
diff --git a/release/packages/lldb-all.ucl b/release/packages/lldb-all.ucl
deleted file mode 100644
index 41a697ebe53d..000000000000
--- a/release/packages/lldb-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ NCSA ]
diff --git a/release/packages/ssh-all.ucl b/release/packages/ssh-all.ucl
deleted file mode 100644
index 4f78d80fa68e..000000000000
--- a/release/packages/ssh-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ ISCL ]
diff --git a/release/packages/template.ucl b/release/packages/template.ucl
index a65f58868118..faa48effe1ad 100644
--- a/release/packages/template.ucl
+++ b/release/packages/template.ucl
@@ -4,7 +4,7 @@
name = "${PKG_NAME_PREFIX}-${PKGNAME}"
origin = "base"
version = "${VERSION}"
-comment = "${COMMENT}"
+comment = "${PKGNAME} package"
categories = [ base ]
maintainer = "${PKG_MAINTAINER}"
www = "${PKG_WWW}"
@@ -12,8 +12,8 @@ prefix = "/"
licenselogic = "single"
licenses = [ BSD2CLAUSE ]
desc = <<EOD
-${DESC}
+${PKGNAME} package
EOD
-.include(try=true,duplicate=rewrite) "${UCLFILES}/${PKGGENNAME}-all.ucl"
+.include(try=false,duplicate=rewrite) "${UCLFILES}/${PKGGENNAME}-all.ucl"
.include(try=true,duplicate=rewrite) "${UCLFILES}/${PKGNAME}.ucl"
.include(try=true,duplicate=rewrite) "${UCLFILES}/${FORCEINCLUDE}.ucl"
diff --git a/release/packages/ucl/acct-all.ucl b/release/packages/ucl/acct-all.ucl
new file mode 100644
index 000000000000..ac4bd8868511
--- /dev/null
+++ b/release/packages/ucl/acct-all.ucl
@@ -0,0 +1,4 @@
+comment = "System Accounting Utilities"
+desc = <<EOD
+System Accounting Utilities
+EOD
diff --git a/release/packages/ucl/acpi-all.ucl b/release/packages/ucl/acpi-all.ucl
new file mode 100644
index 000000000000..70ea39fc3862
--- /dev/null
+++ b/release/packages/ucl/acpi-all.ucl
@@ -0,0 +1,4 @@
+comment = "ACPI Utilities"
+desc = <<EOD
+ACPI Utilities
+EOD
diff --git a/release/packages/ucl/amd-all.ucl b/release/packages/ucl/amd-all.ucl
new file mode 100644
index 000000000000..e2bc7cfc1b2a
--- /dev/null
+++ b/release/packages/ucl/amd-all.ucl
@@ -0,0 +1,4 @@
+comment = "AMD Utilities"
+desc = <<EOD
+AMD Utilities
+EOD
diff --git a/release/packages/ucl/apm-all.ucl b/release/packages/ucl/apm-all.ucl
new file mode 100644
index 000000000000..bf1b40000805
--- /dev/null
+++ b/release/packages/ucl/apm-all.ucl
@@ -0,0 +1,4 @@
+comment = "APM Utilities"
+desc = <<EOD
+APM Utilities
+EOD
diff --git a/release/packages/ucl/at-all.ucl b/release/packages/ucl/at-all.ucl
new file mode 100644
index 000000000000..c15642737b36
--- /dev/null
+++ b/release/packages/ucl/at-all.ucl
@@ -0,0 +1,4 @@
+comment = "AT Utilities"
+desc = <<EOD
+AT Utilities
+EOD
diff --git a/release/packages/ucl/audit-all.ucl b/release/packages/ucl/audit-all.ucl
new file mode 100644
index 000000000000..e0f3d4bf1675
--- /dev/null
+++ b/release/packages/ucl/audit-all.ucl
@@ -0,0 +1,4 @@
+comment = "OpenBSM auditing utilities"
+desc = <<EOD
+OpenBSM auditing utilities
+EOD
diff --git a/release/packages/ucl/autofs-all.ucl b/release/packages/ucl/autofs-all.ucl
new file mode 100644
index 000000000000..0e3e8d2336ca
--- /dev/null
+++ b/release/packages/ucl/autofs-all.ucl
@@ -0,0 +1,4 @@
+comment = "Autofs Utilities"
+desc = <<EOD
+Autofs Utilities
+EOD
diff --git a/release/packages/ucl/bhyve-all.ucl b/release/packages/ucl/bhyve-all.ucl
new file mode 100644
index 000000000000..2b20ca9a716f
--- /dev/null
+++ b/release/packages/ucl/bhyve-all.ucl
@@ -0,0 +1,4 @@
+comment = "Bhyve Utilities"
+desc = <<EOD
+Bhyve Utilities
+EOD
diff --git a/release/packages/ucl/blocklist-all.ucl b/release/packages/ucl/blocklist-all.ucl
new file mode 100644
index 000000000000..03330a417af9
--- /dev/null
+++ b/release/packages/ucl/blocklist-all.ucl
@@ -0,0 +1,4 @@
+comment = "Blocklist Utilities"
+desc = <<EOD
+Blocklist Utilities
+EOD
diff --git a/release/packages/ucl/bluetooth-all.ucl b/release/packages/ucl/bluetooth-all.ucl
new file mode 100644
index 000000000000..c139d9056a14
--- /dev/null
+++ b/release/packages/ucl/bluetooth-all.ucl
@@ -0,0 +1,4 @@
+comment = "Bluetooth Utilities"
+desc = <<EOD
+Bluetooth Utilities
+EOD
diff --git a/release/packages/ucl/bootloader-all.ucl b/release/packages/ucl/bootloader-all.ucl
new file mode 100644
index 000000000000..c5690e85c7ba
--- /dev/null
+++ b/release/packages/ucl/bootloader-all.ucl
@@ -0,0 +1,4 @@
+comment = "Bootloader"
+desc = <<EOD
+Bootloader and configuration files
+EOD
diff --git a/release/packages/ucl/bsdinstall-all.ucl b/release/packages/ucl/bsdinstall-all.ucl
new file mode 100644
index 000000000000..4c4586dcc702
--- /dev/null
+++ b/release/packages/ucl/bsdinstall-all.ucl
@@ -0,0 +1,4 @@
+comment = "BSDInstall Utilities"
+desc = <<EOD
+BSDInstall Utilities
+EOD
diff --git a/release/packages/ucl/bsnmp-all.ucl b/release/packages/ucl/bsnmp-all.ucl
new file mode 100644
index 000000000000..9b80310c0617
--- /dev/null
+++ b/release/packages/ucl/bsnmp-all.ucl
@@ -0,0 +1,4 @@
+comment = "BSNMP Utilities"
+desc = <<EOD
+BSNMP Utilities
+EOD
diff --git a/release/packages/ucl/caroot-all.ucl b/release/packages/ucl/caroot-all.ucl
new file mode 100644
index 000000000000..151c1f18ae39
--- /dev/null
+++ b/release/packages/ucl/caroot-all.ucl
@@ -0,0 +1,4 @@
+comment = "SSL Certificates"
+desc = <<EOD
+SSL Certificates
+EOD
diff --git a/release/packages/ucl/caroot.ucl b/release/packages/ucl/caroot.ucl
new file mode 100644
index 000000000000..4d2b52d300fc
--- /dev/null
+++ b/release/packages/ucl/caroot.ucl
@@ -0,0 +1,10 @@
+deps {
+ "certctl": {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
+scripts: {
+ post-install = "/usr/sbin/certctl -D${PKG_ROOTDIR}/ rehash"
+ post-uninstall = "/usr/sbin/certctl -D${PKG_ROOTDIR}/ rehash"
+}
diff --git a/release/packages/ucl/ccdconfig-all.ucl b/release/packages/ucl/ccdconfig-all.ucl
new file mode 100644
index 000000000000..76ba9d64db61
--- /dev/null
+++ b/release/packages/ucl/ccdconfig-all.ucl
@@ -0,0 +1,5 @@
+comment = "Concatenated disk driver (ccd) configuration utility"
+desc = <<EOD
+ccdconfig(8) is used to configure the concatenated disk driver, ccd(4).
+ccdconfig(8) may also be started on boot using the "ccd" rc(8) service.
+EOD
diff --git a/release/packages/ucl/certctl-all.ucl b/release/packages/ucl/certctl-all.ucl
new file mode 100644
index 000000000000..b4bc5ae261c5
--- /dev/null
+++ b/release/packages/ucl/certctl-all.ucl
@@ -0,0 +1,4 @@
+comment = "SSL Certificate Utility"
+desc = <<EOD
+SSL Certificate Utility
+EOD
diff --git a/release/packages/ucl/certctl.ucl b/release/packages/ucl/certctl.ucl
new file mode 100644
index 000000000000..7f7adec83159
--- /dev/null
+++ b/release/packages/ucl/certctl.ucl
@@ -0,0 +1,6 @@
+deps {
+ "openssl": {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
diff --git a/release/packages/ucl/clang-all.ucl b/release/packages/ucl/clang-all.ucl
new file mode 100644
index 000000000000..3f79f0acb229
--- /dev/null
+++ b/release/packages/ucl/clang-all.ucl
@@ -0,0 +1,5 @@
+comment = "Clang Utilities"
+desc = <<EOD
+Clang Utilities
+EOD
+licenses = [ NCSA ]
diff --git a/release/packages/ucl/clang.ucl b/release/packages/ucl/clang.ucl
new file mode 100644
index 000000000000..956b769a1ee7
--- /dev/null
+++ b/release/packages/ucl/clang.ucl
@@ -0,0 +1,11 @@
+deps {
+ "lld" {
+ version = "${VERSION}"
+ origin = "base"
+ }
+
+ "libcompiler_rt-dev" {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
diff --git a/release/packages/ucl/clibs-all.ucl b/release/packages/ucl/clibs-all.ucl
new file mode 100644
index 000000000000..69ae018d4d1f
--- /dev/null
+++ b/release/packages/ucl/clibs-all.ucl
@@ -0,0 +1,4 @@
+comment = "Core C Libraries"
+desc = <<EOD
+Core C Libraries
+EOD
diff --git a/release/packages/clibs.ucl b/release/packages/ucl/clibs.ucl
index 093fbb60248a..093fbb60248a 100644
--- a/release/packages/clibs.ucl
+++ b/release/packages/ucl/clibs.ucl
diff --git a/release/packages/ucl/console-tools-all.ucl b/release/packages/ucl/console-tools-all.ucl
new file mode 100644
index 000000000000..53f31b2a9937
--- /dev/null
+++ b/release/packages/ucl/console-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "Console Utilities"
+desc = <<EOD
+Console Utilities
+EOD
diff --git a/release/packages/ucl/cron-all.ucl b/release/packages/ucl/cron-all.ucl
new file mode 100644
index 000000000000..d9edf6bfde52
--- /dev/null
+++ b/release/packages/ucl/cron-all.ucl
@@ -0,0 +1,4 @@
+comment = "cron(8) and crontab(1)"
+desc = <<EOD
+cron(8) and crontab(1)
+EOD
diff --git a/release/packages/ucl/csh-all.ucl b/release/packages/ucl/csh-all.ucl
new file mode 100644
index 000000000000..df4dc71f8dd5
--- /dev/null
+++ b/release/packages/ucl/csh-all.ucl
@@ -0,0 +1,4 @@
+comment = "C Shell"
+desc = <<EOD
+C Shell
+EOD
diff --git a/release/packages/ucl/ctf-tools-all.ucl b/release/packages/ucl/ctf-tools-all.ucl
new file mode 100644
index 000000000000..38ca769f6109
--- /dev/null
+++ b/release/packages/ucl/ctf-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "CTF Utilities"
+desc = <<EOD
+CTF Utilities
+EOD
diff --git a/release/packages/ucl/ctl-all.ucl b/release/packages/ucl/ctl-all.ucl
new file mode 100644
index 000000000000..d24ffabea1a0
--- /dev/null
+++ b/release/packages/ucl/ctl-all.ucl
@@ -0,0 +1,4 @@
+comment = "CAM Target Layer"
+desc = <<EOD
+The CAM Target Layer allows CAM to export storage targets, e.g. via iSCSI.
+EOD
diff --git a/release/packages/ucl/cxgbe-tools-all.ucl b/release/packages/ucl/cxgbe-tools-all.ucl
new file mode 100644
index 000000000000..e2f6132f7ef9
--- /dev/null
+++ b/release/packages/ucl/cxgbe-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "Chelsio cxbge Utilities"
+desc = <<EOD
+Chelsio cxbge Utilities
+EOD
diff --git a/release/packages/ucl/devd-all.ucl b/release/packages/ucl/devd-all.ucl
new file mode 100644
index 000000000000..dc7d162a1930
--- /dev/null
+++ b/release/packages/ucl/devd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Devd Utility and scripts"
+desc = <<EOD
+Devd Utility and scripts
+EOD
diff --git a/release/packages/ucl/devmatch-all.ucl b/release/packages/ucl/devmatch-all.ucl
new file mode 100644
index 000000000000..02dc903fd422
--- /dev/null
+++ b/release/packages/ucl/devmatch-all.ucl
@@ -0,0 +1,4 @@
+comment = "Devmatch Utility"
+desc = <<EOD
+Devmatch Utility
+EOD
diff --git a/release/packages/ucl/dhclient-all.ucl b/release/packages/ucl/dhclient-all.ucl
new file mode 100644
index 000000000000..6785366aea5e
--- /dev/null
+++ b/release/packages/ucl/dhclient-all.ucl
@@ -0,0 +1,4 @@
+comment = "DHCP Client"
+desc = <<EOD
+DHCP Client
+EOD
diff --git a/release/packages/ucl/dma-all.ucl b/release/packages/ucl/dma-all.ucl
new file mode 100644
index 000000000000..e8824acf7a36
--- /dev/null
+++ b/release/packages/ucl/dma-all.ucl
@@ -0,0 +1,4 @@
+comment = "DMA Mail Agent Utilities"
+desc = <<EOD
+DMA Mail Agent Utilities
+EOD
diff --git a/release/packages/ucl/docs-all.ucl b/release/packages/ucl/docs-all.ucl
new file mode 100644
index 000000000000..7159d3f8f4ec
--- /dev/null
+++ b/release/packages/ucl/docs-all.ucl
@@ -0,0 +1,4 @@
+comment = "Documentation"
+desc = <<EOD
+Documentation
+EOD
diff --git a/release/packages/ucl/dtb-all.ucl b/release/packages/ucl/dtb-all.ucl
new file mode 100644
index 000000000000..cc5c1c60f062
--- /dev/null
+++ b/release/packages/ucl/dtb-all.ucl
@@ -0,0 +1,4 @@
+comment = "FreeBSD Devicetree Blobs"
+desc = <<EOD
+FreeBSD Devicetree Blobs
+EOD
diff --git a/release/packages/ucl/dtrace-all.ucl b/release/packages/ucl/dtrace-all.ucl
new file mode 100644
index 000000000000..fb36816123c5
--- /dev/null
+++ b/release/packages/ucl/dtrace-all.ucl
@@ -0,0 +1,4 @@
+comment = "Dtrace Utilities"
+desc = <<EOD
+Dtrace Utilities
+EOD
diff --git a/release/packages/ucl/dwatch-all.ucl b/release/packages/ucl/dwatch-all.ucl
new file mode 100644
index 000000000000..5f7e0fb764ce
--- /dev/null
+++ b/release/packages/ucl/dwatch-all.ucl
@@ -0,0 +1,4 @@
+comment = "Dwatch Utilities"
+desc = <<EOD
+Dwatch Utilities
+EOD
diff --git a/release/packages/ucl/ee-all.ucl b/release/packages/ucl/ee-all.ucl
new file mode 100644
index 000000000000..c003942ad3a9
--- /dev/null
+++ b/release/packages/ucl/ee-all.ucl
@@ -0,0 +1,4 @@
+comment = "Easy Editor Utilities"
+desc = <<EOD
+Easy Editor Utilities
+EOD
diff --git a/release/packages/ucl/efi-tools-all.ucl b/release/packages/ucl/efi-tools-all.ucl
new file mode 100644
index 000000000000..51d5e12189dd
--- /dev/null
+++ b/release/packages/ucl/efi-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "UEFI Utilities"
+desc = <<EOD
+UEFI Utilities
+EOD
diff --git a/release/packages/ucl/examples-all.ucl b/release/packages/ucl/examples-all.ucl
new file mode 100644
index 000000000000..93f0aee16187
--- /dev/null
+++ b/release/packages/ucl/examples-all.ucl
@@ -0,0 +1,4 @@
+comment = "Examples in /usr/share/examples"
+desc = <<EOD
+Examples in /usr/share/examples
+EOD
diff --git a/release/packages/ucl/fd-all.ucl b/release/packages/ucl/fd-all.ucl
new file mode 100644
index 000000000000..7092449174e3
--- /dev/null
+++ b/release/packages/ucl/fd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Floppy disk support"
+desc = <<EOD
+Utilities for formatting and managing floppy disks supported by fdc(4).
+EOD
diff --git a/release/packages/ucl/fetch-all.ucl b/release/packages/ucl/fetch-all.ucl
new file mode 100644
index 000000000000..f9a3e03e6fa4
--- /dev/null
+++ b/release/packages/ucl/fetch-all.ucl
@@ -0,0 +1,4 @@
+comment = "Fetch Utility"
+desc = <<EOD
+Fetch Utility
+EOD
diff --git a/release/packages/ucl/firmware-iwm-all.ucl b/release/packages/ucl/firmware-iwm-all.ucl
new file mode 100644
index 000000000000..6fec27c15351
--- /dev/null
+++ b/release/packages/ucl/firmware-iwm-all.ucl
@@ -0,0 +1,4 @@
+comment = "iwm(4) firmwares"
+desc = <<EOD
+iwm(4) firmwares
+EOD
diff --git a/release/packages/ucl/ftp-all.ucl b/release/packages/ucl/ftp-all.ucl
new file mode 100644
index 000000000000..6275bc46e657
--- /dev/null
+++ b/release/packages/ucl/ftp-all.ucl
@@ -0,0 +1,4 @@
+comment = "FTP Utilities"
+desc = <<EOD
+FTP Utilities
+EOD
diff --git a/release/packages/ucl/ftpd-all.ucl b/release/packages/ucl/ftpd-all.ucl
new file mode 100644
index 000000000000..cbaa078123d5
--- /dev/null
+++ b/release/packages/ucl/ftpd-all.ucl
@@ -0,0 +1,4 @@
+comment = "FTP Daemon"
+desc = <<EOD
+FTP Daemon
+EOD
diff --git a/release/packages/ucl/fwget-all.ucl b/release/packages/ucl/fwget-all.ucl
new file mode 100644
index 000000000000..7a6f9dff5cc9
--- /dev/null
+++ b/release/packages/ucl/fwget-all.ucl
@@ -0,0 +1,4 @@
+comment = "FWGET Utility"
+desc = <<EOD
+FWGET Utility
+EOD
diff --git a/release/packages/ucl/games-all.ucl b/release/packages/ucl/games-all.ucl
new file mode 100644
index 000000000000..747638fe6a8f
--- /dev/null
+++ b/release/packages/ucl/games-all.ucl
@@ -0,0 +1,4 @@
+comment = "Games"
+desc = <<EOD
+Games
+EOD
diff --git a/release/packages/ucl/geom-all.ucl b/release/packages/ucl/geom-all.ucl
new file mode 100644
index 000000000000..6d80b4458f64
--- /dev/null
+++ b/release/packages/ucl/geom-all.ucl
@@ -0,0 +1,4 @@
+comment = "GEOM Utilitites"
+desc = <<EOD
+GEOM Utilitites
+EOD
diff --git a/release/packages/ucl/ggate-all.ucl b/release/packages/ucl/ggate-all.ucl
new file mode 100644
index 000000000000..0d0b984b440e
--- /dev/null
+++ b/release/packages/ucl/ggate-all.ucl
@@ -0,0 +1,4 @@
+comment = "GEOM Gate Utilities"
+desc = <<EOD
+GEOM Gate Utilities
+EOD
diff --git a/release/packages/ucl/hast-all.ucl b/release/packages/ucl/hast-all.ucl
new file mode 100644
index 000000000000..b2441ddb6866
--- /dev/null
+++ b/release/packages/ucl/hast-all.ucl
@@ -0,0 +1,4 @@
+comment = "Highly Available Storage daemon"
+desc = <<EOD
+Highly Available Storage daemon
+EOD
diff --git a/release/packages/ucl/hostapd-all.ucl b/release/packages/ucl/hostapd-all.ucl
new file mode 100644
index 000000000000..c2e0d0c0bd11
--- /dev/null
+++ b/release/packages/ucl/hostapd-all.ucl
@@ -0,0 +1,4 @@
+comment = "802.11 Access Point Daemon an Utilities"
+desc = <<EOD
+802.11 Access Point Daemon an Utilities
+EOD
diff --git a/release/packages/ucl/hyperv-tools-all.ucl b/release/packages/ucl/hyperv-tools-all.ucl
new file mode 100644
index 000000000000..e16fd5b4b053
--- /dev/null
+++ b/release/packages/ucl/hyperv-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "Microsoft HyperV Utilities"
+desc = <<EOD
+Microsoft HyperV Utilities
+EOD
diff --git a/release/packages/ucl/inetd-all.ucl b/release/packages/ucl/inetd-all.ucl
new file mode 100644
index 000000000000..731769bdc399
--- /dev/null
+++ b/release/packages/ucl/inetd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Internet super-server"
+desc = <<EOD
+Internet super-server
+EOD
diff --git a/release/packages/ucl/ipf-all.ucl b/release/packages/ucl/ipf-all.ucl
new file mode 100644
index 000000000000..bd1bec5232de
--- /dev/null
+++ b/release/packages/ucl/ipf-all.ucl
@@ -0,0 +1,4 @@
+comment = "IP Filter (ipf) packet filter management tools"
+desc = <<EOD
+IP Filter (ipf) is a stateful packet filter for IPv4 and IPv6 networks.
+EOD
diff --git a/release/packages/ucl/ipfw-all.ucl b/release/packages/ucl/ipfw-all.ucl
new file mode 100644
index 000000000000..0884d48aa071
--- /dev/null
+++ b/release/packages/ucl/ipfw-all.ucl
@@ -0,0 +1,4 @@
+comment = "ipfw (IP firewall) management utilities"
+desc = <<EOD
+ipfw provides stateful packet filtering, NAT and traffic shaping for IP traffic.
+EOD
diff --git a/release/packages/ucl/iscsi-all.ucl b/release/packages/ucl/iscsi-all.ucl
new file mode 100644
index 000000000000..e81961cb40a5
--- /dev/null
+++ b/release/packages/ucl/iscsi-all.ucl
@@ -0,0 +1,6 @@
+comment = "iSCSI target, initiator, and management tools"
+desc = <<EOD
+iSCSI allows a block device to be exported from one system to another over a
+network. This package provides the iSCSI target and initiator and associated
+management tools.
+EOD
diff --git a/release/packages/ucl/jail-all.ucl b/release/packages/ucl/jail-all.ucl
new file mode 100644
index 000000000000..da844b500ad5
--- /dev/null
+++ b/release/packages/ucl/jail-all.ucl
@@ -0,0 +1,4 @@
+comment = "Jail Utilities"
+desc = <<EOD
+Jail Utilities
+EOD
diff --git a/release/packages/ucl/kerberos-all.ucl b/release/packages/ucl/kerberos-all.ucl
new file mode 100644
index 000000000000..6fb7f059296b
--- /dev/null
+++ b/release/packages/ucl/kerberos-all.ucl
@@ -0,0 +1,4 @@
+comment = "Kerberos Utilities"
+desc = <<EOD
+Kerberos Utilities
+EOD
diff --git a/release/packages/ucl/kerberos-lib-all.ucl b/release/packages/ucl/kerberos-lib-all.ucl
new file mode 100644
index 000000000000..ab769ee16f96
--- /dev/null
+++ b/release/packages/ucl/kerberos-lib-all.ucl
@@ -0,0 +1,4 @@
+comment = "Kerberos Libraries"
+desc = <<EOD
+Kerberos Libraries
+EOD
diff --git a/release/packages/ucl/kernel-all.ucl b/release/packages/ucl/kernel-all.ucl
new file mode 100644
index 000000000000..31671602a947
--- /dev/null
+++ b/release/packages/ucl/kernel-all.ucl
@@ -0,0 +1,4 @@
+comment = "FreeBSD ${KERNEL_NAME} Kernel ${KERNEL_FLAVOR}"
+desc = <<EOD
+FreeBSD ${KERNEL_NAME} Kernel ${KERNEL_FLAVOR}
+EOD
diff --git a/release/packages/ucl/krb5-all.ucl b/release/packages/ucl/krb5-all.ucl
new file mode 100644
index 000000000000..e269aabe1e85
--- /dev/null
+++ b/release/packages/ucl/krb5-all.ucl
@@ -0,0 +1,4 @@
+comment = "KRB5 Utilities"
+desc = <<EOD
+KRB5 Utilities
+EOD
diff --git a/release/packages/ucl/krb5-lib-all.ucl b/release/packages/ucl/krb5-lib-all.ucl
new file mode 100644
index 000000000000..854b8a9f85df
--- /dev/null
+++ b/release/packages/ucl/krb5-lib-all.ucl
@@ -0,0 +1,4 @@
+comment = "KRB5 Libraries"
+desc = <<EOD
+KRB5 Libraries
+EOD
diff --git a/release/packages/ucl/lib9p-all.ucl b/release/packages/ucl/lib9p-all.ucl
new file mode 100644
index 000000000000..76a5b8de4596
--- /dev/null
+++ b/release/packages/ucl/lib9p-all.ucl
@@ -0,0 +1,5 @@
+comment = "9P network protocol library"
+desc = <<EOD
+lib9p implements the server side of the 9p2000, 9p2000.u and 9p2000.L revisions
+of the 9P protocol
+EOD
diff --git a/release/packages/ucl/libarchive-all.ucl b/release/packages/ucl/libarchive-all.ucl
new file mode 100644
index 000000000000..9b98404b3235
--- /dev/null
+++ b/release/packages/ucl/libarchive-all.ucl
@@ -0,0 +1,4 @@
+comment = "Archive handling library"
+desc = <<EOD
+libarchive allows applications to read and write archive files of various types.
+EOD
diff --git a/release/packages/ucl/libbegemot-all.ucl b/release/packages/ucl/libbegemot-all.ucl
new file mode 100644
index 000000000000..7a2f19df8e0e
--- /dev/null
+++ b/release/packages/ucl/libbegemot-all.ucl
@@ -0,0 +1,5 @@
+comment = "rpoll(3) interface for event-driven I/O"
+desc = <<EOD
+libbegemot provides rpoll(3), a simplified interface for handling event-driven
+I/O programming.
+EOD
diff --git a/release/packages/ucl/libblocksruntime-all.ucl b/release/packages/ucl/libblocksruntime-all.ucl
new file mode 100644
index 000000000000..818c32174a6c
--- /dev/null
+++ b/release/packages/ucl/libblocksruntime-all.ucl
@@ -0,0 +1,4 @@
+comment = "LLVM BlocksRuntime library"
+desc = <<EOD
+The LLVM libBlocksRuntime library.
+EOD
diff --git a/release/packages/ucl/libbsdstat-all.ucl b/release/packages/ucl/libbsdstat-all.ucl
new file mode 100644
index 000000000000..4db0059827a0
--- /dev/null
+++ b/release/packages/ucl/libbsdstat-all.ucl
@@ -0,0 +1,5 @@
+comment = "Periodic statistics library"
+desc = <<EOD
+libbsdstat is a library for managing and display periodically collected
+statistics.
+EOD
diff --git a/release/packages/ucl/libbsm-all.ucl b/release/packages/ucl/libbsm-all.ucl
new file mode 100644
index 000000000000..0a60ada09075
--- /dev/null
+++ b/release/packages/ucl/libbsm-all.ucl
@@ -0,0 +1,6 @@
+comment = "Basic Security Module (BSM) audit library"
+desc = <<EOD
+The libbsm library routines provide an interface to BSM audit record streams,
+allowing both the parsing of existing audit streams, as well as the creation of
+new audit records and streams.
+EOD
diff --git a/release/packages/ucl/libbz2-all.ucl b/release/packages/ucl/libbz2-all.ucl
new file mode 100644
index 000000000000..c8141bcb1d11
--- /dev/null
+++ b/release/packages/ucl/libbz2-all.ucl
@@ -0,0 +1,5 @@
+comment = "bzip2 compression library"
+desc = <<EOD
+libbz2 allows applications to compress and decompress data using the bzip2
+compression algorithm.
+EOD
diff --git a/release/packages/ucl/libcasper-all.ucl b/release/packages/ucl/libcasper-all.ucl
new file mode 100644
index 000000000000..b25a82a32050
--- /dev/null
+++ b/release/packages/ucl/libcasper-all.ucl
@@ -0,0 +1,5 @@
+comment = "Casper library"
+desc = <<EOD
+The libcasper library provides for the control of application capabilities
+through the casper process.
+EOD
diff --git a/release/packages/ucl/libcompat-all.ucl b/release/packages/ucl/libcompat-all.ucl
new file mode 100644
index 000000000000..a562f155dc5f
--- /dev/null
+++ b/release/packages/ucl/libcompat-all.ucl
@@ -0,0 +1,4 @@
+comment = "Compatibility library"
+desc = <<EOD
+libcompat provides implementations of some obsolete library functions.
+EOD
diff --git a/release/packages/ucl/libcompiler_rt-all.ucl b/release/packages/ucl/libcompiler_rt-all.ucl
new file mode 100644
index 000000000000..f21e629ac88c
--- /dev/null
+++ b/release/packages/ucl/libcompiler_rt-all.ucl
@@ -0,0 +1,4 @@
+comment = "LLVM compiler_rt library"
+desc = <<EOD
+The libcompiler_rt library from LLVM.
+EOD
diff --git a/release/packages/ucl/libcuse-all.ucl b/release/packages/ucl/libcuse-all.ucl
new file mode 100644
index 000000000000..de972d4b8d3a
--- /dev/null
+++ b/release/packages/ucl/libcuse-all.ucl
@@ -0,0 +1,5 @@
+comment = "Userland character device library"
+desc = <<EOD
+The libcuse library contains functions to create a character device in
+userspace.
+EOD
diff --git a/release/packages/ucl/libdwarf-all.ucl b/release/packages/ucl/libdwarf-all.ucl
new file mode 100644
index 000000000000..4226dbfee592
--- /dev/null
+++ b/release/packages/ucl/libdwarf-all.ucl
@@ -0,0 +1,6 @@
+comment = "DWARF access library"
+desc = <<EOD
+The DWARF Access Library provides functions that allow an application to read
+and write debugging information in object files. The format of debugging
+information accessible through this API is defined by the DWARF standard.
+EOD
diff --git a/release/packages/ucl/libevent1-all.ucl b/release/packages/ucl/libevent1-all.ucl
new file mode 100644
index 000000000000..511e077233d2
--- /dev/null
+++ b/release/packages/ucl/libevent1-all.ucl
@@ -0,0 +1,4 @@
+comment = "Private libevent1 library"
+desc = <<EOD
+A private library used by applications in the base system.
+EOD
diff --git a/release/packages/ucl/libexecinfo-all.ucl b/release/packages/ucl/libexecinfo-all.ucl
new file mode 100644
index 000000000000..8a0c110381be
--- /dev/null
+++ b/release/packages/ucl/libexecinfo-all.ucl
@@ -0,0 +1,5 @@
+comment = "NetBSD stack backtrace library"
+desc = <<EOD
+libexecinfo provides the backtrace(3) interface to allow an application to
+examine its current call stack.
+EOD
diff --git a/release/packages/ucl/libipt-all.ucl b/release/packages/ucl/libipt-all.ucl
new file mode 100644
index 000000000000..eb0ef6a32d40
--- /dev/null
+++ b/release/packages/ucl/libipt-all.ucl
@@ -0,0 +1,6 @@
+comment = "Intel(R) Processor Trace decoder library"
+desc = <<EOD
+The Intel Processor Trace (Intel PT) Decoder Library is Intel's reference
+implementation for decoding Intel PT. It can be used as a standalone library
+or it can be partially or fully integrated into your tool.
+EOD
diff --git a/release/packages/ucl/libldns-all.ucl b/release/packages/ucl/libldns-all.ucl
new file mode 100644
index 000000000000..55de2701bbb8
--- /dev/null
+++ b/release/packages/ucl/libldns-all.ucl
@@ -0,0 +1,6 @@
+comment="NLnet Labs LDNS library"
+desc = <<EOD
+The goal of ldns is to simplify DNS programming in C. ldns supports all
+low-level DNS and DNSSEC operations. It also defines a higher level API which
+allows a programmer to for instance create or sign packets.
+EOD
diff --git a/release/packages/ucl/liblzma-all.ucl b/release/packages/ucl/liblzma-all.ucl
new file mode 100644
index 000000000000..0b1bfcbcecc6
--- /dev/null
+++ b/release/packages/ucl/liblzma-all.ucl
@@ -0,0 +1,5 @@
+comment = "XZ LZMA library"
+desc = <<EOD
+liblzma allows applications to compress and decompress data using the XZ
+compression algorithm.
+EOD
diff --git a/release/packages/ucl/libmagic-all.ucl b/release/packages/ucl/libmagic-all.ucl
new file mode 100644
index 000000000000..2a29aacb260d
--- /dev/null
+++ b/release/packages/ucl/libmagic-all.ucl
@@ -0,0 +1,5 @@
+comment = "Magic number recognition library"
+desc = <<EOD
+libmagic allows an application to identity data using the magic(5) magic number
+database.
+EOD
diff --git a/release/packages/ucl/libopencsd-all.ucl b/release/packages/ucl/libopencsd-all.ucl
new file mode 100644
index 000000000000..af46292dceed
--- /dev/null
+++ b/release/packages/ucl/libopencsd-all.ucl
@@ -0,0 +1,5 @@
+comment = "ARM CoreSight Trace Decode Library"
+desc = <<EOD
+This library provides an API suitable for the decode of ARM CoreSight
+trace streams.
+EOD
diff --git a/release/packages/ucl/libpathconv-all.ucl b/release/packages/ucl/libpathconv-all.ucl
new file mode 100644
index 000000000000..872d34a24e6a
--- /dev/null
+++ b/release/packages/ucl/libpathconv-all.ucl
@@ -0,0 +1,5 @@
+comment = "Library for handling relative and absolute pathnames"
+desc = <<EOD
+libpathconv provides the abs2rel() and rel2abs() functions to convert between
+absolute and relative pathnames.
+EOD
diff --git a/release/packages/ucl/librpcsec_gss-all.ucl b/release/packages/ucl/librpcsec_gss-all.ucl
new file mode 100644
index 000000000000..67f481e9e9b5
--- /dev/null
+++ b/release/packages/ucl/librpcsec_gss-all.ucl
@@ -0,0 +1,5 @@
+comment = "RPC GSS-API authentication library"
+desc = <<EOD
+librpcsec_gss provides an API to allow applications to interact with the
+RPCSEC_GSS security mechanism.
+EOD
diff --git a/release/packages/ucl/librss-all.ucl b/release/packages/ucl/librss-all.ucl
new file mode 100644
index 000000000000..3c09025356a8
--- /dev/null
+++ b/release/packages/ucl/librss-all.ucl
@@ -0,0 +1,5 @@
+comment = "Receive-side scaling library"
+desc = <<EOD
+The librss library and the functions it provides are used for both fetching the
+system RSS configuration and interacting with RSS aware sockets.
+EOD
diff --git a/release/packages/ucl/libsdp-all.ucl b/release/packages/ucl/libsdp-all.ucl
new file mode 100644
index 000000000000..31f04e089470
--- /dev/null
+++ b/release/packages/ucl/libsdp-all.ucl
@@ -0,0 +1,5 @@
+comment = "Bluetooth Service Discovery Protocol library"
+desc = <<EOD
+libsdp allows applications to interact with the Bluetooth Service Discovery
+Protocol.
+EOD
diff --git a/release/packages/ucl/libsqlite3-all.ucl b/release/packages/ucl/libsqlite3-all.ucl
new file mode 100644
index 000000000000..55ac00863bf1
--- /dev/null
+++ b/release/packages/ucl/libsqlite3-all.ucl
@@ -0,0 +1,4 @@
+comment = "Private SQLite library"
+desc = <<EOD
+A private version of SQLite for use by applications in the base system.
+EOD
diff --git a/release/packages/ucl/libstdbuf-all.ucl b/release/packages/ucl/libstdbuf-all.ucl
new file mode 100644
index 000000000000..d85f2d3b70f2
--- /dev/null
+++ b/release/packages/ucl/libstdbuf-all.ucl
@@ -0,0 +1,6 @@
+comment = "Preloaded library to change standard streams initial buffering"
+desc = <<EOD
+The libstdbuf library is meant to be preloaded with the LD_PRELOAD environment
+variable to as to change the initial buffering of standard input, standard
+output and standard error streams.
+EOD
diff --git a/release/packages/ucl/libstdthreads-all.ucl b/release/packages/ucl/libstdthreads-all.ucl
new file mode 100644
index 000000000000..5af147ea5ca7
--- /dev/null
+++ b/release/packages/ucl/libstdthreads-all.ucl
@@ -0,0 +1,4 @@
+comment = "C11 threading library"
+desc = <<EOD
+libstdthreads provides the thread-control interface defined in the C99 standard.
+EOD
diff --git a/release/packages/ucl/libthread_db-all.ucl b/release/packages/ucl/libthread_db-all.ucl
new file mode 100644
index 000000000000..ba2164a3f211
--- /dev/null
+++ b/release/packages/ucl/libthread_db-all.ucl
@@ -0,0 +1,5 @@
+comment = "Library for interacting with threaded processes"
+desc = <<EOD
+libthread_db is used by the debugger to examine and interact with a
+multithreaded process being debugger.
+EOD
diff --git a/release/packages/ucl/libucl-all.ucl b/release/packages/ucl/libucl-all.ucl
new file mode 100644
index 000000000000..d04c2109df06
--- /dev/null
+++ b/release/packages/ucl/libucl-all.ucl
@@ -0,0 +1,5 @@
+comment = "Private Universal Configuration Library (UCL) library"
+desc = <<EOD
+A private library for reading and writing UCL files, for used by applications
+in the base system.
+EOD
diff --git a/release/packages/ucl/libufs-all.ucl b/release/packages/ucl/libufs-all.ucl
new file mode 100644
index 000000000000..d86a84bbd637
--- /dev/null
+++ b/release/packages/ucl/libufs-all.ucl
@@ -0,0 +1,8 @@
+comment = "Low-level access to UFS filesystems"
+desc = <<EOD
+The libufs library and the functions it provides are used for implementing
+utilities which need to access a UFS file system at a low level from userland.
+Facilities provided are used to implement utilities such as newfs(8) and
+dumpfs(8). The libufs library is designed to be simple, and to provide
+functions that are traditionally useful to have.
+EOD
diff --git a/release/packages/ucl/libvgl-all.ucl b/release/packages/ucl/libvgl-all.ucl
new file mode 100644
index 000000000000..fea63d807de0
--- /dev/null
+++ b/release/packages/ucl/libvgl-all.ucl
@@ -0,0 +1,13 @@
+comment = "Video Graphics Library"
+desc = <<EOD
+libvgl is a library that enables the programmer access to the graphics modes
+supported by the console driver (syscons). The library takes care of
+programming the actual video hardware, and provides a number of simple
+functions to do various graphic operations. There is also support for a mouse
+via the standard mouse system in FreeBSD, including the ability to
+transparently have a mouse pointer superimposed on the graphic image currently
+being worked on. The library takes care of screen switching by storing the
+current image in memory before switching to another virtual console, and
+restoring when the user switches back. This allows several graphic
+applications at once, but on different virtual consoles.
+EOD
diff --git a/release/packages/ucl/libvmmapi-all.ucl b/release/packages/ucl/libvmmapi-all.ucl
new file mode 100644
index 000000000000..976fb1bfce47
--- /dev/null
+++ b/release/packages/ucl/libvmmapi-all.ucl
@@ -0,0 +1,4 @@
+comment = "Front-end to vmm(4) virtualization driver"
+desc = <<EOD
+libvmmapi provides an interface for applications to access the vmm(4) driver.
+EOD
diff --git a/release/packages/ucl/liby-all.ucl b/release/packages/ucl/liby-all.ucl
new file mode 100644
index 000000000000..575aeda0a1ef
--- /dev/null
+++ b/release/packages/ucl/liby-all.ucl
@@ -0,0 +1,5 @@
+comment = "YACC library"
+desc = <<EOD
+liby provides default implementations of main() and yyerror() for use with
+applications which use yacc(1).
+EOD
diff --git a/release/packages/ucl/libyaml-all.ucl b/release/packages/ucl/libyaml-all.ucl
new file mode 100644
index 000000000000..f98a5a39362f
--- /dev/null
+++ b/release/packages/ucl/libyaml-all.ucl
@@ -0,0 +1,5 @@
+comment = "Private YAML library"
+desc = <<EOD
+The libprivateyaml library is used by the FreeBSD base system to parse YAML
+files. This library is not intended for use outside of the base system.
+EOD
diff --git a/release/packages/ucl/libzfs-all.ucl b/release/packages/ucl/libzfs-all.ucl
new file mode 100644
index 000000000000..bd53521f3aa0
--- /dev/null
+++ b/release/packages/ucl/libzfs-all.ucl
@@ -0,0 +1,5 @@
+comment = "ZFS filesystem library"
+desc = <<EOD
+libzfs allows applications to manage ZFS pools and filesystems. Several
+libraries which libzfs requires are also provided.
+EOD
diff --git a/release/packages/ucl/lld-all.ucl b/release/packages/ucl/lld-all.ucl
new file mode 100644
index 000000000000..03daf1b235e6
--- /dev/null
+++ b/release/packages/ucl/lld-all.ucl
@@ -0,0 +1,6 @@
+comment = "ELF linker from the LLVM project"
+desc = <<EOD
+ld.lld is the ELF linker provided by LLVM.
+EOD
+
+licenses = [ NCSA ]
diff --git a/release/packages/ucl/lldb-all.ucl b/release/packages/ucl/lldb-all.ucl
new file mode 100644
index 000000000000..da481c026981
--- /dev/null
+++ b/release/packages/ucl/lldb-all.ucl
@@ -0,0 +1,6 @@
+comment = "LLVM debugger"
+desc = <<EOD
+lldb is a source-level debugger from the LLVM project.
+EOD
+
+licenses = [ NCSA ]
diff --git a/release/packages/ucl/locales-all.ucl b/release/packages/ucl/locales-all.ucl
new file mode 100644
index 000000000000..6fc53ab10fca
--- /dev/null
+++ b/release/packages/ucl/locales-all.ucl
@@ -0,0 +1,4 @@
+comment = "Locale definitions"
+desc = <<EOD
+Provides the locale definitions (LC_*) for supported locales.
+EOD
diff --git a/release/packages/ucl/lp-all.ucl b/release/packages/ucl/lp-all.ucl
new file mode 100644
index 000000000000..c400038458d0
--- /dev/null
+++ b/release/packages/ucl/lp-all.ucl
@@ -0,0 +1,4 @@
+comment = "Printer subsystem"
+desc = <<EOD
+Printer subsystem
+EOD
diff --git a/release/packages/ucl/manuals-all.ucl b/release/packages/ucl/manuals-all.ucl
new file mode 100644
index 000000000000..9acfd90159ae
--- /dev/null
+++ b/release/packages/ucl/manuals-all.ucl
@@ -0,0 +1,4 @@
+comment = "Manual Pages"
+desc = <<EOD
+Manual Pages
+EOD
diff --git a/release/packages/ucl/mlx-tools-all.ucl b/release/packages/ucl/mlx-tools-all.ucl
new file mode 100644
index 000000000000..4af47252c71d
--- /dev/null
+++ b/release/packages/ucl/mlx-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "Mellanox Utilities"
+desc = <<EOD
+Mellanox Utilities
+EOD
diff --git a/release/packages/ucl/mtree-all.ucl b/release/packages/ucl/mtree-all.ucl
new file mode 100644
index 000000000000..b921c51a6afb
--- /dev/null
+++ b/release/packages/ucl/mtree-all.ucl
@@ -0,0 +1,4 @@
+comment = "MTREE Files"
+desc = <<EOD
+MTREE Files
+EOD
diff --git a/release/packages/ucl/natd-all.ucl b/release/packages/ucl/natd-all.ucl
new file mode 100644
index 000000000000..db5103c1d591
--- /dev/null
+++ b/release/packages/ucl/natd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Network Address Translation (NAT) daemon for ipfw"
+desc = <<EOD
+natd provides userland NAT support for ipfw using divert(4) sockets.
+EOD
diff --git a/release/packages/ucl/netmap-all.ucl b/release/packages/ucl/netmap-all.ucl
new file mode 100644
index 000000000000..e0c0c65b8fb8
--- /dev/null
+++ b/release/packages/ucl/netmap-all.ucl
@@ -0,0 +1,4 @@
+comment = "Netmap Library and Utilities"
+desc = <<EOD
+Netmap Library and Utilities
+EOD
diff --git a/release/packages/ucl/newsyslog-all.ucl b/release/packages/ucl/newsyslog-all.ucl
new file mode 100644
index 000000000000..e52b34dbdcba
--- /dev/null
+++ b/release/packages/ucl/newsyslog-all.ucl
@@ -0,0 +1,4 @@
+comment = "Newsyslog Utility"
+desc = <<EOD
+Newsyslog Utility
+EOD
diff --git a/release/packages/ucl/nfs-all.ucl b/release/packages/ucl/nfs-all.ucl
new file mode 100644
index 000000000000..a53d2f028975
--- /dev/null
+++ b/release/packages/ucl/nfs-all.ucl
@@ -0,0 +1,4 @@
+comment = "NFS Utilities"
+desc = <<EOD
+NFS Utilities
+EOD
diff --git a/release/packages/ucl/ntp-all.ucl b/release/packages/ucl/ntp-all.ucl
new file mode 100644
index 000000000000..c01ae91c31cf
--- /dev/null
+++ b/release/packages/ucl/ntp-all.ucl
@@ -0,0 +1,4 @@
+comment = "Network Time Protocol server and client"
+desc = <<EOD
+Network Time Protocol server and client
+EOD
diff --git a/release/packages/ucl/nuageinit-all.ucl b/release/packages/ucl/nuageinit-all.ucl
new file mode 100644
index 000000000000..4d510b799fa7
--- /dev/null
+++ b/release/packages/ucl/nuageinit-all.ucl
@@ -0,0 +1,4 @@
+comment = "CloudInit support scripts"
+desc = <<EOD
+CloudInit support scripts
+EOD
diff --git a/release/packages/ucl/nvme-tools-all.ucl b/release/packages/ucl/nvme-tools-all.ucl
new file mode 100644
index 000000000000..5863af2d5e34
--- /dev/null
+++ b/release/packages/ucl/nvme-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "NVME Utilities"
+desc = <<EOD
+NVME Utilities
+EOD
diff --git a/release/packages/ucl/openssl-all.ucl b/release/packages/ucl/openssl-all.ucl
new file mode 100644
index 000000000000..8dd2da021f0a
--- /dev/null
+++ b/release/packages/ucl/openssl-all.ucl
@@ -0,0 +1,4 @@
+comment = "OpenSSL Utility"
+desc = <<EOD
+OpenSSL Utility
+EOD
diff --git a/release/packages/ucl/openssl-lib-all.ucl b/release/packages/ucl/openssl-lib-all.ucl
new file mode 100644
index 000000000000..c81dd44855cd
--- /dev/null
+++ b/release/packages/ucl/openssl-lib-all.ucl
@@ -0,0 +1,4 @@
+comment = "OpenSSL Libraries"
+desc = <<EOD
+OpenSSL Libraries
+EOD
diff --git a/release/packages/ucl/periodic-all.ucl b/release/packages/ucl/periodic-all.ucl
new file mode 100644
index 000000000000..569bf8d829c4
--- /dev/null
+++ b/release/packages/ucl/periodic-all.ucl
@@ -0,0 +1,4 @@
+comment = "Periodic Utility"
+desc = <<EOD
+Periodic Utility
+EOD
diff --git a/release/packages/ucl/periodic.ucl b/release/packages/ucl/periodic.ucl
new file mode 100644
index 000000000000..6f85d2ab744b
--- /dev/null
+++ b/release/packages/ucl/periodic.ucl
@@ -0,0 +1,6 @@
+deps {
+ "cron" {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
diff --git a/release/packages/ucl/pf-all.ucl b/release/packages/ucl/pf-all.ucl
new file mode 100644
index 000000000000..4b58fa4f6364
--- /dev/null
+++ b/release/packages/ucl/pf-all.ucl
@@ -0,0 +1,4 @@
+comment = "OpenBSD packet filter"
+desc = <<EOD
+pf is an advanced stateful packet filter developed by the OpenBSD project.
+EOD
diff --git a/release/packages/ucl/pkg-bootstrap-all.ucl b/release/packages/ucl/pkg-bootstrap-all.ucl
new file mode 100644
index 000000000000..9ca6ccd2af58
--- /dev/null
+++ b/release/packages/ucl/pkg-bootstrap-all.ucl
@@ -0,0 +1,4 @@
+comment = "pkg bootstrap Utility"
+desc = <<EOD
+pkg bootstrap Utility
+EOD
diff --git a/release/packages/ucl/ppp-all.ucl b/release/packages/ucl/ppp-all.ucl
new file mode 100644
index 000000000000..454e54b7b872
--- /dev/null
+++ b/release/packages/ucl/ppp-all.ucl
@@ -0,0 +1,5 @@
+comment = "Userland PPP implementation"
+desc = <<EOD
+ppp(8) is a userland implementations of the Point to Point Protocol for serial
+lines and Ethernet (PPPoE).
+EOD
diff --git a/release/packages/ucl/quotacheck-all.ucl b/release/packages/ucl/quotacheck-all.ucl
new file mode 100644
index 000000000000..18b2c3d9bd5c
--- /dev/null
+++ b/release/packages/ucl/quotacheck-all.ucl
@@ -0,0 +1,8 @@
+comment = "Filesystem quota consistency checker"
+desc = <<EOD
+The quotacheck utility examines each file system, builds a table of current
+disk usage, and compares this table against that recorded in the disk quota
+file for the file system. If any inconsistencies are detected, both the quota
+file and the current system copy of the incorrect quotas are updated (the
+latter only occurs if an active file system is checked).
+EOD
diff --git a/release/packages/ucl/rc-all.ucl b/release/packages/ucl/rc-all.ucl
new file mode 100644
index 000000000000..04ed0dafacf0
--- /dev/null
+++ b/release/packages/ucl/rc-all.ucl
@@ -0,0 +1,4 @@
+comment = "RC Scripts"
+desc = <<EOD
+RC Scripts
+EOD
diff --git a/release/packages/ucl/rcmds-all.ucl b/release/packages/ucl/rcmds-all.ucl
new file mode 100644
index 000000000000..db51d52ed246
--- /dev/null
+++ b/release/packages/ucl/rcmds-all.ucl
@@ -0,0 +1,7 @@
+comment = "BSD/SunOS remote status commands"
+desc = <<EOD
+The BSD/SunOS remote status commands, which can be used to query or interact
+with remote hosts over the network. This includes the command-line utilities
+rwho, ruptime, rup, rusers and rwall and the daemons rwhod, rpc.rstatd,
+rpc.rusersd, and rpc.rwalld.
+EOD
diff --git a/release/packages/ucl/rcmds.ucl b/release/packages/ucl/rcmds.ucl
new file mode 100644
index 000000000000..88a4916675dc
--- /dev/null
+++ b/release/packages/ucl/rcmds.ucl
@@ -0,0 +1,8 @@
+deps {
+ # The RPC daemons require rpcbind.
+ "utilities" {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
+
diff --git a/release/packages/ucl/rdma-all.ucl b/release/packages/ucl/rdma-all.ucl
new file mode 100644
index 000000000000..313c2b7d17e0
--- /dev/null
+++ b/release/packages/ucl/rdma-all.ucl
@@ -0,0 +1 @@
+comment = "RDMA Utilities"
diff --git a/release/packages/ucl/rescue-all.ucl b/release/packages/ucl/rescue-all.ucl
new file mode 100644
index 000000000000..da870079bbb7
--- /dev/null
+++ b/release/packages/ucl/rescue-all.ucl
@@ -0,0 +1,4 @@
+comment = "Rescue Utilities"
+desc = <<EOD
+Rescue Utilities
+EOD
diff --git a/release/packages/ucl/resolvconf-all.ucl b/release/packages/ucl/resolvconf-all.ucl
new file mode 100644
index 000000000000..a2d2e0debfa1
--- /dev/null
+++ b/release/packages/ucl/resolvconf-all.ucl
@@ -0,0 +1,4 @@
+comment = "Resolvconf Utility and scripts"
+desc = <<EOD
+Resolvconf Utility and scripts
+EOD
diff --git a/release/packages/ucl/runtime-all.ucl b/release/packages/ucl/runtime-all.ucl
new file mode 100644
index 000000000000..f614a3ef3d43
--- /dev/null
+++ b/release/packages/ucl/runtime-all.ucl
@@ -0,0 +1,4 @@
+comment = "FreeBSD Base System"
+desc = <<EOD
+FreeBSD Base System
+EOD
diff --git a/release/packages/runtime.ucl b/release/packages/ucl/runtime.ucl
index b04bc32f33cc..b04bc32f33cc 100644
--- a/release/packages/runtime.ucl
+++ b/release/packages/ucl/runtime.ucl
diff --git a/release/packages/ucl/sendmail-all.ucl b/release/packages/ucl/sendmail-all.ucl
new file mode 100644
index 000000000000..2711e33a31a8
--- /dev/null
+++ b/release/packages/ucl/sendmail-all.ucl
@@ -0,0 +1,4 @@
+comment = "Sendmail Utilities"
+desc = <<EOD
+Sendmail Utilities
+EOD
diff --git a/release/packages/ucl/smbutils-all.ucl b/release/packages/ucl/smbutils-all.ucl
new file mode 100644
index 000000000000..779179ca3875
--- /dev/null
+++ b/release/packages/ucl/smbutils-all.ucl
@@ -0,0 +1,4 @@
+comment = "SMB Utilities"
+desc = <<EOD
+SMB Utilities
+EOD
diff --git a/release/packages/ucl/src-all.ucl b/release/packages/ucl/src-all.ucl
new file mode 100644
index 000000000000..15b2b7d5b29d
--- /dev/null
+++ b/release/packages/ucl/src-all.ucl
@@ -0,0 +1,5 @@
+comment = "System userland source code"
+desc = <<EOD
+The source code used to rebuild the system, located in /usr/src.
+This package includes everything except the kernel source code.
+EOD
diff --git a/release/packages/ucl/src-sys-all.ucl b/release/packages/ucl/src-sys-all.ucl
new file mode 100644
index 000000000000..9b1c5b64bfbb
--- /dev/null
+++ b/release/packages/ucl/src-sys-all.ucl
@@ -0,0 +1,5 @@
+comment = "System kernel source code"
+desc = <<EOD
+The source code used to rebuild the system, located in /usr/src.
+This package includes the kernel source code.
+EOD
diff --git a/release/packages/ucl/ssh-all.ucl b/release/packages/ucl/ssh-all.ucl
new file mode 100644
index 000000000000..8159391eab08
--- /dev/null
+++ b/release/packages/ucl/ssh-all.ucl
@@ -0,0 +1,5 @@
+comment = "Secure Shell Utilities"
+desc = <<EOD
+Secure Shell Utilities
+EOD
+licenses = [ ISCL ]
diff --git a/release/packages/ucl/syscons-data-all.ucl b/release/packages/ucl/syscons-data-all.ucl
new file mode 100644
index 000000000000..9f59bfd60588
--- /dev/null
+++ b/release/packages/ucl/syscons-data-all.ucl
@@ -0,0 +1,4 @@
+comment = "syscons(4) fonts and keymaps"
+desc = <<EOD
+Fonts and keymaps for use with the legacy syscons(4) video console driver.
+EOD
diff --git a/release/packages/ucl/syslogd-all.ucl b/release/packages/ucl/syslogd-all.ucl
new file mode 100644
index 000000000000..0f82c31fdf0f
--- /dev/null
+++ b/release/packages/ucl/syslogd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Syslog Daemon"
+desc = <<EOD
+Syslog Daemon
+EOD
diff --git a/release/packages/ucl/tcpd-all.ucl b/release/packages/ucl/tcpd-all.ucl
new file mode 100644
index 000000000000..13b7449af267
--- /dev/null
+++ b/release/packages/ucl/tcpd-all.ucl
@@ -0,0 +1,4 @@
+comment = "TCP Wrapper utilities"
+desc = <<EOD
+TCP Wrapper utilities
+EOD
diff --git a/release/packages/ucl/telnet-all.ucl b/release/packages/ucl/telnet-all.ucl
new file mode 100644
index 000000000000..e235b0d776eb
--- /dev/null
+++ b/release/packages/ucl/telnet-all.ucl
@@ -0,0 +1,4 @@
+comment = "Telnet client"
+desc = <<EOD
+Telnet client
+EOD
diff --git a/release/packages/ucl/tests-all.ucl b/release/packages/ucl/tests-all.ucl
new file mode 100644
index 000000000000..39bd365bee5b
--- /dev/null
+++ b/release/packages/ucl/tests-all.ucl
@@ -0,0 +1,4 @@
+comment = "Test Suite"
+desc = <<EOD
+Test Suite
+EOD
diff --git a/release/packages/ucl/toolchain-all.ucl b/release/packages/ucl/toolchain-all.ucl
new file mode 100644
index 000000000000..dd6517745722
--- /dev/null
+++ b/release/packages/ucl/toolchain-all.ucl
@@ -0,0 +1,4 @@
+comment = "Utilities for program development"
+desc = <<EOD
+Utilities for program development.
+EOD
diff --git a/release/packages/ucl/ufs-all.ucl b/release/packages/ucl/ufs-all.ucl
new file mode 100644
index 000000000000..48f9975e0dbd
--- /dev/null
+++ b/release/packages/ucl/ufs-all.ucl
@@ -0,0 +1,4 @@
+comment = "UFS Libraries and Utilities"
+desc = <<EOD
+UFS Libraries and Utilities
+EOD
diff --git a/release/packages/ucl/unbound-all.ucl b/release/packages/ucl/unbound-all.ucl
new file mode 100644
index 000000000000..700c9e4cf9d0
--- /dev/null
+++ b/release/packages/ucl/unbound-all.ucl
@@ -0,0 +1,5 @@
+comment = "Unbound DNS Resolver"
+desc = <<EOD
+Unbound DNS Resolver
+EOD
+licenses = [ BSD4CLAUSE ]
diff --git a/release/packages/ucl/utilities-all.ucl b/release/packages/ucl/utilities-all.ucl
new file mode 100644
index 000000000000..aeb82b0cfed5
--- /dev/null
+++ b/release/packages/ucl/utilities-all.ucl
@@ -0,0 +1,4 @@
+comment = "Non-vital programs and libraries"
+desc = <<EOD
+Non-vital programs and libraries
+EOD
diff --git a/release/packages/utilities.ucl b/release/packages/ucl/utilities.ucl
index 4eb98cae292a..4eb98cae292a 100644
--- a/release/packages/utilities.ucl
+++ b/release/packages/ucl/utilities.ucl
diff --git a/release/packages/ucl/vi-all.ucl b/release/packages/ucl/vi-all.ucl
new file mode 100644
index 000000000000..c2ad2f8e95eb
--- /dev/null
+++ b/release/packages/ucl/vi-all.ucl
@@ -0,0 +1,4 @@
+comment = "Vi Editor"
+desc = <<EOD
+Vi Editor
+EOD
diff --git a/release/packages/ucl/vt-data-all.ucl b/release/packages/ucl/vt-data-all.ucl
new file mode 100644
index 000000000000..4142b2eeae70
--- /dev/null
+++ b/release/packages/ucl/vt-data-all.ucl
@@ -0,0 +1,4 @@
+comment = "vt(4) fonts and keymaps"
+desc = <<EOD
+Fonts and keymaps for use with the vt(4) video console driver.
+EOD
diff --git a/release/packages/ucl/wpa-all.ucl b/release/packages/ucl/wpa-all.ucl
new file mode 100644
index 000000000000..e5ad7f36db95
--- /dev/null
+++ b/release/packages/ucl/wpa-all.ucl
@@ -0,0 +1,4 @@
+comment = "802.11 Supplicant"
+desc = <<EOD
+802.11 Supplicant
+EOD
diff --git a/release/packages/ucl/yp-all.ucl b/release/packages/ucl/yp-all.ucl
new file mode 100644
index 000000000000..9e17cd108d84
--- /dev/null
+++ b/release/packages/ucl/yp-all.ucl
@@ -0,0 +1,7 @@
+comment = "Yellow Pages (YP) / Network Information Service (NIS)"
+desc = <<EOD
+YP, also called NIS, is a network protocol for sharing name service
+information across machines on a network. This packages contains the YP
+server, YP management utilities, the YP-LDAP gateway (ypldap), YP client
+utilities and a sample Makefile for building the YP database.
+EOD
diff --git a/release/packages/ucl/zfs-all.ucl b/release/packages/ucl/zfs-all.ucl
new file mode 100644
index 000000000000..f4178acc481c
--- /dev/null
+++ b/release/packages/ucl/zfs-all.ucl
@@ -0,0 +1,4 @@
+comment = "ZFS Libraries and Utilities"
+desc = <<EOD
+ZFS Libraries and Utilities
+EOD
diff --git a/release/packages/ucl/zoneinfo-all.ucl b/release/packages/ucl/zoneinfo-all.ucl
new file mode 100644
index 000000000000..39991bf144e6
--- /dev/null
+++ b/release/packages/ucl/zoneinfo-all.ucl
@@ -0,0 +1,5 @@
+comment = "Timezone database"
+desc = <<EOD
+The timezone database allows applications to convert dates and times between
+UTC and local timezones.
+EOD
diff --git a/release/packages/unbound-all.ucl b/release/packages/unbound-all.ucl
deleted file mode 100644
index 78bb1f284ff2..000000000000
--- a/release/packages/unbound-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ BSD4CLAUSE ]
diff --git a/release/powerpc/mkisoimages.sh b/release/powerpc/mkisoimages.sh
index ba7c32f87bee..9d83390f1a4e 100644
--- a/release/powerpc/mkisoimages.sh
+++ b/release/powerpc/mkisoimages.sh
@@ -24,6 +24,9 @@
set -e
+scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
+
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
@@ -107,7 +110,7 @@ echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > "$BASEBITSDIR/etc/fstab"
if [ -n "${METALOG}" ]; then
echo "./etc/fstab type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$MAKEFSARG" "$@"
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$MAKEFSARG" "$@"
rm -f "$BASEBITSDIR/etc/fstab"
if [ n "$bootable" ]; then
rm $BOOTBLOCK
diff --git a/release/riscv/make-memstick.sh b/release/riscv/make-memstick.sh
index 90ff98b394c7..0da59c29635b 100755
--- a/release/riscv/make-memstick.sh
+++ b/release/riscv/make-memstick.sh
@@ -17,6 +17,7 @@ if [ "$(uname -s)" = "FreeBSD" ]; then
fi
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
if [ $# -ne 2 ]; then
@@ -51,7 +52,7 @@ if [ -n "${METALOG}" ]; then
echo "./etc/rc.conf.local type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
rm ${BASEBITSDIR}/etc/fstab
rm ${BASEBITSDIR}/etc/rc.conf.local
if [ -n "${METALOG}" ]; then
@@ -62,7 +63,7 @@ fi
espfilename=$(mktemp /tmp/efiboot.XXXXXX)
make_esp_file ${espfilename} ${fat32min} ${BASEBITSDIR}/boot/loader.efi
-mkimg -s gpt \
+${MKIMG} -s gpt \
-p efi:=${espfilename} \
-p freebsd-ufs:=${2}.part \
-o ${2}
diff --git a/release/riscv/mkisoimages.sh b/release/riscv/mkisoimages.sh
index cb58178ed4b9..46b16f0ce08d 100644
--- a/release/riscv/mkisoimages.sh
+++ b/release/riscv/mkisoimages.sh
@@ -21,20 +21,9 @@
set -e
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
-if [ -z $ETDUMP ]; then
- ETDUMP=etdump
-fi
-
-if [ -z $MAKEFS ]; then
- MAKEFS=makefs
-fi
-
-if [ -z $MKIMG ]; then
- MKIMG=mkimg
-fi
-
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
diff --git a/release/scripts/make-oci-image.sh b/release/scripts/make-oci-image.sh
index cc599c76bd51..8a620e9d8973 100644
--- a/release/scripts/make-oci-image.sh
+++ b/release/scripts/make-oci-image.sh
@@ -22,16 +22,16 @@ echo "Building OCI freebsd${major}-${image} image for ${abi}"
init_repo() {
local workdir=$1; shift
local abi=$1; shift
+ local srcdir=$(realpath ${curdir}/..)
mkdir -p ${workdir}/repos
cat > ${workdir}/repos/base.conf <<EOF
FreeBSD-base: {
- url: "file:///usr/obj/usr/src/repo/${abi}/latest"
+ url: "file:///usr/obj${srcdir}/repo/${abi}/latest"
signature_type: "none"
fingerprints: "none"
}
EOF
- cp /etc/pkg/FreeBSD.conf ${workdir}/repos
}
# Install packages using pkg(8) into a container with rootfs at $3
diff --git a/release/scripts/tools.subr b/release/scripts/tools.subr
new file mode 100644
index 000000000000..e818f0a55410
--- /dev/null
+++ b/release/scripts/tools.subr
@@ -0,0 +1,13 @@
+#!/bin/sh
+#-
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 The FreeBSD Foundation
+#
+# This software was developed by Klara, Inc.
+# under sponsorship from the FreeBSD Foundation.
+#
+
+: ${ETDUMP:=etdump}
+: ${MAKEFS:=makefs}
+: ${MKIMG:=mkimg}
diff --git a/release/tools/oci-image-static.conf b/release/tools/oci-image-static.conf
index 753a03af653b..8e642d9defce 100644
--- a/release/tools/oci-image-static.conf
+++ b/release/tools/oci-image-static.conf
@@ -14,7 +14,7 @@ oci_image_build() {
mtree -deU -p $m/usr -f ${srcdir}/etc/mtree/BSD.usr.dist > /dev/null
mtree -deU -p $m/usr/include -f ${srcdir}/etc/mtree/BSD.include.dist > /dev/null
mtree -deU -p $m/usr/lib -f ${srcdir}/etc/mtree/BSD.debug.dist > /dev/null
- install_packages ${abi} ${workdir} FreeBSD-caroot FreeBSD-zoneinfo
+ install_packages ${abi} ${workdir} FreeBSD-zoneinfo
cp ${srcdir}/etc/master.passwd $m/etc
pwd_mkdb -p -d $m/etc $m/etc/master.passwd || return $?
cp ${srcdir}/etc/group $m/etc || return $?
@@ -22,7 +22,10 @@ oci_image_build() {
# working directory to OBJDIR/release
cp ../etc/termcap/termcap.small $m/etc/termcap.small || return $?
cp ../etc/termcap/termcap.small $m/usr/share/misc/termcap || return $?
- env DESTDIR=$m /usr/sbin/certctl rehash
+ env DESTDIR=$m \
+ TRUSTPATH=${srcdir}/secure/caroot/trusted \
+ UNTRUSTPATH=${srcdir}/secure/caroot/untrusted \
+ certctl -c rehash
# Generate a suitable repo config for pkgbase
case ${branch} in
CURRENT|STABLE|BETA*)
diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr
index ce0ea03c096c..eb816018e9d3 100644
--- a/release/tools/vmimage.subr
+++ b/release/tools/vmimage.subr
@@ -6,6 +6,7 @@
#
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
@@ -209,11 +210,11 @@ buildfs() {
case "${VMFS}" in
ufs)
- cd ${DESTDIR} && makefs ${MAKEFSARGS} -o label=rootfs -o version=2 -o softupdates=1 \
+ cd ${DESTDIR} && ${MAKEFS} ${MAKEFSARGS} -o label=rootfs -o version=2 -o softupdates=1 \
${VMBASE} .${NO_ROOT:+/METALOG}
;;
zfs)
- cd ${DESTDIR} && makefs -t zfs ${MAKEFSARGS} \
+ cd ${DESTDIR} && ${MAKEFS} -t zfs ${MAKEFSARGS} \
-o poolname=zroot -o bootfs=zroot/ROOT/default -o rootpath=/ \
-o fs=zroot\;mountpoint=none \
-o fs=zroot/ROOT\;mountpoint=none \
@@ -342,7 +343,7 @@ vm_create_disk() {
buildfs
echo "Building final disk image... Please wait."
- mkimg -s ${PARTSCHEME} -f ${VMFORMAT} \
+ ${MKIMG} -s ${PARTSCHEME} -f ${VMFORMAT} \
${BOOTPARTS} \
${SWAPOPT} \
${CONFIG_DRIVE} \
diff --git a/sbin/bectl/bectl.8 b/sbin/bectl/bectl.8
index cc88c7019d13..0e08b3383e9a 100644
--- a/sbin/bectl/bectl.8
+++ b/sbin/bectl/bectl.8
@@ -3,12 +3,12 @@
.\"
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
-.Dd April 9, 2024
+.Dd June 13, 2025
.Dt BECTL 8
.Os
.Sh NAME
.Nm bectl
-.Nd Utility to manage boot environments on ZFS
+.Nd manage ZFS boot environments
.Sh SYNOPSIS
.Nm
.Op Fl h
@@ -80,34 +80,31 @@
.Sh DESCRIPTION
The
.Nm
-command is used to setup and interact with ZFS boot environments, which are
-bootable clones of datasets.
-.Pp
-A boot environment allows the system to be upgraded, while preserving the
-pre-upgrade system environment.
-.Pp
-.Nm
-itself accepts an
-.Fl r
-flag specified before the command to indicate the
-.Ar beroot
-that should be used as the boot environment root, or the dataset whose children
-are all boot environments.
-Normally this information is derived from the bootfs property of the pool that
-is mounted at
-.Pa / ,
-but it is useful when the system has not been booted into a ZFS root or a
-different pool should be operated on.
-For instance, booting into the recovery media and manually importing a pool from
-one of the system's resident disks will require the
-.Fl r
-flag to work.
+utility manages bootable ZFS clones called boot environments.
+Boot envionments allow system changes to be tested safely,
+as they are selectable directly from the boot
+.Xr loader 8 .
+This utility can
+.Cm create ,
+.Cm list ,
+.Cm mount ,
+or
+.Cm jail
+boot environments.
+Once the changes have been tested, the boot environment can be
+.Cm unmount Ns ed ,
+.Cm activate Ns d ,
+.Cm rename Ns d ,
+and
+.Cm destroy Ns ed .
.Ss Supported Subcommands and Flags
-.Bl -tag -width activate
-.It Xo
-.Fl h
-.Xc
+.Bl -tag -width indent
+.It Fl h
Print usage information and exit.
+.It Fl r Ar beroot Sy Ar subcommand
+Specify a parent dataset for the boot environment to use for
+.Ar subcommand
+for operation on manually imported pools or unusual layouts.
.It Xo
.Cm activate
.Op Fl t | Fl T
@@ -122,19 +119,19 @@ flag is given, this takes effect only for the next boot.
Flag
.Fl T
removes temporary boot once configuration.
-Without temporary configuration, the next boot will use zfs dataset specified
-in boot pool
+Without temporary configuration,
+the next boot will use zfs dataset specified in boot pool
.Ar bootfs
property.
.It Xo
.Cm check
.Xc
-Performs a silent sanity check on the current system.
+Perform a check to see if the current system can use boot environments.
If boot environments are supported and used,
.Nm
will exit with a status code of 0.
-Any other status code is not currently defined and may, in the future, grow
-special meaning for different degrees of sanity check failures.
+Any other status code is not currently defined and may, in the future,
+grow special meaning for different degrees of sanity check failures.
.It Xo
.Cm create
.Op Fl r
@@ -162,8 +159,8 @@ environment.
.Pp
If
.Nm
-is creating from another boot environment, a snapshot of that boot environment
-will be created to clone from.
+is creating from another boot environment,
+a snapshot of that boot environment will be created to clone from.
.It Xo
.Cm create
.Op Fl r
@@ -174,8 +171,10 @@ Create a snapshot of the boot environment named
.Pp
If the
.Fl r
-flag is given, a recursive snapshot of the boot environment will be created.
-A snapshot is created for each descendant dataset of the boot environment.
+flag is given,
+a recursive snapshot of the boot environment will be created.
+A snapshot is created for each descendant dataset
+of the boot environment.
See
.Sx Boot Environment Structures
for a discussion on different layouts.
@@ -241,8 +240,8 @@ If
.Ar utility
is specified, it will be executed instead of
.Pa /bin/sh .
-The jail will be destroyed and the boot environment unmounted when the command
-finishes executing, unless the
+The jail will be destroyed and the boot environment unmounted
+when the command finishes executing, unless the
.Fl U
argument is specified.
.Pp
@@ -269,11 +268,11 @@ The following default parameters are provided:
.It Va allow.mount Ta Cm true
.It Va allow.mount.devfs Ta Cm true
.It Va enforce_statfs Ta Cm 1
-.It Va name Ta Set to jail ID.
+.It Va name Ta set to jail ID
.It Va host.hostname Ta Va bootenv
-.It Va path Ta Set to a path in Pa /tmp
+.It Va path Ta set to a path in Pa /tmp
generated by
-.Xr libbe 3 .
+.Xr libbe 3
.El
.Pp
All default parameters may be overwritten.
@@ -298,8 +297,8 @@ or combination of
.It Fl a
Display all datasets.
.It Fl D
-Display the full space usage for each boot environment, assuming all
-other boot environments were destroyed.
+Display the full space usage for each boot environment,
+assuming all other boot environments were destroyed.
.It Fl H
Used for scripting.
Do not print headers and separate fields by a single tab instead of
@@ -351,8 +350,8 @@ will make a directory such as
.Pa be_mount.c6Sf
in
.Pa /tmp .
-Randomness in the last four characters of the directory name will prevent
-mount point conflicts.
+Randomness in the last four characters of the directory name
+will prevent mount point conflicts.
Unmount of an environment, followed by mount of the same environment
without giving a
.Ar mountpoint ,
@@ -362,7 +361,7 @@ Rename the given
.Ar origBeName
to the given
.Ar newBeName .
-The boot environment will not be unmounted in order for this rename to occur.
+The boot environment will not be unmounted for this rename to occur.
.It Cm ujail Brq Ar jailId | jailName | beName
.It Cm unjail Brq Ar jailId | jailName | beName
Destroy the jail created from the given boot environment.
@@ -390,8 +389,8 @@ boot environment layout, as created by the Auto ZFS option to
.Xr bsdinstall 8 ,
is a
.Dq shallow
-boot environment structure, where boot environment datasets do not have any
-directly subordinate datasets.
+boot environment structure, where boot environment datasets
+do not have any directly subordinate datasets.
Instead, they're organized off in
.Pa zroot/ROOT ,
and they rely on datasets elsewhere in the pool having
@@ -419,7 +418,8 @@ set to
.Dv off ,
thus files in
.Pa /usr
-typically fall into the boot environment because this dataset is not mounted.
+typically fall into the boot environment
+because this dataset is not mounted.
.Pa zroot/usr/src
is mounted, thus files in
.Pa /usr/src
@@ -445,8 +445,8 @@ Note that the subordinate datasets now have
.Dv canmount
set to
.Dv noauto .
-These are more obviously a part of the boot environment, as indicated by their
-positioning in the layout.
+These are more obviously a part of the boot environment,
+as indicated by their positioning in the layout.
These subordinate datasets will be mounted by the
.Dv zfsbe
.Xr rc 8
@@ -468,16 +468,25 @@ A future version of
may default to handling both styles and deprecate the various
.Fl r
flags.
-.\" .Sh EXAMPLES
-.\" .Bl -bullet
-.\" .It
+.Sh EXAMPLES
+Create a boot environment, named with today's date,
+containing snapshots of the root dataset and of all child datasets:
+.Pp
+.Dl bectl create -r `date +%Y%m%d`
+.Pp
+Mount a previous boot environment,
+.Ar yesterdaysbe ,
+to
+.Pa /mnt :
+.Pp
+.Dl bectl mount yesterdaysbe /mnt
.\" To fill in with jail upgrade example when behavior is firm.
-.\" .El
.Sh SEE ALSO
.Xr libbe 3 ,
.Xr zfsprops 7 ,
.Xr beinstall.sh 8 ,
.Xr jail 8 ,
+.Xr loader 8 ,
.Xr zfs 8 ,
.Xr zpool 8
.Sh HISTORY
diff --git a/sbin/devd/Makefile b/sbin/devd/Makefile
index 4ff0187a5a22..5d5721d16884 100644
--- a/sbin/devd/Makefile
+++ b/sbin/devd/Makefile
@@ -46,6 +46,11 @@ HYPERV+= hyperv.conf
HYPERVPACKAGE= hyperv-tools
.endif
+CONFGROUPS+= NVME
+NVMEDIR= ${DEVDDIR}
+NVME+= nvmf.conf
+NVMEPACKAGE= nvme-tools
+
.if ${MK_USB} != "no"
DEVD+= uath.conf ulpt.conf
.endif
diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc
index d7a3fee57870..6705dcc0158e 100644
--- a/sbin/devd/devd.cc
+++ b/sbin/devd/devd.cc
@@ -153,6 +153,8 @@ static volatile sig_atomic_t romeo_must_die = 0;
static const char *configfile = CF;
+static char vm_guest[80];
+
static void devdlog(int priority, const char* message, ...)
__printflike(2, 3);
static void event_loop(void);
@@ -867,6 +869,8 @@ process_event(char *buffer)
cfg.set_variable("timestamp", timestr);
free(timestr);
+ cfg.set_variable("vm_guest", vm_guest);
+
// Match doesn't have a device, and the format is a little
// different, so handle it separately.
switch (type) {
@@ -1322,6 +1326,7 @@ int
main(int argc, char **argv)
{
int ch;
+ size_t len;
check_devd_enabled();
while ((ch = getopt(argc, argv, "df:l:nq")) != -1) {
@@ -1346,6 +1351,12 @@ main(int argc, char **argv)
}
}
+ len = sizeof(vm_guest);
+ if (sysctlbyname("kern.vm_guest", vm_guest, &len, NULL, 0) < 0) {
+ devdlog(LOG_ERR,
+ "sysctlbyname(kern.vm_guest) failed: %d\n", errno);
+ }
+
cfg.parse();
if (!no_daemon && daemonize_quick) {
cfg.open_pidfile();
diff --git a/sbin/devd/devd.conf.5 b/sbin/devd/devd.conf.5
index adeeec7fd611..baf4b9d3a183 100644
--- a/sbin/devd/devd.conf.5
+++ b/sbin/devd/devd.conf.5
@@ -38,7 +38,7 @@
.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
.\" SOFTWARE.
.\"
-.Dd April 29, 2025
+.Dd July 9, 2025
.Dt DEVD.CONF 5
.Os
.Sh NAME
@@ -322,7 +322,7 @@ mechanism.
.\" for each of the tables so that things line up in columns nicely.
.\" Please do not omit the type column for notifiers that omit it.
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li ACPI Ta Ta Ta
Events related to the ACPI Subsystem.
@@ -346,13 +346,13 @@ Suspend notification.
Thermal zone events.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li AEON Ta Li power Ta Li press Ta
The power button on an Amiga has been pressed.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li CAM Ta Ta Ta
Events related to the
@@ -366,24 +366,24 @@ Generic errors.
Command timeouts.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li CARP Ta Ta Ta
Events related to the
.Xr carp 4
protocol.
-.It CARP Ta Ar vhid@inet Ta Ta
+.It Li CARP Ta Ar vhid@inet Ta Ta
The
.Dq subsystem
contains the actual CARP vhid and the name of the network interface
on which the event took place.
-.It CARP Ta Ar vhid@inet Ta MASTER Ta
+.It Li CARP Ta Ar vhid@inet Ta Li MASTER Ta
Node become the master for a virtual host.
-.It CARP Ta Ar vhid@inet Ta BACKUP Ta
+.It Li CARP Ta Ar vhid@inet Ta Li BACKUP Ta
Node become the backup for a virtual host.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "CORETEMP" "SUBSYSTEM" "TEMPERATURE" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li coretemp Ta Ta Ta
Events related to the
@@ -395,7 +395,7 @@ Notification that the CPU core has reached critical temperature.
String containing the temperature of the core that has become too hot.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li DEVFS
.It Li DEVFS Ta Li CDEV Ta Li CREATE Ta
@@ -408,7 +408,7 @@ The
node is destroyed.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li ETHERNET Ta Ar inet Ta IFATTACH Ta
Notification when the default VNET instance of the
@@ -416,7 +416,7 @@ Notification when the default VNET instance of the
interface is attached.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "GEOM::ROTATION_RATE" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li GEOM Ta Ta Ta
Events related to the
@@ -447,7 +447,7 @@ A
provider size has changed.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "LINK_DOWN" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li IFNET
.It Li IFNET Ta Em inet Ta Ta
@@ -471,7 +471,7 @@ The network interface address added.
The network interface address removed.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li kernel Ta Li signal Ta Li coredump Ta
Notification that a process has crashed and dumped core.
@@ -479,21 +479,33 @@ Notification that a process has crashed and dumped core.
Notification that the system has woken from the suspended state.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "SMART_ERROR" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
+.It Li nvme Ta Li controller Ta Ta
+Controller events provide the controller name
+.Pq for example, Li nvme0
+in $name.
.It Li nvme Ta Li controller Ta Li SMART_ERROR Ta
A SMART Critical Warning State change has happened.
$state has a hex bitmask of the bits that changed, as defined
in the NVMe Standard for Critical Warning field of log page 2
.Dq SMART / Health Information Log :
-.Bl -column "Bit Value" "Meaning" -compact
-.Sy "Bit Value" Ta Sy "Meaning"
-.It 0x1 Ta Spare capacity below threshold
-.It 0x2 Ta Temperature outside acceptable range
-.It 0x4 Ta Reliability of media degraded
-.It 0x8 Ta Media placed into read-only mode
-.It 0x10 Ta Volatime memory backup failure
-.It 0x20 Ta Persistent memory read-only or degraded
+.Pp
+.Bl -tag -width "Bit Value" -compact
+.It Sy "Bit Value"
+.Sy Meaning
+.It 0x1
+Spare capacity below threshold
+.It 0x2
+Temperature outside acceptable range
+.It 0x4
+Reliability of media degraded
+.It 0x8
+Media placed into read-only mode
+.It 0x10
+Volatime memory backup failure
+.It 0x20
+Persistent memory read-only or degraded
.El
.It Li nvme Ta Li controller Ta Li RESET Ta
A controller reset event has happened.
@@ -503,11 +515,13 @@ $event is one of
and
.Dq timed_out
representing the start of a controller reset, the successful completion of a
-controller reset, and a timeout while waiting for the controller to reset
+controller reset, or a timeout while waiting for the controller to reset,
respectively.
+.It Li nvme Ta Li controller Ta Li RECONNECT Ta
+An NVMe over Fabrics host has disconnected and is requesting a reconnect.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "SHUTDOWN-THRESHOLD" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li PMU Ta Ta Ta
Notification of events from various types of Power Management Units.
@@ -520,25 +534,25 @@ Power has been applied to the AC power line.
.It Li PMU Ta Li "AC" Ta Li unplugged Ta
Power has been removed from the AC power line.
.It Li PMU Ta Li Battery Ta Ta
-.It Li PMU Ta Li Battery Ta absent Ta
+.It Li PMU Ta Li Battery Ta Li absent Ta
Battery is no longer absent.
-.It Li PMU Ta Li Battery Ta charged Ta
+.It Li PMU Ta Li Battery Ta Li charged Ta
The battery has become charged.
-.It Li PMU Ta Li Battery Ta charging Ta
+.It Li PMU Ta Li Battery Ta Li charging Ta
The battery has started charging.
-.It Li PMU Ta Li Battery Ta disconnected Ta
+.It Li PMU Ta Li Battery Ta Li disconnected Ta
The battery has been disconnected.
-.It Li PMU Ta Li Battery Ta high-temp Ta
+.It Li PMU Ta Li Battery Ta Li high-temp Ta
The battery reported a temperature over the limit.
-.It Li PMU Ta Li Battery Ta low-temp Ta
+.It Li PMU Ta Li Battery Ta Li low-temp Ta
The battery reported a temperature under the limit.
-.It Li PMU Ta Li Battery Ta plugged Ta
+.It Li PMU Ta Li Battery Ta Li plugged Ta
The battery has become plugged (eg connected).
-.It Li PMU Ta Li Battery Ta shutdown-threshold Ta
+.It Li PMU Ta Li Battery Ta Li shutdown-threshold Ta
The power in the battery has fallen below the shutdown threshold.
-.It Li PMU Ta Li Battery Ta warning-threshold Ta
+.It Li PMU Ta Li Battery Ta Li warning-threshold Ta
The power in the battery has fallen below the warn the user threshold.
-.It Li PMU Ta Li Button Ta pressed Ta
+.It Li PMU Ta Li Button Ta Li pressed Ta
A button on a
.Xr adb 4
or
@@ -548,39 +562,39 @@ has been pressed.
One of the keys on the
.Xr adb 4
keyboard has been pressed.
-.It Li PMU Ta Li keys Ta brightness Ta
+.It Li PMU Ta Li keys Ta Li brightness Ta
A brightness level change has been requested.
Direction is in the $notify variable.
-.It Li PMU Ta Li keys Ta mute Ta
+.It Li PMU Ta Li keys Ta Li mute Ta
The mute key
-.It Li PMU Ta Li keys Ta volume Ta
+.It Li PMU Ta Li keys Ta Li volume Ta
A volume level change has been requested.
Direction is in the $notify variable.
-.It Li PMU Ta Li keys Ta eject Ta
+.It Li PMU Ta Li keys Ta Li eject Ta
An ejection has been requested.
-.It Li PMU Ta Li lid Ta close Ta
+.It Li PMU Ta Li lid Ta Li close Ta
The
.Xr pmc 4
device has detected the lid closing.
-.It Li PMU Ta Li lid Ta open Ta
+.It Li PMU Ta Li lid Ta Li open Ta
The
.Xr pmc 4
device has detected the lid openinging.
-.It Li PMU Ta Li POWER Ta ACLINE Ta
+.It Li PMU Ta Li POWER Ta Li ACLINE Ta
The
.Xr pmc 4
device has detected an AC line state ($notify=0x00 is offline, 0x01 is online).
-.It Li PMU Ta Li USB Ta overvoltage Ta
+.It Li PMU Ta Li USB Ta Li overvoltage Ta
An over-voltage condition on the power lines for the USB power pins.
-.It Li PMU Ta Li USB Ta plugged Ta
+.It Li PMU Ta Li USB Ta Li plugged Ta
A device has been plugged into a USB device.
-.It Li PMU Ta Li USB Ta undervoltage Ta
+.It Li PMU Ta Li USB Ta Li undervoltage Ta
An under-voltage condition on the power lines for the USB power pins.
-.It Li PMU Ta Li USB Ta unplugged Ta
-A device has been unplugged into a USB device.
+.It Li PMU Ta Li USB Ta Li unplugged Ta
+A device has been unplugged from a USB device.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li RCTL Ta Ta Ta
Events related to the
@@ -590,7 +604,7 @@ framework.
A rule with action specified as "devctl" was triggered.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li USB Ta Ta Ta
Events related to the USB subsystem.
@@ -604,7 +618,7 @@ USB interface is attached to a device.
USB interface is detached from a device.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
.It Li VFS Ta Ta Ta
Events from the vfs system.
@@ -618,18 +632,18 @@ Notification of a filesystem is remounted (whether or not the options actually c
Notification of a filesystem being unmounted.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
-.It Li VT Ta BELL Ta RING Ta
+.It Li VT Ta Li BELL Ta Li RING Ta
Notification that the console bell has rung.
See
.Xr vt 4
for details.
.El
.Pp
-.Bl -column "System" "Subsystem" "1234567" -compact
+.Bl -column "SYSTEM" "SUBSYSTEM" "12345678" -compact
.Sy "System" Ta Sy "Subsystem" Ta Sy "Type" Ta Sy "Description"
-.It Li ZFS Ta ZFS Ta Ta
+.It Li ZFS Ta Li ZFS Ta Ta
Events about the ZFS subsystem.
See
.Xr zfsd 8
diff --git a/sbin/devd/hyperv.conf b/sbin/devd/hyperv.conf
index 13695a0c75b6..70108ac36e54 100644
--- a/sbin/devd/hyperv.conf
+++ b/sbin/devd/hyperv.conf
@@ -103,5 +103,6 @@ notify 10 {
notify 10 {
match "system" "ETHERNET";
match "type" "IFATTACH";
+ match "vm_guest" "hv";
action "/usr/libexec/hyperv/hyperv_vfattach $subsystem 0";
};
diff --git a/sbin/devd/nvmf.conf b/sbin/devd/nvmf.conf
new file mode 100644
index 000000000000..eaf3ebe86cec
--- /dev/null
+++ b/sbin/devd/nvmf.conf
@@ -0,0 +1,7 @@
+# Attempt to reconnect NVMeoF host devices when requested
+notify 100 {
+ match "system" "nvme";
+ match "subsystem" "controller";
+ match "type" "RECONNECT";
+ action "nvmecontrol reconnect $name";
+};
diff --git a/sbin/ifconfig/ifbridge.c b/sbin/ifconfig/ifbridge.c
index 2d0af1255a73..ce5d2f4894fa 100644
--- a/sbin/ifconfig/ifbridge.c
+++ b/sbin/ifconfig/ifbridge.c
@@ -147,6 +147,36 @@ bridge_addresses(if_ctx *ctx, const char *prefix)
}
static void
+print_vlans(ifbvlan_set_t *vlans)
+{
+ unsigned printed = 0;
+
+ for (unsigned vlan = DOT1Q_VID_MIN; vlan <= DOT1Q_VID_MAX;) {
+ unsigned last;
+
+ if (!BRVLAN_TEST(vlans, vlan)) {
+ ++vlan;
+ continue;
+ }
+
+ last = vlan;
+ while (last < DOT1Q_VID_MAX && BRVLAN_TEST(vlans, last + 1))
+ ++last;
+
+ if (printed == 0)
+ printf(" tagged ");
+ else
+ printf(",");
+
+ printf("%u", vlan);
+ if (last != vlan)
+ printf("-%u", last);
+ ++printed;
+ vlan = last + 1;
+ }
+}
+
+static void
bridge_status(if_ctx *ctx)
{
struct ifconfig_bridge_status *bridge;
@@ -211,6 +241,9 @@ bridge_status(if_ctx *ctx)
else
printf(" <unknown state %d>", state);
}
+ if (member->ifbr_untagged != 0)
+ printf(" untagged %u", (unsigned)member->ifbr_untagged);
+ print_vlans(&bridge->member_vlans[i]);
printf("\n");
}
@@ -577,6 +610,45 @@ setbridge_ifpathcost(if_ctx *ctx, const char *ifn, const char *cost)
}
static void
+setbridge_untagged(if_ctx *ctx, const char *ifn, const char *vlanid)
+{
+ struct ifbreq req;
+ u_long val;
+
+ memset(&req, 0, sizeof(req));
+
+ if (get_val(vlanid, &val) < 0)
+ errx(1, "invalid VLAN identifier: %s", vlanid);
+
+ /*
+ * Reject vlan 0, since it's not a valid vlan identifier and has a
+ * special meaning in the kernel interface.
+ */
+ if (val == 0)
+ errx(1, "invalid VLAN identifier: %lu", val);
+
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ req.ifbr_untagged = val;
+
+ if (do_cmd(ctx, BRDGSIFUNTAGGED, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFUNTAGGED %s", vlanid);
+}
+
+static void
+unsetbridge_untagged(if_ctx *ctx, const char *ifn, int dummy __unused)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ req.ifbr_untagged = 0;
+
+ if (do_cmd(ctx, BRDGSIFUNTAGGED, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFUNTAGGED");
+}
+
+static void
setbridge_ifmaxaddr(if_ctx *ctx, const char *ifn, const char *arg)
{
struct ifbreq req;
@@ -612,17 +684,118 @@ setbridge_timeout(if_ctx *ctx, const char *arg, int dummy __unused)
static void
setbridge_private(if_ctx *ctx, const char *val, int dummy __unused)
{
-
do_bridgeflag(ctx, val, IFBIF_PRIVATE, 1);
}
static void
unsetbridge_private(if_ctx *ctx, const char *val, int dummy __unused)
{
-
do_bridgeflag(ctx, val, IFBIF_PRIVATE, 0);
}
+static void
+setbridge_vlanfilter(if_ctx *ctx, const char *val, int dummy __unused)
+{
+ do_bridgeflag(ctx, val, IFBIF_VLANFILTER, 1);
+}
+
+static void
+unsetbridge_vlanfilter(if_ctx *ctx, const char *val, int dummy __unused)
+{
+ do_bridgeflag(ctx, val, IFBIF_VLANFILTER, 0);
+}
+
+static int
+parse_vlans(ifbvlan_set_t *set, const char *str)
+{
+ char *s, *token;
+
+ /* "none" means the empty vlan set */
+ if (strcmp(str, "none") == 0) {
+ __BIT_ZERO(BRVLAN_SETSIZE, set);
+ return (0);
+ }
+
+ /* "all" means all vlans, except for 0 and 4095 which are reserved */
+ if (strcmp(str, "all") == 0) {
+ __BIT_FILL(BRVLAN_SETSIZE, set);
+ BRVLAN_CLR(set, DOT1Q_VID_NULL);
+ BRVLAN_CLR(set, DOT1Q_VID_RSVD_IMPL);
+ return (0);
+ }
+
+ if ((s = strdup(str)) == NULL)
+ return (-1);
+
+ while ((token = strsep(&s, ",")) != NULL) {
+ unsigned long first, last;
+ char *p, *lastp;
+
+ if ((lastp = strchr(token, '-')) != NULL)
+ *lastp++ = '\0';
+
+ first = last = strtoul(token, &p, 10);
+ if (*p != '\0')
+ goto err;
+ if (first < DOT1Q_VID_MIN || first > DOT1Q_VID_MAX)
+ goto err;
+
+ if (lastp) {
+ last = strtoul(lastp, &p, 10);
+ if (*p != '\0')
+ goto err;
+ if (last < DOT1Q_VID_MIN || last > DOT1Q_VID_MAX ||
+ last < first)
+ goto err;
+ }
+
+ for (unsigned vlan = first; vlan <= last; ++vlan)
+ BRVLAN_SET(set, vlan);
+ }
+
+ free(s);
+ return (0);
+
+err:
+ free(s);
+ return (-1);
+}
+
+static void
+set_bridge_vlanset(if_ctx *ctx, const char *ifn, const char *vlans, int op)
+{
+ struct ifbif_vlan_req req;
+
+ memset(&req, 0, sizeof(req));
+
+ if (parse_vlans(&req.bv_set, vlans) != 0)
+ errx(1, "invalid vlan set: %s", vlans);
+
+ strlcpy(req.bv_ifname, ifn, sizeof(req.bv_ifname));
+ req.bv_op = op;
+
+ if (do_cmd(ctx, BRDGSIFVLANSET, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFVLANSET %s", vlans);
+}
+
+static void
+setbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans)
+{
+ set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_SET);
+}
+
+static void
+addbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans)
+{
+ set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_ADD);
+}
+
+static void
+delbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans)
+{
+ set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_DEL);
+}
+
static struct cmd bridge_cmds[] = {
DEF_CMD_ARG("addm", setbridge_add),
DEF_CMD_ARG("deletem", setbridge_delete),
@@ -659,6 +832,13 @@ static struct cmd bridge_cmds[] = {
DEF_CMD_ARG2("ifpriority", setbridge_ifpriority),
DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost),
DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr),
+ DEF_CMD_ARG("vlanfilter", setbridge_vlanfilter),
+ DEF_CMD_ARG("-vlanfilter", unsetbridge_vlanfilter),
+ DEF_CMD_ARG2("untagged", setbridge_untagged),
+ DEF_CMD_ARG("-untagged", unsetbridge_untagged),
+ DEF_CMD_ARG2("tagged", setbridge_tagged),
+ DEF_CMD_ARG2("+tagged", addbridge_tagged),
+ DEF_CMD_ARG2("-tagged", delbridge_tagged),
DEF_CMD_ARG("timeout", setbridge_timeout),
DEF_CMD_ARG("private", setbridge_private),
DEF_CMD_ARG("-private", unsetbridge_private),
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index e3f094a336fb..b6e7d3ff2c63 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 24, 2025
+.Dd July 14, 2025
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -2696,6 +2696,57 @@ source addresses are dropped until an existing host cache entry expires or is
removed.
Set to 0 to disable.
.El
+.Ss Bridge VLAN Filtering Parameters
+The behaviour of these options is described in the
+.Dq VLAN SUPPORT
+section of
+.Xr bridge 4 .
+.Bl -tag -width indent
+.It Cm vlanfilter Ar interface
+Enable VLAN filtering on an interface.
+.It Cm -vlanfilter Ar interface
+Disable VLAN filtering on an interface.
+.It Cm untagged Ar interface Ar vlan-id
+Set the untagged VLAN identifier for an interface.
+.Pp
+Setting
+.Cm untagged
+will automatically enable VLAN filtering on the interface.
+.It Cm -untagged Ar interface Ar vlan-id
+Clear the untagged VLAN identifier for an interface.
+.It Cm tagged Ar interface Ar vlan-list
+Set the interface's VLAN access list to the provided list of VLANs.
+The list should be a comma-separated list of one or more VLAN IDs
+or ranges formatted as
+.Ar first-last ,
+the value
+.Dq none
+meaning the empty set,
+or the value
+.Dq all
+meaning all VLANs (1-4094).
+.Pp
+Setting
+.Cm tagged
+will automatically enable VLAN filtering on the interface.
+.It Cm +tagged Ar interface Ar vlan-list
+Add the provided list of VLAN IDs to the interface's VLAN access list.
+The list should be formatted as described for
+.Cm tagged .
+.Pp
+Setting
+.Cm +tagged
+will automatically enable VLAN filtering on the interface.
+.It Cm -tagged Ar interface Ar vlan-list
+Remove the provided list of VLAN IDs from the interface's VLAN access
+list.
+The list should be formatted as described for
+.Cm tagged .
+.Pp
+Setting
+.Cm -tagged
+will automatically enable VLAN filtering on the interface.
+.El
.Ss Link Aggregation and Link Failover Parameters
The following parameters are specific to lagg interfaces:
.Bl -tag -width indent
@@ -2827,34 +2878,26 @@ interfaces previously configured with
Another name for the
.Fl tunnel
parameter.
-.It Cm accept_rev_ethip_ver
-Set a flag to accept both correct EtherIP packets and ones
-with reversed version field.
-Enabled by default.
-This is for backward compatibility with
-.Fx 6.1 ,
-6.2, 6.3, 7.0, and 7.1.
-.It Cm -accept_rev_ethip_ver
-Clear a flag
-.Cm accept_rev_ethip_ver .
+.It Cm noclamp
+This flag prevents the MTU from being clamped to 1280 bytes, the
+minimum MTU for IPv6, when the outer protocol is IPv6. When the
+flag is set, the MTU value configured on the interface will be
+used instead of the fixed length of 1280 bytes. For more details,
+please refer to the
+.Ar MTU Configuration and Path MTU Discovery
+section in
+.Xr gif 4 .
+.It Cm -noclamp
+Clear the flag
+.Cm noclamp .
.It Cm ignore_source
Set a flag to accept encapsulated packets destined to this host
independently from source address.
This may be useful for hosts, that receive encapsulated packets
from the load balancers.
.It Cm -ignore_source
-Clear a flag
+Clear the flag
.Cm ignore_source .
-.It Cm send_rev_ethip_ver
-Set a flag to send EtherIP packets with reversed version
-field intentionally.
-Disabled by default.
-This is for backward compatibility with
-.Fx 6.1 ,
-6.2, 6.3, 7.0, and 7.1.
-.It Cm -send_rev_ethip_ver
-Clear a flag
-.Cm send_rev_ethip_ver .
.El
.Ss GRE Tunnel Parameters
The following parameters apply to GRE tunnel interfaces,
diff --git a/sbin/ifconfig/ifgif.c b/sbin/ifconfig/ifgif.c
index 991cf110678f..9b8be210a59e 100644
--- a/sbin/ifconfig/ifgif.c
+++ b/sbin/ifconfig/ifgif.c
@@ -49,6 +49,7 @@
#include "ifconfig.h"
static const char *GIFBITS[] = {
+ [0] = "NOCLAMP",
[1] = "IGNORE_SOURCE",
};
@@ -90,6 +91,8 @@ setgifopts(if_ctx *ctx, const char *val __unused, int d)
}
static struct cmd gif_cmds[] = {
+ DEF_CMD("noclamp", GIF_NOCLAMP, setgifopts),
+ DEF_CMD("-noclamp", -GIF_NOCLAMP, setgifopts),
DEF_CMD("ignore_source", GIF_IGNORE_SOURCE, setgifopts),
DEF_CMD("-ignore_source", -GIF_IGNORE_SOURCE, setgifopts),
};
diff --git a/sbin/ipf/libipf/printhash_live.c b/sbin/ipf/libipf/printhash_live.c
index 3caaa5e022fe..b8ee31b27597 100644
--- a/sbin/ipf/libipf/printhash_live.c
+++ b/sbin/ipf/libipf/printhash_live.c
@@ -61,5 +61,8 @@ printhash_live(iphtable_t *hp, int fd, char *name, int opts, wordtab_t *fields)
if ((opts & OPT_DEBUG) == 0)
PRINTF(" };\n");
+
+ (void) ioctl(fd,SIOCIPFDELTOK, &iter.ili_key);
+
return (hp->iph_next);
}
diff --git a/sbin/kldstat/kldstat.c b/sbin/kldstat/kldstat.c
index 79c647576440..3a90f1c97eb4 100644
--- a/sbin/kldstat/kldstat.c
+++ b/sbin/kldstat/kldstat.c
@@ -35,7 +35,7 @@
#include <libutil.h>
#include <stdio.h>
#include <stdlib.h>
-#include <strings.h>
+#include <string.h>
#include <unistd.h>
#define PTR_WIDTH ((int)(sizeof(void *) * 2 + 2))
@@ -51,7 +51,7 @@ printmod(int modid)
{
struct module_stat stat;
- bzero(&stat, sizeof(stat));
+ memset(&stat, 0, sizeof(stat));
stat.version = sizeof(struct module_stat);
if (modstat(modid, &stat) < 0) {
warn("can't stat module id %d", modid);
diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8
index b584d71ea567..7bfc21ea41d5 100644
--- a/sbin/mount/mount.8
+++ b/sbin/mount/mount.8
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 30, 2025
+.Dd July 16, 2025
.Dt MOUNT 8
.Os
.Sh NAME
@@ -80,7 +80,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl a
All the file systems described in
@@ -573,7 +573,7 @@ support for a particular file system might be provided either on a static
.Xr acl 3 ,
.Xr getmntinfo 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr cd9660 4 ,
.Xr devfs 4 ,
.Xr ext2fs 4 ,
diff --git a/sbin/nvmecontrol/connect.c b/sbin/nvmecontrol/connect.c
index c1d5d2cbaf5a..3d6d12bf2c48 100644
--- a/sbin/nvmecontrol/connect.c
+++ b/sbin/nvmecontrol/connect.c
@@ -31,6 +31,8 @@ static struct options {
const char *subnqn;
const char *hostnqn;
uint32_t kato;
+ uint32_t reconnect_delay;
+ uint32_t controller_loss_timeout;
uint16_t num_io_queues;
uint16_t queue_size;
bool data_digests;
@@ -43,6 +45,8 @@ static struct options {
.subnqn = NULL,
.hostnqn = NULL,
.kato = NVMF_KATO_DEFAULT / 1000,
+ .reconnect_delay = NVMF_DEFAULT_RECONNECT_DELAY,
+ .controller_loss_timeout = NVMF_DEFAULT_CONTROLLER_LOSS,
.num_io_queues = 1,
.queue_size = 0,
.data_digests = false,
@@ -107,7 +111,7 @@ connect_nvm_controller(enum nvmf_trtype trtype, int adrfam, const char *address,
}
error = nvmf_handoff_host(dle, hostnqn, admin, opt.num_io_queues, io,
- &cdata);
+ &cdata, opt.reconnect_delay, opt.controller_loss_timeout);
if (error != 0) {
warnc(error, "Failed to handoff queues to kernel");
free(io);
@@ -259,6 +263,11 @@ static const struct opts connect_opts[] = {
"Number of entries in each I/O queue"),
OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato,
"Keep Alive timeout (in seconds)"),
+ OPT("reconnect-delay", 'r', arg_uint32, opt, reconnect_delay,
+ "Delay between reconnect attempts after connection loss "
+ "(in seconds)"),
+ OPT("ctrl-loss-tmo", 'l', arg_uint32, opt, controller_loss_timeout,
+ "Controller loss timeout after connection loss (in seconds)"),
OPT("hostnqn", 'q', arg_string, opt, hostnqn,
"Host NQN"),
OPT("flow_control", 'F', arg_none, opt, flow_control,
diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8
index d886b60a2545..624a0c93719b 100644
--- a/sbin/nvmecontrol/nvmecontrol.8
+++ b/sbin/nvmecontrol/nvmecontrol.8
@@ -33,7 +33,7 @@
.\"
.\" Author: Jim Harris <jimharris@FreeBSD.org>
.\"
-.Dd April 29, 2025
+.Dd July 9, 2025
.Dt NVMECONTROL 8
.Os
.Sh NAME
@@ -216,6 +216,8 @@
.Op Fl c Ar cntl-id
.Op Fl i Ar queues
.Op Fl k Ar seconds
+.Op Fl l Ar seconds
+.Op Fl r Ar seconds
.Op Fl t Ar transport
.Op Fl q Ar HostNQN
.Op Fl Q Ar entries
@@ -226,6 +228,8 @@
.Op Fl FGg
.Op Fl i Ar queues
.Op Fl k Ar seconds
+.Op Fl l Ar seconds
+.Op Fl r Ar seconds
.Op Fl t Ar transport
.Op Fl q Ar HostNQN
.Op Fl Q Ar entries
@@ -241,6 +245,8 @@
.Op Fl FGg
.Op Fl i Ar queues
.Op Fl k Ar seconds
+.Op Fl l Ar seconds
+.Op Fl r Ar seconds
.Op Fl t Ar transport
.Op Fl q Ar HostNQN
.Op Fl Q Ar entries
@@ -786,6 +792,29 @@ The default is 1.
.It Fl k Ar seconds
Keep Alive timer duration in seconds.
The default is 120.
+.It Fl l Ar seconds
+Controller Loss timer duration in seconds.
+The default is 600.
+.Pp
+This timer starts when an association is lost with a remote I/O controller
+and is cancelled when a new association is established.
+If the timer expires, the controller device is deleted.
+A setting of zero disables this timer.
+.It Fl r Ar seconds
+Reconnect timer duration in seconds.
+The default is 10.
+.Pp
+When an association is lost with a remote I/O controller,
+the controller device will request reconnection via periodic
+.Xr devctl 4
+notifications until either a new association is established or the controller
+device is deleted.
+This timer sets the interval between each
+.Xr devctl 4
+notification.
+Note that the first notification is triggered immediately after an association
+is lost.
+A setting of zero disables this timer.
.It Fl t Ar transport
Transport to use.
The default is
diff --git a/sbin/nvmecontrol/reconnect.c b/sbin/nvmecontrol/reconnect.c
index adf1edac662b..06af40624177 100644
--- a/sbin/nvmecontrol/reconnect.c
+++ b/sbin/nvmecontrol/reconnect.c
@@ -27,6 +27,8 @@ static struct options {
const char *transport;
const char *hostnqn;
uint32_t kato;
+ uint32_t reconnect_delay;
+ uint32_t controller_loss_timeout;
uint16_t num_io_queues;
uint16_t queue_size;
bool data_digests;
@@ -37,6 +39,8 @@ static struct options {
.transport = "tcp",
.hostnqn = NULL,
.kato = NVMF_KATO_DEFAULT / 1000,
+ .reconnect_delay = NVMF_DEFAULT_RECONNECT_DELAY,
+ .controller_loss_timeout = NVMF_DEFAULT_CONTROLLER_LOSS,
.num_io_queues = 1,
.queue_size = 0,
.data_digests = false,
@@ -59,6 +63,7 @@ static int
reconnect_nvm_controller(int fd, const struct nvmf_association_params *aparams,
enum nvmf_trtype trtype, int adrfam, const char *address, const char *port,
uint16_t cntlid, const char *subnqn, const char *hostnqn, uint32_t kato,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout,
u_int num_io_queues, u_int queue_size,
const struct nvme_discovery_log_entry *dle)
{
@@ -88,7 +93,7 @@ reconnect_nvm_controller(int fd, const struct nvmf_association_params *aparams,
}
error = nvmf_reconnect_host(fd, dle, hostnqn, admin, num_io_queues, io,
- &cdata);
+ &cdata, reconnect_delay, controller_loss_timeout);
if (error != 0) {
warnc(error, "Failed to handoff queues to kernel");
free(io);
@@ -137,7 +142,8 @@ reconnect_by_address(int fd, const nvlist_t *rparams, const char *addr)
error = reconnect_nvm_controller(fd, &aparams, trtype, AF_UNSPEC,
address, port, le16toh(dle->cntlid), subnqn, hostnqn,
- opt.kato * 1000, opt.num_io_queues, opt.queue_size, NULL);
+ opt.kato * 1000, opt.reconnect_delay, opt.controller_loss_timeout,
+ opt.num_io_queues, opt.queue_size, NULL);
free(subnqn);
free(tofree);
return (error);
@@ -196,6 +202,8 @@ reconnect_by_params(int fd, const nvlist_t *rparams)
address, port, le16toh(dle->cntlid), dle->subnqn,
nvlist_get_string(rparams, "hostnqn"),
dnvlist_get_number(rparams, "kato", 0),
+ dnvlist_get_number(rparams, "reconnect_delay", 0),
+ dnvlist_get_number(rparams, "controller_loss_timeout", 0),
nvlist_get_number(rparams, "num_io_queues"),
nvlist_get_number(rparams, "io_qsize"), dle);
free(subnqn);
@@ -291,6 +299,11 @@ static const struct opts reconnect_opts[] = {
"Number of entries in each I/O queue"),
OPT("keep-alive-tmo", 'k', arg_uint32, opt, kato,
"Keep Alive timeout (in seconds)"),
+ OPT("reconnect-delay", 'r', arg_uint32, opt, reconnect_delay,
+ "Delay between reconnect attempts after connection loss "
+ "(in seconds)"),
+ OPT("ctrl-loss-tmo", 'l', arg_uint32, opt, controller_loss_timeout,
+ "Controller loss timeout after connection loss (in seconds)"),
OPT("hostnqn", 'q', arg_string, opt, hostnqn,
"Host NQN"),
OPT("flow_control", 'F', arg_none, opt, flow_control,
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index c939b5ae7cce..358fa909fc50 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -95,7 +95,7 @@ static struct file {
int eof_reached;
int lineno;
int errors;
-} *file;
+} *file, *topfile;
struct file *pushfile(const char *, int);
int popfile(void);
int check_file_secrecy(int, const char *);
@@ -367,6 +367,7 @@ static struct node_fairq_opts fairq_opts;
static struct node_state_opt *keep_state_defaults = NULL;
static struct pfctl_watermarks syncookie_opts;
+int validate_range(uint8_t, uint16_t, uint16_t);
int disallow_table(struct node_host *, const char *);
int disallow_urpf_failed(struct node_host *, const char *);
int disallow_alias(struct node_host *, const char *);
@@ -921,7 +922,27 @@ varset : STRING '=' varstring {
}
;
-anchorname : STRING { $$ = $1; }
+anchorname : STRING {
+ if ($1[0] == '\0') {
+ free($1);
+ yyerror("anchor name must not be empty");
+ YYERROR;
+ }
+ if (strlen(pf->anchor->path) + 1 +
+ strlen($1) >= PATH_MAX) {
+ free($1);
+ yyerror("anchor name is longer than %u",
+ PATH_MAX - 1);
+ YYERROR;
+ }
+ if ($1[0] == '_' || strstr($1, "/_") != NULL) {
+ free($1);
+ yyerror("anchor names beginning with '_' "
+ "are reserved for internal use");
+ YYERROR;
+ }
+ $$ = $1;
+ }
| /* empty */ { $$ = NULL; }
;
@@ -938,6 +959,8 @@ pfa_anchor : '{'
struct pfctl_ruleset *rs;
/* stepping into a brace anchor */
+ if (pf->asd >= PFCTL_ANCHOR_STACK_DEPTH)
+ errx(1, "pfa_anchor: anchors too deep");
pf->asd++;
pf->bn++;
@@ -974,13 +997,6 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
YYERROR;
}
- if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
- free($2);
- yyerror("anchor names beginning with '_' "
- "are reserved for internal use");
- YYERROR;
- }
-
pfctl_init_rule(&r);
if (pf->astack[pf->asd + 1]) {
@@ -1162,14 +1178,11 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
}
;
-loadrule : LOAD ANCHOR string FROM string {
+loadrule : LOAD ANCHOR anchorname FROM string {
struct loadanchors *loadanchor;
- if (strlen(pf->anchor->path) + 1 +
- strlen($3) >= MAXPATHLEN) {
- yyerror("anchorname %s too long, max %u\n",
- $3, MAXPATHLEN - 1);
- free($3);
+ if ($3 == NULL) {
+ yyerror("anchor name is missing");
YYERROR;
}
loadanchor = calloc(1, sizeof(struct loadanchors));
@@ -1251,6 +1264,8 @@ etherpfa_anchor : '{'
struct pfctl_eth_ruleset *rs;
/* steping into a brace anchor */
+ if (pf->asd >= PFCTL_ANCHOR_STACK_DEPTH)
+ errx(1, "pfa_anchor: anchors too deep");
pf->asd++;
pf->bn++;
@@ -3217,8 +3232,7 @@ logopts : logopt { $$ = $1; }
logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; }
| MATCHES { $$.log = PF_LOG_MATCHES; $$.logif = 0; }
- | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
- | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
+ | USER { $$.log = PF_LOG_USER; $$.logif = 0; }
| TO string {
const char *errstr;
u_int i;
@@ -3811,9 +3825,14 @@ port_item : portrange {
err(1, "port_item: calloc");
$$->port[0] = $1.a;
$$->port[1] = $1.b;
- if ($1.t)
+ if ($1.t) {
$$->op = PF_OP_RRG;
- else
+ if (validate_range($$->op, $$->port[0],
+ $$->port[1])) {
+ yyerror("invalid port range");
+ YYERROR;
+ }
+ } else
$$->op = PF_OP_EQ;
$$->next = NULL;
$$->tail = $$;
@@ -3830,6 +3849,10 @@ port_item : portrange {
$$->port[0] = $2.a;
$$->port[1] = $2.b;
$$->op = $1;
+ if (validate_range($$->op, $$->port[0], $$->port[1])) {
+ yyerror("invalid port range");
+ YYERROR;
+ }
$$->next = NULL;
$$->tail = $$;
}
@@ -3845,6 +3868,10 @@ port_item : portrange {
$$->port[0] = $1.a;
$$->port[1] = $3.a;
$$->op = $2;
+ if (validate_range($$->op, $$->port[0], $$->port[1])) {
+ yyerror("invalid port range");
+ YYERROR;
+ }
$$->next = NULL;
$$->tail = $$;
}
@@ -3891,7 +3918,7 @@ uid_item : uid {
$$->tail = $$;
}
| unaryop uid {
- if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
yyerror("user unknown requires operator = or "
"!=");
YYERROR;
@@ -3906,7 +3933,7 @@ uid_item : uid {
$$->tail = $$;
}
| uid PORTBINARY uid {
- if ($1 == UID_MAX || $3 == UID_MAX) {
+ if ($1 == -1 || $3 == -1) {
yyerror("user unknown requires operator = or "
"!=");
YYERROR;
@@ -3924,7 +3951,7 @@ uid_item : uid {
uid : STRING {
if (!strcmp($1, "unknown"))
- $$ = UID_MAX;
+ $$ = -1;
else {
uid_t uid;
@@ -3969,7 +3996,7 @@ gid_item : gid {
$$->tail = $$;
}
| unaryop gid {
- if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
yyerror("group unknown requires operator = or "
"!=");
YYERROR;
@@ -3984,7 +4011,7 @@ gid_item : gid {
$$->tail = $$;
}
| gid PORTBINARY gid {
- if ($1 == GID_MAX || $3 == GID_MAX) {
+ if ($1 == -1 || $3 == -1) {
yyerror("group unknown requires operator = or "
"!=");
YYERROR;
@@ -4002,7 +4029,7 @@ gid_item : gid {
gid : STRING {
if (!strcmp($1, "unknown"))
- $$ = GID_MAX;
+ $$ = -1;
else {
gid_t gid;
@@ -5183,6 +5210,19 @@ yyerror(const char *fmt, ...)
}
int
+validate_range(uint8_t op, uint16_t p1, uint16_t p2)
+{
+ uint16_t a = ntohs(p1);
+ uint16_t b = ntohs(p2);
+
+ if ((op == PF_OP_RRG && a > b) || /* 34:12, i.e. none */
+ (op == PF_OP_IRG && a >= b) || /* 34><12, i.e. none */
+ (op == PF_OP_XRG && a > b)) /* 34<>22, i.e. all */
+ return 1;
+ return 0;
+}
+
+int
disallow_table(struct node_host *h, const char *fmt)
{
for (; h != NULL; h = h->next)
@@ -5310,6 +5350,10 @@ filter_consistent(struct pfctl_rule *r, int anchor_call)
"synproxy state or modulate state");
problems++;
}
+ if ((r->keep_state == PF_STATE_SYNPROXY) && (r->direction != PF_IN))
+ fprintf(stderr, "%s:%d: warning: "
+ "synproxy used for inbound rules only, "
+ "ignored for outbound\n", file->name, yylval.lineno);
if (r->rule_flag & PFRULE_AFTO && r->rt) {
if (r->rt != PF_ROUTETO && r->rt != PF_REPLYTO) {
yyerror("dup-to "
@@ -5424,6 +5468,12 @@ process_tabledef(char *name, struct table_opts *opts, int popts)
if (pf->opts & PF_OPT_VERBOSE)
print_tabledef(name, opts->flags, opts->init_addr,
&opts->init_nodes);
+ if (!(pf->opts & PF_OPT_NOACTION) ||
+ (pf->opts & PF_OPT_DUMMYACTION))
+ warn_duplicate_tables(name, pf->anchor->path);
+ else if (pf->opts & PF_OPT_VERBOSE)
+ fprintf(stderr, "%s:%d: skipping duplicate table checks"
+ " for <%s>\n", file->name, yylval.lineno, name);
if (!(pf->opts & PF_OPT_NOACTION) &&
pfctl_define_table(name, opts->flags, opts->init_addr,
pf->anchor->path, &ab, pf->anchor->ruleset.tticket)) {
@@ -5438,7 +5488,7 @@ process_tabledef(char *name, struct table_opts *opts, int popts)
name);
else
yyerror("cannot define table %s: %s", name,
- pfr_strerror(errno));
+ pf_strerror(errno));
goto _error;
}
@@ -5994,8 +6044,14 @@ apply_rdr_ports(struct pfctl_rule *r, struct pfctl_pool *rpool, struct redirspec
if (!rs->rport.b && rs->rport.t) {
rpool->proxy_port[1] = ntohs(rs->rport.a) +
(ntohs(r->dst.port[1]) - ntohs(r->dst.port[0]));
- } else
+ } else {
+ if (validate_range(rs->rport.t, rs->rport.a,
+ rs->rport.b)) {
+ yyerror("invalid rdr-to port range");
+ return (1);
+ }
r->rdr.proxy_port[1] = ntohs(rs->rport.b);
+ }
if (rs->pool_opts.staticport) {
yyerror("the 'static-port' option is only valid with nat rules");
@@ -6723,7 +6779,7 @@ lgetc(int quotec)
if (quotec) {
if ((c = igetc()) == EOF) {
yyerror("reached end of file while parsing quoted string");
- if (popfile() == EOF)
+ if (file == topfile || popfile() == EOF)
return (EOF);
return (quotec);
}
@@ -6751,7 +6807,7 @@ lgetc(int quotec)
return ('\n');
}
while (c == EOF) {
- if (popfile() == EOF)
+ if (file == topfile || popfile() == EOF)
return (EOF);
c = igetc();
}
@@ -6854,7 +6910,8 @@ top:
} else if (c == '\\') {
if ((next = lgetc(quotec)) == EOF)
return (0);
- if (next == quotec || c == ' ' || c == '\t')
+ if (next == quotec || next == ' ' ||
+ next == '\t')
c = next;
else if (next == '\n') {
file->lineno++;
@@ -6917,7 +6974,7 @@ top:
if (c == '-' || isdigit(c)) {
do {
*p++ = c;
- if ((unsigned)(p-buf) >= sizeof(buf)) {
+ if ((size_t)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
@@ -6956,7 +7013,7 @@ nodigits:
if (isalnum(c) || c == ':' || c == '_') {
do {
*p++ = c;
- if ((unsigned)(p-buf) >= sizeof(buf)) {
+ if ((size_t)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
@@ -7048,17 +7105,17 @@ popfile(void)
{
struct file *prev;
- if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
+ if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
prev->errors += file->errors;
- TAILQ_REMOVE(&files, file, entry);
- fclose(file->stream);
- free(file->name);
- free(file->ungetbuf);
- free(file);
- file = prev;
- return (0);
- }
- return (EOF);
+
+ TAILQ_REMOVE(&files, file, entry);
+ fclose(file->stream);
+ free(file->name);
+ free(file->ungetbuf);
+ free(file);
+ file = prev;
+
+ return (file ? 0 : EOF);
}
int
@@ -7081,6 +7138,7 @@ parse_config(char *filename, struct pfctl *xpf)
warn("cannot open the main config file!");
return (-1);
}
+ topfile = file;
yyparse();
errors = file->errors;
@@ -7149,11 +7207,10 @@ pfctl_cmdline_symset(char *s)
if ((val = strrchr(s, '=')) == NULL)
return (-1);
- if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
+ sym = strndup(s, val - s);
+ if (sym == NULL)
err(1, "%s: malloc", __func__);
- strlcpy(sym, s, strlen(s) - strlen(val) + 1);
-
ret = symset(sym, val + 1, 1);
free(sym);
@@ -7181,19 +7238,11 @@ mv_rules(struct pfctl_ruleset *src, struct pfctl_ruleset *dst)
struct pfctl_rule *r;
for (i = 0; i < PF_RULESET_MAX; ++i) {
- while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
- != NULL) {
- TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
- TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
+ TAILQ_FOREACH(r, src->rules[i].active.ptr, entries)
dst->anchor->match++;
- }
+ TAILQ_CONCAT(dst->rules[i].active.ptr, src->rules[i].active.ptr, entries);
src->anchor->match = 0;
- while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
- != NULL) {
- TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
- TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
- r, entries);
- }
+ TAILQ_CONCAT(dst->rules[i].inactive.ptr, src->rules[i].inactive.ptr, entries);
}
}
diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8
index 5238c53f709d..f582c6301124 100644
--- a/sbin/pfctl/pfctl.8
+++ b/sbin/pfctl/pfctl.8
@@ -24,7 +24,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd June 30, 2025
+.Dd July 7, 2025
.Dt PFCTL 8
.Os
.Sh NAME
@@ -186,6 +186,13 @@ as the anchor name:
.Bd -literal -offset indent
# pfctl -a '*' -sr
.Ed
+.Pp
+To flush all rulesets and tables recursively, specify only
+.Sq *
+as the anchor name:
+.Bd -literal -offset indent
+# pfctl -a '*' -Fa
+.Ed
.It Fl D Ar macro Ns = Ns Ar value
Define
.Ar macro
@@ -223,9 +230,27 @@ Flush the filter information (statistics that are not bound to rules).
Flush the tables.
.It Fl F Cm osfp
Flush the passive operating system fingerprints.
+.It Fl F Cm Reset
+Reset limits, timeouts and other options back to default settings.
+See the OPTIONS section in
+.Xr pf.conf 5
+for details.
.It Fl F Cm all
Flush all of the above.
.El
+.Pp
+If
+.Fl a
+is specified as well and
+.Ar anchor
+is terminated with a
+.Sq *
+character,
+.Cm rules ,
+.Cm Tables
+and
+.Cm all
+flush the given anchor recursively.
.It Fl f Ar file
Load the rules contained in
.Ar file .
@@ -401,7 +426,11 @@ Only print errors and warnings.
Load only the filter rules present in the rule file.
Other rules and options are ignored.
.It Fl r
-Perform reverse DNS lookups on states when displaying them.
+Perform reverse DNS lookups on states and tables when displaying them.
+.Fl N
+and
+.Fl r
+are mutually exclusive.
.It Fl s Ar modifier
Show the filter parameters specified by
.Ar modifier
@@ -458,7 +487,10 @@ Show the contents of the source tracking table.
Show filter information (statistics and counters).
When used together with
.Fl v ,
-source tracking statistics are also shown.
+source tracking statistics, the firewall's 32-bit hostid number and the
+main ruleset's MD5 checksum for use with
+.Xr pfsync 4
+are also shown.
.It Fl s Cm Running
Show the running status and provide a non-zero exit status when disabled.
.It Fl s Cm labels
@@ -474,7 +506,7 @@ Show the list of tables.
.It Fl s Cm osfp
Show the list of operating system fingerprints.
.It Fl s Cm Interfaces
-Show the list of interfaces and interface drivers available to PF.
+Show the list of interfaces and interface groups available to PF.
When used together with
.Fl v ,
it additionally lists which interfaces have skip rules activated.
@@ -544,7 +576,7 @@ Kill a table.
Flush all addresses of a table.
.It Fl T Cm add
Add one or more addresses in a table.
-Automatically create a nonexisting table.
+Automatically create a persistent table if it does not exist.
.It Fl T Cm delete
Delete one or more addresses from a table.
.It Fl T Cm expire Ar number
@@ -556,7 +588,7 @@ For entries which have never had their statistics cleared,
refers to the time they were added to the table.
.It Fl T Cm replace
Replace the addresses of the table.
-Automatically create a nonexisting table.
+Automatically create a persistent table if it does not exist.
.It Fl T Cm show
Show the content (addresses) of a table.
.It Fl T Cm test
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 8c6497b4d1ee..2015e0a09549 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -59,6 +59,8 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <stdarg.h>
+#include <libgen.h>
#include "pfctl_parser.h"
#include "pfctl.h"
@@ -72,13 +74,14 @@ void pfctl_check_skip_ifaces(char *);
void pfctl_adjust_skip_ifaces(struct pfctl *);
void pfctl_clear_interface_flags(int, int);
void pfctl_flush_eth_rules(int, int, char *);
-void pfctl_flush_rules(int, int, char *);
+int pfctl_flush_rules(int, int, char *);
void pfctl_flush_nat(int, int, char *);
int pfctl_clear_altq(int, int);
void pfctl_clear_src_nodes(int, int);
void pfctl_clear_iface_states(int, const char *, int);
-void pfctl_addrprefix(char *, struct pf_addr *);
-void pfctl_kill_src_nodes(int, const char *, int);
+struct addrinfo *
+ pfctl_addrprefix(char *, struct pf_addr *, int);
+void pfctl_kill_src_nodes(int, int);
void pfctl_net_kill_states(int, const char *, int);
void pfctl_gateway_kill_states(int, const char *, int);
void pfctl_label_kill_states(int, const char *, int);
@@ -122,6 +125,18 @@ int pfctl_load_ruleset(struct pfctl *, char *,
struct pfctl_ruleset *, int, int);
int pfctl_load_rule(struct pfctl *, char *, struct pfctl_rule *, int);
const char *pfctl_lookup_option(char *, const char * const *);
+void pfctl_reset(int, int);
+int pfctl_walk_show(int, struct pfioc_ruleset *, void *);
+int pfctl_walk_get(int, struct pfioc_ruleset *, void *);
+int pfctl_walk_anchors(int, int, const char *,
+ int(*)(int, struct pfioc_ruleset *, void *), void *);
+struct pfr_anchors *
+ pfctl_get_anchors(int, const char *, int);
+int pfctl_recurse(int, int, const char *,
+ int(*)(int, int, struct pfr_anchoritem *));
+int pfctl_call_clearrules(int, int, struct pfr_anchoritem *);
+int pfctl_call_cleartables(int, int, struct pfr_anchoritem *);
+int pfctl_call_clearanchors(int, int, struct pfr_anchoritem *);
static struct pfctl_anchor_global pf_anchors;
struct pfctl_anchor pf_main_anchor;
@@ -149,6 +164,7 @@ int dev = -1;
struct pfctl_handle *pfh = NULL;
static int first_title = 1;
static int labels = 0;
+static int exit_val = 0;
#define INDENT(d, o) do { \
if (o) { \
@@ -230,7 +246,7 @@ static const struct {
static const char * const clearopt_list[] = {
"nat", "queue", "rules", "Sources",
"states", "info", "Tables", "osfp", "all",
- "ethernet", NULL
+ "ethernet", "Reset", NULL
};
static const char * const showopt_list[] = {
@@ -267,6 +283,40 @@ usage(void)
exit(1);
}
+void
+pfctl_err(int opts, int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if ((opts & PF_OPT_IGNFAIL) == 0)
+ verr(eval, fmt, ap);
+ else
+ vwarn(fmt, ap);
+
+ va_end(ap);
+
+ exit_val = eval;
+}
+
+void
+pfctl_errx(int opts, int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if ((opts & PF_OPT_IGNFAIL) == 0)
+ verrx(eval, fmt, ap);
+ else
+ vwarnx(fmt, ap);
+
+ va_end(ap);
+
+ exit_val = eval;
+}
+
/*
* Cache protocol number to name translations.
*
@@ -359,7 +409,7 @@ pfctl_clear_stats(struct pfctl_handle *h, int opts)
{
int ret;
if ((ret = pfctl_clear_status(h)) != 0)
- errc(1, ret, "DIOCCLRSTATUS");
+ pfctl_err(opts, 1, "DIOCCLRSTATUS");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "pf: statistics cleared\n");
}
@@ -467,16 +517,19 @@ pfctl_flush_eth_rules(int dev, int opts, char *anchorname)
fprintf(stderr, "Ethernet rules cleared\n");
}
-void
+int
pfctl_flush_rules(int dev, int opts, char *anchorname)
{
int ret;
ret = pfctl_clear_rules(dev, anchorname);
- if (ret != 0)
- err(1, "pfctl_clear_rules");
- if ((opts & PF_OPT_QUIET) == 0)
+ if (ret != 0) {
+ pfctl_err(opts, 1, "%s", __func__);
+ return (1);
+ } else if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "rules cleared\n");
+
+ return (0);
}
void
@@ -513,7 +566,7 @@ void
pfctl_clear_src_nodes(int dev, int opts)
{
if (ioctl(dev, DIOCCLRSRCNODES))
- err(1, "DIOCCLRSRCNODES");
+ pfctl_err(opts, 1, "DIOCCLRSRCNODES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "source tracking entries cleared\n");
}
@@ -528,46 +581,47 @@ pfctl_clear_iface_states(int dev, const char *iface, int opts)
memset(&kill, 0, sizeof(kill));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
if ((ret = pfctl_clear_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCCLRSTATES");
+ pfctl_err(opts, 1, "DIOCCLRSTATUS");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "%d states cleared\n", killed);
}
-void
-pfctl_addrprefix(char *addr, struct pf_addr *mask)
+struct addrinfo *
+pfctl_addrprefix(char *addr, struct pf_addr *mask, int numeric)
{
char *p;
const char *errstr;
int prefix, ret_ga, q, r;
struct addrinfo hints, *res;
- if ((p = strchr(addr, '/')) == NULL)
- return;
-
- *p++ = '\0';
- prefix = strtonum(p, 0, 128, &errstr);
- if (errstr)
- errx(1, "prefix is %s: %s", errstr, p);
-
bzero(&hints, sizeof(hints));
- /* prefix only with numeric addresses */
- hints.ai_flags |= AI_NUMERICHOST;
+ hints.ai_socktype = SOCK_DGRAM; /* dummy */
+ if (numeric)
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if ((p = strchr(addr, '/')) != NULL) {
+ *p++ = '\0';
+ /* prefix only with numeric addresses */
+ hints.ai_flags |= AI_NUMERICHOST;
+ }
if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
/* NOTREACHED */
}
- if (res->ai_family == AF_INET && prefix > 32)
- errx(1, "prefix too long for AF_INET");
- else if (res->ai_family == AF_INET6 && prefix > 128)
- errx(1, "prefix too long for AF_INET6");
+ if (p == NULL)
+ return (res);
+
+ prefix = strtonum(p, 0, res->ai_family == AF_INET6 ? 128 : 32, &errstr);
+ if (errstr)
+ errx(1, "prefix is %s: %s", errstr, p);
q = prefix >> 3;
r = prefix & 7;
@@ -586,17 +640,17 @@ pfctl_addrprefix(char *addr, struct pf_addr *mask)
(0xff00 >> r) & 0xff;
break;
}
- freeaddrinfo(res);
+
+ return (res);
}
void
-pfctl_kill_src_nodes(int dev, const char *iface, int opts)
+pfctl_kill_src_nodes(int dev, int opts)
{
struct pfioc_src_node_kill psnk;
struct addrinfo *res[2], *resp[2];
struct sockaddr last_src, last_dst;
int killed, sources, dests;
- int ret_ga;
killed = sources = dests = 0;
@@ -606,12 +660,9 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts)
memset(&last_src, 0xff, sizeof(last_src));
memset(&last_dst, 0xff, sizeof(last_dst));
- pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
+ res[0] = pfctl_addrprefix(src_node_kill[0],
+ &psnk.psnk_src.addr.v.a.mask, (opts & PF_OPT_NODNS));
- if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
- errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
- /* NOTREACHED */
- }
for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
if (resp[0]->ai_addr == NULL)
continue;
@@ -623,29 +674,16 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts)
psnk.psnk_af = resp[0]->ai_family;
sources++;
- if (psnk.psnk_af == AF_INET)
- psnk.psnk_src.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
- else if (psnk.psnk_af == AF_INET6)
- psnk.psnk_src.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp[0]->ai_addr)->
- sin6_addr;
- else
- errx(1, "Unknown address family %d", psnk.psnk_af);
+ copy_satopfaddr(&psnk.psnk_src.addr.v.a.addr, resp[0]->ai_addr);
if (src_node_killers > 1) {
dests = 0;
memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
sizeof(psnk.psnk_dst.addr.v.a.mask));
memset(&last_dst, 0xff, sizeof(last_dst));
- pfctl_addrprefix(src_node_kill[1],
- &psnk.psnk_dst.addr.v.a.mask);
- if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
- &res[1]))) {
- errx(1, "getaddrinfo: %s",
- gai_strerror(ret_ga));
- /* NOTREACHED */
- }
+ res[1] = pfctl_addrprefix(src_node_kill[1],
+ &psnk.psnk_dst.addr.v.a.mask,
+ (opts & PF_OPT_NODNS));
for (resp[1] = res[1]; resp[1];
resp[1] = resp[1]->ai_next) {
if (resp[1]->ai_addr == NULL)
@@ -660,18 +698,8 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts)
dests++;
- if (psnk.psnk_af == AF_INET)
- psnk.psnk_dst.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp[1]->
- ai_addr)->sin_addr;
- else if (psnk.psnk_af == AF_INET6)
- psnk.psnk_dst.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp[1]->
- ai_addr)->sin6_addr;
- else
- errx(1, "Unknown address family %d",
- psnk.psnk_af);
-
+ copy_satopfaddr(&psnk.psnk_src.addr.v.a.addr,
+ resp[1]->ai_addr);
if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
err(1, "DIOCKILLSRCNODES");
killed += psnk.psnk_killed;
@@ -699,7 +727,7 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
struct sockaddr last_src, last_dst;
unsigned int newkilled;
int killed, sources, dests;
- int ret_ga, ret;
+ int ret;
killed = sources = dests = 0;
@@ -710,7 +738,7 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
memset(&last_dst, 0xff, sizeof(last_dst));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (state_killers == 2 && (strcmp(state_kill[0], "nat") == 0)) {
kill.nat = true;
@@ -718,15 +746,12 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
state_killers = 1;
}
- pfctl_addrprefix(state_kill[0], &kill.src.addr.v.a.mask);
+ res[0] = pfctl_addrprefix(state_kill[0],
+ &kill.src.addr.v.a.mask, (opts & PF_OPT_NODNS));
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
- if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
- errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
- /* NOTREACHED */
- }
for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
if (resp[0]->ai_addr == NULL)
continue;
@@ -738,29 +763,16 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
kill.af = resp[0]->ai_family;
sources++;
- if (kill.af == AF_INET)
- kill.src.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
- else if (kill.af == AF_INET6)
- kill.src.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp[0]->ai_addr)->
- sin6_addr;
- else
- errx(1, "Unknown address family %d", kill.af);
+ copy_satopfaddr(&kill.src.addr.v.a.addr, resp[0]->ai_addr);
if (state_killers > 1) {
dests = 0;
memset(&kill.dst.addr.v.a.mask, 0xff,
sizeof(kill.dst.addr.v.a.mask));
memset(&last_dst, 0xff, sizeof(last_dst));
- pfctl_addrprefix(state_kill[1],
- &kill.dst.addr.v.a.mask);
- if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
- &res[1]))) {
- errx(1, "getaddrinfo: %s",
- gai_strerror(ret_ga));
- /* NOTREACHED */
- }
+ res[1] = pfctl_addrprefix(state_kill[1],
+ &kill.dst.addr.v.a.mask,
+ (opts & PF_OPT_NODNS));
for (resp[1] = res[1]; resp[1];
resp[1] = resp[1]->ai_next) {
if (resp[1]->ai_addr == NULL)
@@ -775,26 +787,17 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
dests++;
- if (kill.af == AF_INET)
- kill.dst.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp[1]->
- ai_addr)->sin_addr;
- else if (kill.af == AF_INET6)
- kill.dst.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp[1]->
- ai_addr)->sin6_addr;
- else
- errx(1, "Unknown address family %d",
- kill.af);
+ copy_satopfaddr(&kill.src.addr.v.a.addr,
+ resp[1]->ai_addr);
if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
killed += newkilled;
}
freeaddrinfo(res[1]);
} else {
if ((ret = pfctl_kill_states_h(pfh, &kill, &newkilled)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
killed += newkilled;
}
}
@@ -814,7 +817,6 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts)
struct sockaddr last_src;
unsigned int newkilled;
int killed = 0;
- int ret_ga;
if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
warnx("no gateway specified");
@@ -827,17 +829,14 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts)
memset(&last_src, 0xff, sizeof(last_src));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
- pfctl_addrprefix(state_kill[1], &kill.rt_addr.addr.v.a.mask);
+ res = pfctl_addrprefix(state_kill[1], &kill.rt_addr.addr.v.a.mask,
+ (opts & PF_OPT_NODNS));
- if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res))) {
- errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
- /* NOTREACHED */
- }
for (resp = res; resp; resp = resp->ai_next) {
if (resp->ai_addr == NULL)
continue;
@@ -848,18 +847,10 @@ pfctl_gateway_kill_states(int dev, const char *iface, int opts)
kill.af = resp->ai_family;
- if (kill.af == AF_INET)
- kill.rt_addr.addr.v.a.addr.v4 =
- ((struct sockaddr_in *)resp->ai_addr)->sin_addr;
- else if (kill.af == AF_INET6)
- kill.rt_addr.addr.v.a.addr.v6 =
- ((struct sockaddr_in6 *)resp->ai_addr)->
- sin6_addr;
- else
- errx(1, "Unknown address family %d", kill.af);
-
+ copy_satopfaddr(&kill.rt_addr.addr.v.a.addr,
+ resp->ai_addr);
if (pfctl_kill_states_h(pfh, &kill, &newkilled))
- err(1, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
killed += newkilled;
}
@@ -883,7 +874,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts)
memset(&kill, 0, sizeof(kill));
if (iface != NULL && strlcpy(kill.ifname, iface,
sizeof(kill.ifname)) >= sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
if (opts & PF_OPT_KILLMATCH)
kill.kill_match = true;
@@ -893,7 +884,7 @@ pfctl_label_kill_states(int dev, const char *iface, int opts)
errx(1, "label too long: %s", state_kill[1]);
if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "killed %d states\n", killed);
@@ -931,7 +922,7 @@ pfctl_id_kill_states(int dev, const char *iface, int opts)
}
if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "killed %d states\n", killed);
@@ -955,7 +946,7 @@ pfctl_key_kill_states(int dev, const char *iface, int opts)
if (iface != NULL &&
strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >=
sizeof(kill.ifname))
- errx(1, "invalid interface: %s", iface);
+ pfctl_errx(opts, 1, "invalid interface: %s", iface);
s = strdup(state_kill[1]);
if (!s)
@@ -991,7 +982,7 @@ pfctl_key_kill_states(int dev, const char *iface, int opts)
errx(1, "invalid host: %s", tokens[didx]);
if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0)
- errc(1, ret, "DIOCKILLSTATES");
+ pfctl_errx(opts, 1, "DIOCKILLSTATES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "killed %d states\n", killed);
@@ -1002,8 +993,6 @@ pfctl_parse_host(char *str, struct pf_rule_addr *addr)
{
char *s = NULL, *sbs, *sbe;
struct addrinfo hints, *ai;
- struct sockaddr_in *sin4;
- struct sockaddr_in6 *sin6;
s = strdup(str);
if (!s)
@@ -1026,19 +1015,10 @@ pfctl_parse_host(char *str, struct pf_rule_addr *addr)
if (getaddrinfo(s, sbs, &hints, &ai) != 0)
goto error;
- switch (ai->ai_family) {
- case AF_INET:
- sin4 = (struct sockaddr_in *)ai->ai_addr;
- addr->addr.v.a.addr.v4 = sin4->sin_addr;
- addr->port[0] = sin4->sin_port;
- break;
-
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *)ai->ai_addr;
- addr->addr.v.a.addr.v6 = sin6->sin6_addr;
- addr->port[0] = sin6->sin6_port;
- break;
- }
+ copy_satopfaddr(&addr->addr.v.a.addr, ai->ai_addr);
+ addr->port[0] = ai->ai_family == AF_INET6 ?
+ ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port :
+ ((struct sockaddr_in *)ai->ai_addr)->sin_port;
freeaddrinfo(ai);
free(s);
@@ -1360,17 +1340,12 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
u_int32_t mnr, nr;
memset(&prs, 0, sizeof(prs));
- if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0) {
- if (ret == EINVAL)
- fprintf(stderr, "Anchor '%s' "
- "not found.\n", anchorname);
- else
- errc(1, ret, "DIOCGETRULESETS");
- }
+ if ((ret = pfctl_get_rulesets(pfh, npath, &mnr)) != 0)
+ errx(1, "%s", pf_strerror(ret));
for (nr = 0; nr < mnr; ++nr) {
if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0)
- errc(1, ret, "DIOCGETRULESET");
+ errx(1, "%s", pf_strerror(ret));
INDENT(depth, !(opts & PF_OPT_VERBOSE));
printf("anchor \"%s\" all {\n", prs.name);
pfctl_show_rules(dev, npath, opts,
@@ -1385,14 +1360,14 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
if (opts & PF_OPT_SHOWALL) {
ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path);
if (ret != 0) {
- warnc(ret, "DIOCGETRULES");
+ warnx("%s", pf_strerror(ret));
goto error;
}
header++;
}
ret = pfctl_get_rules_info_h(pfh, &ri, PF_SCRUB, path);
if (ret != 0) {
- warnc(ret, "DIOCGETRULES");
+ warnx("%s", pf_strerror(ret));
goto error;
}
if (opts & PF_OPT_SHOWALL) {
@@ -1585,12 +1560,12 @@ pfctl_show_nat(int dev, const char *path, int opts, char *anchorname, int depth,
fprintf(stderr, "NAT anchor '%s' "
"not found.\n", anchorname);
else
- errc(1, ret, "DIOCGETRULESETS");
+ errx(1, "%s", pf_strerror(ret));
}
for (nr = 0; nr < mnr; ++nr) {
if ((ret = pfctl_get_ruleset(pfh, npath, nr, &prs)) != 0)
- errc(1, ret, "DIOCGETRULESET");
+ errx(1, "%s", pf_strerror(ret));
INDENT(depth, !(opts & PF_OPT_VERBOSE));
printf("nat-anchor \"%s\" all {\n", prs.name);
pfctl_show_nat(dev, npath, opts,
@@ -1703,7 +1678,7 @@ pfctl_show_states(int dev, const char *iface, int opts)
struct pfctl_state_filter filter = {};
if (iface != NULL)
- strncpy(filter.ifname, iface, IFNAMSIZ);
+ strlcpy(filter.ifname, iface, IFNAMSIZ);
arg.opts = opts;
arg.dotitle = opts & PF_OPT_SHOWALL;
@@ -2109,13 +2084,12 @@ pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs,
if ((pf->opts & PF_OPT_NOACTION) == 0 &&
(error = pfctl_ruleset_trans(pf,
path, rs->anchor, false))) {
- printf("pfctl_load_rulesets: "
- "pfctl_ruleset_trans %d\n", error);
+ printf("%s: "
+ "pfctl_ruleset_trans %d\n", __func__, error);
goto error;
}
} else if (pf->opts & PF_OPT_VERBOSE)
printf("\n");
-
}
if (pf->optimize && rs_num == PF_RULESET_FILTER)
@@ -2877,7 +2851,7 @@ pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
if ((pf->opts & PF_OPT_NOACTION) == 0) {
if (how == 0) {
if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
- err(1, "DIOCCLRIFFLAG");
+ pfctl_err(pf->opts, 1, "DIOCCLRIFFLAG");
} else {
if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
err(1, "DIOCSETIFFLAG");
@@ -2936,43 +2910,178 @@ pfctl_test_altqsupport(int dev, int opts)
}
int
-pfctl_show_anchors(int dev, int opts, char *anchorname)
+pfctl_walk_show(int opts, struct pfioc_ruleset *pr, void *warg)
+{
+ if (pr->path[0]) {
+ if (pr->path[0] != '_' || (opts & PF_OPT_VERBOSE))
+ printf(" %s/%s\n", pr->path, pr->name);
+ } else if (pr->name[0] != '_' || (opts & PF_OPT_VERBOSE))
+ printf(" %s\n", pr->name);
+
+ return (0);
+}
+
+int
+pfctl_walk_get(int opts, struct pfioc_ruleset *pr, void *warg)
+{
+ struct pfr_anchoritem *pfra;
+ struct pfr_anchors *anchors;
+ int e;
+
+ anchors = (struct pfr_anchors *)warg;
+
+ pfra = malloc(sizeof(*pfra));
+ if (pfra == NULL)
+ err(1, "%s", __func__);
+
+ if (pr->path[0])
+ e = asprintf(&pfra->pfra_anchorname, "%s/%s", pr->path,
+ pr->name);
+ else
+ e = asprintf(&pfra->pfra_anchorname, "%s", pr->name);
+
+ if (e == -1)
+ err(1, "%s", __func__);
+
+ SLIST_INSERT_HEAD(anchors, pfra, pfra_sle);
+
+ return (0);
+}
+
+int
+pfctl_walk_anchors(int dev, int opts, const char *anchor,
+ int(walkf)(int, struct pfioc_ruleset *, void *), void *warg)
{
struct pfioc_ruleset pr;
u_int32_t mnr, nr;
int ret;
memset(&pr, 0, sizeof(pr));
- if ((ret = pfctl_get_rulesets(pfh, anchorname, &mnr)) != 0) {
- if (ret == EINVAL)
- fprintf(stderr, "Anchor '%s' not found.\n",
- anchorname);
- else
- errc(1, ret, "DIOCGETRULESETS");
- return (-1);
- }
+ if ((ret = pfctl_get_rulesets(pfh, anchor, &mnr)) != 0)
+ errx(1, "%s", pf_strerror(ret));
for (nr = 0; nr < mnr; ++nr) {
char sub[MAXPATHLEN];
- if ((ret = pfctl_get_ruleset(pfh, anchorname, nr, &pr)) != 0)
+ if ((ret = pfctl_get_ruleset(pfh, anchor, nr, &pr)) != 0)
errc(1, ret, "DIOCGETRULESET");
if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
continue;
- sub[0] = 0;
- if (pr.path[0]) {
- strlcat(sub, pr.path, sizeof(sub));
- strlcat(sub, "/", sizeof(sub));
- }
- strlcat(sub, pr.name, sizeof(sub));
- if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
- printf(" %s\n", sub);
- if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
+ sub[0] = '\0';
+ if (walkf(opts, &pr, warg))
+ return (-1);
+
+ if (pr.path[0])
+ snprintf(sub, sizeof(sub), "%s/%s", pr.path, pr.name);
+ else
+ snprintf(sub, sizeof(sub), "%s", pr.name);
+ if (pfctl_walk_anchors(dev, opts, sub, walkf, warg))
return (-1);
}
return (0);
}
int
+pfctl_show_anchors(int dev, int opts, char *anchor)
+{
+ return (
+ pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_show, NULL));
+}
+
+struct pfr_anchors *
+pfctl_get_anchors(int dev, const char *anchor, int opts)
+{
+ struct pfioc_ruleset pr;
+ static struct pfr_anchors anchors;
+ char anchorbuf[PATH_MAX];
+ char *n;
+
+ SLIST_INIT(&anchors);
+
+ memset(&pr, 0, sizeof(pr));
+ if (*anchor != '\0') {
+ strlcpy(anchorbuf, anchor, sizeof(anchorbuf));
+ n = dirname(anchorbuf);
+ if (n[0] != '.' && n[1] != '\0')
+ strlcpy(pr.path, n, sizeof(pr.path));
+ strlcpy(anchorbuf, anchor, sizeof(anchorbuf));
+ n = basename(anchorbuf);
+ if (n != NULL)
+ strlcpy(pr.name, n, sizeof(pr.name));
+ }
+
+ /* insert a root anchor first. */
+ pfctl_walk_get(opts, &pr, &anchors);
+
+ if (pfctl_walk_anchors(dev, opts, anchor, pfctl_walk_get, &anchors))
+ errx(1, "%s failed to retrieve list of anchors, can't continue",
+ __func__);
+
+ return (&anchors);
+}
+
+int
+pfctl_call_cleartables(int dev, int opts, struct pfr_anchoritem *pfra)
+{
+ /*
+ * PF_OPT_QUIET makes pfctl_clear_tables() to stop printing number of
+ * tables cleared for given anchor.
+ */
+ opts |= PF_OPT_QUIET;
+ return ((pfctl_do_clear_tables(pfra->pfra_anchorname, opts) == -1) ?
+ 1 : 0);
+}
+
+int
+pfctl_call_clearrules(int dev, int opts, struct pfr_anchoritem *pfra)
+{
+ /*
+ * PF_OPT_QUIET makes pfctl_clear_rules() to stop printing a 'rules
+ * cleared' message for every anchor it deletes.
+ */
+ opts |= PF_OPT_QUIET;
+ return (pfctl_flush_rules(dev, opts, pfra->pfra_anchorname));
+}
+
+int
+pfctl_call_clearanchors(int dev, int opts, struct pfr_anchoritem *pfra)
+{
+ int rv = 0;
+
+ rv |= pfctl_call_cleartables(dev, opts, pfra);
+ rv |= pfctl_call_clearrules(dev, opts, pfra);
+
+ return (rv);
+}
+
+int
+pfctl_recurse(int dev, int opts, const char *anchorname,
+ int(*walkf)(int, int, struct pfr_anchoritem *))
+{
+ int rv = 0;
+ struct pfr_anchors *anchors;
+ struct pfr_anchoritem *pfra, *pfra_save;
+
+ anchors = pfctl_get_anchors(dev, anchorname, opts);
+ /*
+ * While traversing the list, pfctl_clear_*() must always return
+ * so that failures on one anchor do not prevent clearing others.
+ */
+ opts |= PF_OPT_IGNFAIL;
+ printf("Removing:\n");
+ SLIST_FOREACH_SAFE(pfra, anchors, pfra_sle, pfra_save) {
+ printf(" %s\n",
+ (*pfra->pfra_anchorname == '\0') ? "/" :
+ pfra->pfra_anchorname);
+ rv |= walkf(dev, opts, pfra);
+ SLIST_REMOVE(anchors, pfra, pfr_anchoritem, pfra_sle);
+ free(pfra->pfra_anchorname);
+ free(pfra);
+ }
+
+ return (rv);
+}
+
+int
pfctl_show_eth_anchors(int dev, int opts, char *anchorname)
{
struct pfctl_eth_rulesets_info ri;
@@ -3020,10 +3129,48 @@ pfctl_lookup_option(char *cmd, const char * const *list)
return (NULL);
}
+void
+pfctl_reset(int dev, int opts)
+{
+ struct pfctl pf;
+ struct pfr_buffer t;
+ int i;
+
+ pf.dev = dev;
+ pf.h = pfh;
+ pfctl_init_options(&pf);
+
+ /* Force reset upon pfctl_load_options() */
+ pf.debug_set = 1;
+ pf.reass_set = 1;
+ pf.syncookieswat_set = 1;
+ pf.ifname = strdup("none");
+ if (pf.ifname == NULL)
+ err(1, "%s: strdup", __func__);
+ pf.ifname_set = 1;
+
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_trans(dev, &t, DIOCXBEGIN, 0))
+ err(1, "%s: DIOCXBEGIN", __func__);
+
+ for (i = 0; pf_limits[i].name; i++)
+ pf.limit_set[pf_limits[i].index] = 1;
+
+ for (i = 0; pf_timeouts[i].name; i++)
+ pf.timeout_set[pf_timeouts[i].timeout] = 1;
+
+ pfctl_load_options(&pf);
+
+ if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "%s: DIOCXCOMMIT", __func__);
+
+ pfctl_clear_interface_flags(dev, opts);
+}
+
int
main(int argc, char *argv[])
{
- int error = 0;
int ch;
int mode = O_RDONLY;
int opts = 0;
@@ -3175,6 +3322,12 @@ main(int argc, char *argv[])
}
}
+ if ((opts & PF_OPT_NODNS) && (opts & PF_OPT_USEDNS))
+ errx(1, "-N and -r are mutually exclusive");
+
+ if ((tblcmdopt == NULL) ^ (tableopt == NULL))
+ usage();
+
if (tblcmdopt != NULL) {
argc -= optind;
argv += optind;
@@ -3196,6 +3349,8 @@ main(int argc, char *argv[])
if (anchoropt != NULL) {
int len = strlen(anchoropt);
+ if (anchoropt[0] == '\0')
+ errx(1, "anchor name must not be empty");
if (mode == O_RDONLY && showopt == NULL && tblcmdopt == NULL) {
warnx("anchors apply to -f, -F, -s, and -T only");
usage();
@@ -3243,7 +3398,7 @@ main(int argc, char *argv[])
if (opts & PF_OPT_DISABLE)
if (pfctl_disable(dev, opts))
- error = 1;
+ exit_val = 1;
if ((path = calloc(1, MAXPATHLEN)) == NULL)
errx(1, "%s: calloc", __func__);
@@ -3284,7 +3439,7 @@ main(int argc, char *argv[])
pfctl_show_status(dev, opts);
break;
case 'R':
- error = pfctl_show_running(dev);
+ exit_val = pfctl_show_running(dev);
break;
case 't':
pfctl_show_timeouts(dev, opts);
@@ -3304,12 +3459,14 @@ main(int argc, char *argv[])
0);
pfctl_show_nat(dev, path, opts, anchorname, 0, 0);
- pfctl_show_rules(dev, path, opts, 0, anchorname, 0, 0);
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
+ anchorname, 0, 0);
pfctl_show_altq(dev, ifaceopt, opts, 0);
pfctl_show_states(dev, ifaceopt, opts);
pfctl_show_src_nodes(dev, opts);
pfctl_show_status(dev, opts);
- pfctl_show_rules(dev, path, opts, 1, anchorname, 0, 0);
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
+ anchorname, 0, 0);
pfctl_show_timeouts(dev, opts);
pfctl_show_limits(dev, opts);
pfctl_show_tables(anchorname, opts);
@@ -3344,7 +3501,11 @@ main(int argc, char *argv[])
pfctl_flush_eth_rules(dev, opts, anchorname);
break;
case 'r':
- pfctl_flush_rules(dev, opts, anchorname);
+ if (opts & PF_OPT_RECURSE)
+ pfctl_recurse(dev, opts, anchorname,
+ pfctl_call_clearrules);
+ else
+ pfctl_flush_rules(dev, opts, anchorname);
break;
case 'n':
pfctl_flush_nat(dev, opts, anchorname);
@@ -3362,24 +3523,42 @@ main(int argc, char *argv[])
pfctl_clear_stats(pfh, opts);
break;
case 'a':
+ if (ifaceopt) {
+ warnx("don't specify an interface with -Fall");
+ usage();
+ /* NOTREACHED */
+ }
pfctl_flush_eth_rules(dev, opts, anchorname);
pfctl_flush_rules(dev, opts, anchorname);
pfctl_flush_nat(dev, opts, anchorname);
- pfctl_do_clear_tables(anchorname, opts);
+ if (opts & PF_OPT_RECURSE)
+ pfctl_recurse(dev, opts, anchorname,
+ pfctl_call_clearanchors);
+ else {
+ pfctl_do_clear_tables(anchorname, opts);
+ pfctl_flush_rules(dev, opts, anchorname);
+ }
if (!*anchorname) {
pfctl_clear_altq(dev, opts);
pfctl_clear_iface_states(dev, ifaceopt, opts);
pfctl_clear_src_nodes(dev, opts);
pfctl_clear_stats(pfh, opts);
pfctl_clear_fingerprints(dev, opts);
- pfctl_clear_interface_flags(dev, opts);
+ pfctl_reset(dev, opts);
}
break;
case 'o':
pfctl_clear_fingerprints(dev, opts);
break;
case 'T':
- pfctl_do_clear_tables(anchorname, opts);
+ if ((opts & PF_OPT_RECURSE) == 0)
+ pfctl_do_clear_tables(anchorname, opts);
+ else
+ pfctl_recurse(dev, opts, anchorname,
+ pfctl_call_cleartables);
+ break;
+ case 'R':
+ pfctl_reset(dev, opts);
break;
}
}
@@ -3397,10 +3576,10 @@ main(int argc, char *argv[])
}
if (src_node_killers)
- pfctl_kill_src_nodes(dev, ifaceopt, opts);
+ pfctl_kill_src_nodes(dev, opts);
if (tblcmdopt != NULL) {
- error = pfctl_command_tables(argc, argv, tableopt,
+ exit_val = pfctl_table(argc, argv, tableopt,
tblcmdopt, rulesopt, anchorname, opts);
rulesopt = NULL;
}
@@ -3426,20 +3605,17 @@ main(int argc, char *argv[])
if (rulesopt != NULL && !(opts & PF_OPT_MERGE) &&
!anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
- error = 1;
+ exit_val = 1;
if (rulesopt != NULL) {
if (pfctl_rules(dev, rulesopt, opts, optimize,
anchorname, NULL))
- error = 1;
- else if (!(opts & PF_OPT_NOACTION) &&
- (loadopt & PFCTL_FLAG_TABLE))
- warn_namespace_collision(NULL);
+ exit_val = 1;
}
if (opts & PF_OPT_ENABLE)
if (pfctl_enable(dev, opts))
- error = 1;
+ exit_val = 1;
if (debugopt != NULL) {
switch (*debugopt) {
@@ -3458,5 +3634,19 @@ main(int argc, char *argv[])
}
}
- exit(error);
+ exit(exit_val);
+}
+
+char *
+pf_strerror(int errnum)
+{
+ switch (errnum) {
+ case ESRCH:
+ return "Table does not exist.";
+ case EINVAL:
+ case ENOENT:
+ return "Anchor does not exist.";
+ default:
+ return strerror(errnum);
+ }
}
diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h
index 5abd5ddcdf8f..afecc78086e0 100644
--- a/sbin/pfctl/pfctl.h
+++ b/sbin/pfctl/pfctl.h
@@ -55,6 +55,13 @@ struct pfr_buffer {
(var) != NULL; \
(var) = pfr_buf_next((buf), (var)))
+struct pfr_anchoritem {
+ SLIST_ENTRY(pfr_anchoritem) pfra_sle;
+ char *pfra_anchorname;
+};
+
+SLIST_HEAD(pfr_anchors, pfr_anchoritem);
+
int pfr_get_fd(void);
int pfr_add_table(struct pfr_table *, int *, int);
int pfr_del_table(struct pfr_table *, int *, int);
@@ -76,17 +83,17 @@ void *pfr_buf_next(struct pfr_buffer *, const void *);
int pfr_buf_grow(struct pfr_buffer *, int);
int pfr_buf_load(struct pfr_buffer *, char *, int,
int (*)(struct pfr_buffer *, char *, int, int), int);
-char *pfr_strerror(int);
+char *pf_strerror(int);
int pfi_get_ifaces(const char *, struct pfi_kif *, int *);
int pfi_clr_istats(const char *, int *, int);
void pfctl_print_title(char *);
-void pfctl_do_clear_tables(const char *, int);
+int pfctl_do_clear_tables(const char *, int);
void pfctl_show_tables(const char *, int);
-int pfctl_command_tables(int, char *[], char *, const char *, char *,
+int pfctl_table(int, char *[], char *, const char *, char *,
const char *, int);
int pfctl_show_altq(int, const char *, int, int);
-void warn_namespace_collision(const char *);
+void warn_duplicate_tables(const char *, const char *);
void pfctl_show_ifaces(const char *, int);
void pfctl_show_creators(int);
FILE *pfctl_fopen(const char *, const char *);
@@ -150,4 +157,7 @@ void expand_label(char *, size_t, struct pfctl_rule *);
const char *pfctl_proto2name(int);
+void pfctl_err(int, int, const char *, ...);
+void pfctl_errx(int, int, const char *, ...);
+
#endif /* _PFCTL_H_ */
diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c
index b58bace326c2..1d2a60555f19 100644
--- a/sbin/pfctl/pfctl_optimize.c
+++ b/sbin/pfctl/pfctl_optimize.c
@@ -273,7 +273,10 @@ pfctl_optimize_ruleset(struct pfctl *pf, struct pfctl_ruleset *rs)
struct pfctl_rule *r;
struct pfctl_rulequeue *old_rules;
- DEBUG("optimizing ruleset");
+ if (TAILQ_EMPTY(rs->rules[PF_RULESET_FILTER].active.ptr))
+ return (0);
+
+ DEBUG("optimizing ruleset \"%s\"", rs->anchor->path);
memset(&table_buffer, 0, sizeof(table_buffer));
skip_init();
TAILQ_INIT(&opt_queue);
@@ -720,11 +723,7 @@ reorder_rules(struct pfctl *pf, struct superblock *block, int depth)
* it based on a more optimal skipstep order.
*/
TAILQ_INIT(&head);
- while ((por = TAILQ_FIRST(&block->sb_rules))) {
- TAILQ_REMOVE(&block->sb_rules, por, por_entry);
- TAILQ_INSERT_TAIL(&head, por, por_entry);
- }
-
+ TAILQ_CONCAT(&head, &block->sb_rules, por_entry);
while (!TAILQ_EMPTY(&head)) {
largest = 1;
@@ -745,11 +744,7 @@ reorder_rules(struct pfctl *pf, struct superblock *block, int depth)
* Nothing useful left. Leave remaining rules in order.
*/
DEBUG("(%d) no more commonality for skip steps", depth);
- while ((por = TAILQ_FIRST(&head))) {
- TAILQ_REMOVE(&head, por, por_entry);
- TAILQ_INSERT_TAIL(&block->sb_rules, por,
- por_entry);
- }
+ TAILQ_CONCAT(&block->sb_rules, &head, por_entry);
} else {
/*
* There is commonality. Extract those common rules
@@ -860,10 +855,7 @@ block_feedback(struct pfctl *pf, struct superblock *block)
*/
TAILQ_INIT(&queue);
- while ((por1 = TAILQ_FIRST(&block->sb_rules)) != NULL) {
- TAILQ_REMOVE(&block->sb_rules, por1, por_entry);
- TAILQ_INSERT_TAIL(&queue, por1, por_entry);
- }
+ TAILQ_CONCAT(&queue, &block->sb_rules, por_entry);
while ((por1 = TAILQ_FIRST(&queue)) != NULL) {
TAILQ_REMOVE(&queue, por1, por_entry);
@@ -900,13 +892,13 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
struct pf_opt_queue queue;
struct pfctl_rules_info rules;
struct pfctl_rule a, b, rule;
- int nr, mnr;
+ int nr, mnr, ret;
TAILQ_INIT(&queue);
TAILQ_INIT(&prof_superblocks);
- if (pfctl_get_rules_info_h(pf->h, &rules, PF_PASS, "")) {
- warn("DIOCGETRULES");
+ if ((ret = pfctl_get_rules_info_h(pf->h, &rules, PF_PASS, "")) != 0) {
+ warnx("%s", pf_strerror(ret));
return (1);
}
mnr = rules.nr;
@@ -921,7 +913,7 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
if (pfctl_get_rule_h(pf->h, nr, rules.ticket, "", PF_PASS,
&rule, anchor_call)) {
- warn("DIOCGETRULENV");
+ warnx("%s", pf_strerror(ret));
free(por);
return (1);
}
@@ -1256,7 +1248,7 @@ add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af,
/* This is just a temporary table name */
snprintf((*tbl)->pt_name, sizeof((*tbl)->pt_name), "%s%d",
- PF_OPT_TABLE_PREFIX, tablenum++);
+ PF_OPTIMIZER_TABLE_PFX, tablenum++);
DEBUG("creating table <%s>", (*tbl)->pt_name);
}
@@ -1323,9 +1315,9 @@ pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl)
/* Now we have to pick a table name that isn't used */
again:
DEBUG("translating temporary table <%s> to <%s%x_%d>", tbl->pt_name,
- PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
+ PF_OPTIMIZER_TABLE_PFX, table_identifier, tablenum);
snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d",
- PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
+ PF_OPTIMIZER_TABLE_PFX, table_identifier, tablenum);
PFRB_FOREACH(t, &table_buffer) {
if (strcasecmp(t->pfrt_name, tbl->pt_name) == 0) {
/* Collision. Try again */
diff --git a/sbin/pfctl/pfctl_osfp.c b/sbin/pfctl/pfctl_osfp.c
index 3a94c2e8c81b..5770c8343a46 100644
--- a/sbin/pfctl/pfctl_osfp.c
+++ b/sbin/pfctl/pfctl_osfp.c
@@ -264,7 +264,7 @@ void
pfctl_clear_fingerprints(int dev, int opts)
{
if (ioctl(dev, DIOCOSFPFLUSH))
- err(1, "DIOCOSFPFLUSH");
+ pfctl_err(opts, 1, "DIOCOSFPFLUSH");
}
/* flush pfctl's view of the fingerprints */
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 1db98c6103d4..f2eb75135609 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -66,10 +66,9 @@
#include "pfctl_parser.h"
#include "pfctl.h"
-void copy_satopfaddr(struct pf_addr *, struct sockaddr *);
void print_op (u_int8_t, const char *, const char *);
void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int);
-void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
+void print_ugid (u_int8_t, id_t, id_t, const char *);
void print_flags (uint16_t);
void print_fromto(struct pf_rule_addr *, pf_osfp_t,
struct pf_rule_addr *, sa_family_t, u_int8_t, int, int);
@@ -365,14 +364,14 @@ print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numer
}
void
-print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
+print_ugid(u_int8_t op, id_t i1, id_t i2, const char *t)
{
char a1[11], a2[11];
- snprintf(a1, sizeof(a1), "%u", u1);
- snprintf(a2, sizeof(a2), "%u", u2);
+ snprintf(a1, sizeof(a1), "%ju", (uintmax_t)i1);
+ snprintf(a2, sizeof(a2), "%ju", (uintmax_t)i2);
printf(" %s", t);
- if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE))
+ if (i1 == -1 && (op == PF_OP_EQ || op == PF_OP_NE))
print_op(op, "unknown", a2);
else
print_op(op, a1, a2);
@@ -929,7 +928,7 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer
printf("%sall", count++ ? ", " : "");
if (r->log & PF_LOG_MATCHES)
printf("%smatches", count++ ? ", " : "");
- if (r->log & PF_LOG_SOCKET_LOOKUP)
+ if (r->log & PF_LOG_USER)
printf("%suser", count++ ? ", " : "");
if (r->logif)
printf("%sto pflog%u", count++ ? ", " : "",
@@ -978,11 +977,9 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer
printf(" %sreceived-on %s", r->rcvifnot ? "!" : "",
r->rcv_ifname);
if (r->uid.op)
- print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
- UID_MAX);
+ print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user");
if (r->gid.op)
- print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
- GID_MAX);
+ print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group");
if (r->flags || r->flagset) {
printf(" flags ");
print_flags(r->flags);
@@ -1486,7 +1483,8 @@ ifa_load(void)
err(1, "getifaddrs");
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (!(ifa->ifa_addr->sa_family == AF_INET ||
+ if (ifa->ifa_addr == NULL ||
+ !(ifa->ifa_addr->sa_family == AF_INET ||
ifa->ifa_addr->sa_family == AF_INET6 ||
ifa->ifa_addr->sa_family == AF_LINK))
continue;
@@ -1795,7 +1793,7 @@ host(const char *s, int opts)
char *p, *ps;
const char *errstr;
- if ((p = strrchr(s, '/')) != NULL) {
+ if ((p = strchr(s, '/')) != NULL) {
mask = strtonum(p+1, 0, 128, &errstr);
if (errstr) {
fprintf(stderr, "netmask is %s: %s\n", errstr, p);
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 91c0f655e008..7a3c0c2a523f 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -55,6 +55,7 @@
#define PF_OPT_RECURSE 0x04000
#define PF_OPT_KILLMATCH 0x08000
#define PF_OPT_NODNS 0x10000
+#define PF_OPT_IGNFAIL 0x20000
#define PF_NAT_PROXY_PORT_LOW 50001
#define PF_NAT_PROXY_PORT_HIGH 65535
@@ -262,7 +263,6 @@ struct pf_opt_tbl {
struct node_tinithead pt_nodes;
struct pfr_buffer *pt_buf;
};
-#define PF_OPT_TABLE_PREFIX "__automatic_"
/* optimizer pf_rule container */
struct pf_opt_rule {
@@ -276,6 +276,8 @@ struct pf_opt_rule {
TAILQ_HEAD(pf_opt_queue, pf_opt_rule);
+void copy_satopfaddr(struct pf_addr *, struct sockaddr *);
+
int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *);
int pfctl_optimize_ruleset(struct pfctl *, struct pfctl_ruleset *);
diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c
index 21191259adff..00e4207d377b 100644
--- a/sbin/pfctl/pfctl_radix.c
+++ b/sbin/pfctl/pfctl_radix.c
@@ -461,16 +461,3 @@ pfr_next_token(char buf[BUF_SIZE], FILE *fp)
buf[i] = '\0';
return (1);
}
-
-char *
-pfr_strerror(int errnum)
-{
- switch (errnum) {
- case ESRCH:
- return "Table does not exist";
- case ENOENT:
- return "Anchor or Ruleset does not exist";
- default:
- return strerror(errnum);
- }
-}
diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c
index 3fe87b53b7f9..f583f5ef8e79 100644
--- a/sbin/pfctl/pfctl_table.c
+++ b/sbin/pfctl/pfctl_table.c
@@ -55,15 +55,12 @@
#include "pfctl.h"
extern void usage(void);
-static int pfctl_table(int, char *[], char *, const char *, char *,
- const char *, int);
static void print_table(const struct pfr_table *, int, int);
static int print_tstats(const struct pfr_tstats *, int);
static int load_addr(struct pfr_buffer *, int, char *[], char *, int, int);
static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
static int nonzero_astats(struct pfr_astats *);
static void print_astats(struct pfr_astats *, int);
-static void radix_perror(void);
static void xprintf(int, const char *, ...);
static void print_iface(struct pfi_kif *, int);
@@ -77,26 +74,28 @@ static const char *istats_text[2][2][2] = {
{ { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } }
};
-#define RVTEST(fct) do { \
- if ((!(opts & PF_OPT_NOACTION) || \
- (opts & PF_OPT_DUMMYACTION)) && \
- (fct)) { \
- radix_perror(); \
- goto _error; \
- } \
+#define RVTEST(fct) do { \
+ if ((!(opts & PF_OPT_NOACTION) || \
+ (opts & PF_OPT_DUMMYACTION)) && \
+ (fct)) { \
+ if ((opts & PF_OPT_RECURSE) == 0) \
+ warnx("%s", pf_strerror(errno)); \
+ goto _error; \
+ } \
} while (0)
#define CREATE_TABLE do { \
+ warn_duplicate_tables(table.pfrt_name, \
+ table.pfrt_anchor); \
table.pfrt_flags |= PFR_TFLAG_PERSIST; \
if ((!(opts & PF_OPT_NOACTION) || \
(opts & PF_OPT_DUMMYACTION)) && \
(pfr_add_table(&table, &nadd, flags)) && \
(errno != EPERM)) { \
- radix_perror(); \
+ warnx("%s", pf_strerror(errno)); \
goto _error; \
} \
if (nadd) { \
- warn_namespace_collision(table.pfrt_name); \
xprintf(opts, "%d table created", nadd); \
if (opts & PF_OPT_NOACTION) \
return (0); \
@@ -104,11 +103,17 @@ static const char *istats_text[2][2][2] = {
table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \
} while(0)
-void
+int
pfctl_do_clear_tables(const char *anchor, int opts)
{
- if (pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts))
- exit(1);
+ int rv;
+
+ if ((rv = pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts)) == -1) {
+ if ((opts & PF_OPT_IGNFAIL) == 0)
+ exit(1);
+ }
+
+ return (rv);
}
void
@@ -119,15 +124,6 @@ pfctl_show_tables(const char *anchor, int opts)
}
int
-pfctl_command_tables(int argc, char *argv[], char *tname,
- const char *command, char *file, const char *anchor, int opts)
-{
- if (tname == NULL || command == NULL)
- usage();
- return pfctl_table(argc, argv, tname, command, file, anchor, opts);
-}
-
-int
pfctl_table(int argc, char *argv[], char *tname, const char *command,
char *file, const char *anchor, int opts)
{
@@ -214,7 +210,8 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size);
if (opts & PF_OPT_VERBOSE)
PFRB_FOREACH(a, &b)
- if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ if ((opts & PF_OPT_VERBOSE2) ||
+ a->pfra_fback != PFR_FB_NONE)
print_addrx(a, NULL,
opts & PF_OPT_USEDNS);
} else if (!strcmp(command, "delete")) {
@@ -228,7 +225,8 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size);
if (opts & PF_OPT_VERBOSE)
PFRB_FOREACH(a, &b)
- if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ if ((opts & PF_OPT_VERBOSE2) ||
+ a->pfra_fback != PFR_FB_NONE)
print_addrx(a, NULL,
opts & PF_OPT_USEDNS);
} else if (!strcmp(command, "replace")) {
@@ -259,7 +257,8 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
xprintf(opts, "no changes");
if (opts & PF_OPT_VERBOSE)
PFRB_FOREACH(a, &b)
- if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ if ((opts & PF_OPT_VERBOSE2) ||
+ a->pfra_fback != PFR_FB_NONE)
print_addrx(a, NULL,
opts & PF_OPT_USEDNS);
} else if (!strcmp(command, "expire")) {
@@ -282,7 +281,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
break;
}
PFRB_FOREACH(p, &b) {
- ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0;
+ ((struct pfr_astats *)p)->pfras_a.pfra_fback = PFR_FB_NONE;
if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero >
lifetime)
if (pfr_buf_add(&b2,
@@ -297,7 +296,8 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size);
if (opts & PF_OPT_VERBOSE)
PFRB_FOREACH(a, &b2)
- if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ if ((opts & PF_OPT_VERBOSE2) ||
+ a->pfra_fback != PFR_FB_NONE)
print_addrx(a, NULL,
opts & PF_OPT_USEDNS);
} else if (!strcmp(command, "reset")) {
@@ -558,13 +558,6 @@ print_astats(struct pfr_astats *as, int dns)
(unsigned long long)as->pfras_bytes[dir][op]);
}
-void
-radix_perror(void)
-{
- extern char *__progname;
- fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno));
-}
-
int
pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
struct pfr_buffer *ab, u_int32_t ticket)
@@ -583,12 +576,10 @@ pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
}
void
-warn_namespace_collision(const char *filter)
+warn_duplicate_tables(const char *tablename, const char *anchorname)
{
struct pfr_buffer b;
struct pfr_table *t;
- const char *name = NULL, *lastcoll;
- int coll = 0;
bzero(&b, sizeof(b));
b.pfrb_type = PFRB_TABLES;
@@ -604,22 +595,13 @@ warn_namespace_collision(const char *filter)
PFRB_FOREACH(t, &b) {
if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE))
continue;
- if (filter != NULL && strcmp(filter, t->pfrt_name))
+ if (!strcmp(anchorname, t->pfrt_anchor))
continue;
- if (!t->pfrt_anchor[0])
- name = t->pfrt_name;
- else if (name != NULL && !strcmp(name, t->pfrt_name)) {
- coll++;
- lastcoll = name;
- name = NULL;
- }
+ if (!strcmp(tablename, t->pfrt_name))
+ warnx("warning: table <%s> already defined"
+ " in anchor \"%s\"", tablename,
+ t->pfrt_anchor[0] ? t->pfrt_anchor : "/");
}
- if (coll == 1)
- warnx("warning: namespace collision with <%s> global table.",
- lastcoll);
- else if (coll > 1)
- warnx("warning: namespace collisions with %d global tables.",
- coll);
pfr_buf_clear(&b);
}
@@ -657,10 +639,8 @@ pfctl_show_ifaces(const char *filter, int opts)
for (;;) {
pfr_buf_grow(&b, b.pfrb_size);
b.pfrb_size = b.pfrb_msize;
- if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) {
- radix_perror();
- exit(1);
- }
+ if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size))
+ errx(1, "%s", pf_strerror(errno));
if (b.pfrb_size <= b.pfrb_msize)
break;
}
diff --git a/sbin/pfctl/tests/files/pf0088.in b/sbin/pfctl/tests/files/pf0088.in
index 4700b6916b7e..a85aa84a30bb 100644
--- a/sbin/pfctl/tests/files/pf0088.in
+++ b/sbin/pfctl/tests/files/pf0088.in
@@ -16,7 +16,7 @@ pass to 10.0.0.2 keep state
block from 10.0.0.3 to 10.0.0.2
pass to 10.0.0.2 modulate state
block from 10.0.0.3 to 10.0.0.2
-pass to 10.0.0.2 synproxy state
+pass in to 10.0.0.2 synproxy state
pass out proto tcp from 10.0.0.4 to 10.0.0.5 keep state
diff --git a/sbin/pfctl/tests/files/pf0088.ok b/sbin/pfctl/tests/files/pf0088.ok
index 47251a4503dd..801056a4ab46 100644
--- a/sbin/pfctl/tests/files/pf0088.ok
+++ b/sbin/pfctl/tests/files/pf0088.ok
@@ -11,7 +11,7 @@ pass inet from any to 10.0.0.2 flags S/SA keep state
block drop inet from 10.0.0.3 to 10.0.0.2
pass inet from any to 10.0.0.2 flags S/SA modulate state
block drop inet from 10.0.0.3 to 10.0.0.2
-pass inet from any to 10.0.0.2 flags S/SA synproxy state
+pass in inet from any to 10.0.0.2 flags S/SA synproxy state
pass out inet proto tcp from 10.0.0.4 to 10.0.0.5 flags S/SA keep state
pass out inet proto tcp from 10.0.0.4 to 10.0.0.5 port = http flags S/SA keep state
pass out all flags S/SA keep state
diff --git a/sbin/pfctl/tests/files/pf1072.fail b/sbin/pfctl/tests/files/pf1072.fail
new file mode 100644
index 000000000000..06ef5ae457e5
--- /dev/null
+++ b/sbin/pfctl/tests/files/pf1072.fail
@@ -0,0 +1 @@
+invalid port range
diff --git a/sbin/pfctl/tests/files/pf1072.in b/sbin/pfctl/tests/files/pf1072.in
new file mode 100644
index 000000000000..e09e92388ce1
--- /dev/null
+++ b/sbin/pfctl/tests/files/pf1072.in
@@ -0,0 +1 @@
+pass in proto tcp from any port 500:100 to any
diff --git a/sbin/pfctl/tests/macro.sh b/sbin/pfctl/tests/macro.sh
index 9c48dbbc69f0..071c6cb4f426 100755
--- a/sbin/pfctl/tests/macro.sh
+++ b/sbin/pfctl/tests/macro.sh
@@ -3,6 +3,7 @@ atf_test_case "space" cleanup
space_head()
{
atf_set descr "Test macros with spaces"
+ atf_set require.kmods "pf"
}
space_body()
diff --git a/sbin/pfctl/tests/pfctl_test.c b/sbin/pfctl/tests/pfctl_test.c
index dbdcaa4900ea..5f0aa7826bb4 100644
--- a/sbin/pfctl/tests/pfctl_test.c
+++ b/sbin/pfctl/tests/pfctl_test.c
@@ -65,24 +65,6 @@
* Copied from OpenBSD.
*/
-static bool
-check_pf_module_available(void)
-{
- int modid;
- struct module_stat stat;
-
- if ((modid = modfind("pf")) < 0) {
- warn("pf module not found");
- return false;
- }
- stat.version = sizeof(struct module_stat);
- if (modstat(modid, &stat) < 0) {
- warn("can't stat pf module id %d", modid);
- return false;
- }
- return (true);
-}
-
extern char **environ;
static struct sbuf *
@@ -185,9 +167,6 @@ run_pfctl_test(const char *input_path, const char *output_path,
struct sbuf *expected_output;
struct sbuf *real_output;
- if (!check_pf_module_available())
- atf_tc_skip("pf(4) is not loaded");
-
/* The test inputs need to be able to use relative includes. */
snprintf(input_files_path, sizeof(input_files_path), "%s/files",
atf_tc_get_config_var(tc, "srcdir"));
@@ -292,6 +271,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
ATF_TC_HEAD(pf##number, tc) \
{ \
atf_tc_set_md_var(tc, "descr", descr); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(pf##number, tc) \
{ \
@@ -301,6 +281,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
ATF_TC_HEAD(selfpf##number, tc) \
{ \
atf_tc_set_md_var(tc, "descr", "Self " descr); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(selfpf##number, tc) \
{ \
@@ -312,6 +293,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
ATF_TC_HEAD(pf##number, tc) \
{ \
atf_tc_set_md_var(tc, "descr", descr); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(pf##number, tc) \
{ \
@@ -325,6 +307,7 @@ do_selfpf_test(const char *number, const atf_tc_t *tc)
atf_tc_set_md_var(tc, "descr", descr); \
atf_tc_set_md_var(tc, "execenv", "jail"); \
atf_tc_set_md_var(tc, "execenv.jail.params", "vnet"); \
+ atf_tc_set_md_var(tc, "require.kmods", "pf"); \
} \
ATF_TC_BODY(pf##number, tc) \
{ \
diff --git a/sbin/pfctl/tests/pfctl_test_list.inc b/sbin/pfctl/tests/pfctl_test_list.inc
index 51729bc9adad..3a68cc06ec74 100644
--- a/sbin/pfctl/tests/pfctl_test_list.inc
+++ b/sbin/pfctl/tests/pfctl_test_list.inc
@@ -180,3 +180,4 @@ PFCTL_TEST(1068, "max-pkt-rate")
PFCTL_TEST(1069, "max-pkt-size")
PFCTL_TEST_FAIL(1070, "include line number")
PFCTL_TEST(1071, "mask length on (lo0)")
+PFCTL_TEST_FAIL(1072, "Invalid port range")
diff --git a/sbin/reboot/reboot.8 b/sbin/reboot/reboot.8
index 0ddcee643244..1bbc39d52be4 100644
--- a/sbin/reboot/reboot.8
+++ b/sbin/reboot/reboot.8
@@ -110,6 +110,15 @@ Care should be taken if
.Va value
contains any characters that are special to the shell or loader's configuration
parsing code.
+.It Fl f
+Force reboot.
+Normally,
+.Nm
+checks for the presence of the next kernel,
+and absence of the
+.Pa /var/run/noshutdown
+file.
+Without this flag, reboot is denied if one of the conditions failed.
.It Fl k Ar kname
Boot the specified kernel
.Ar kname
diff --git a/sbin/reboot/reboot.c b/sbin/reboot/reboot.c
index 9825d4f96319..f6065e80fb66 100644
--- a/sbin/reboot/reboot.c
+++ b/sbin/reboot/reboot.c
@@ -40,6 +40,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <spawn.h>
@@ -222,6 +223,7 @@ main(int argc, char *argv[])
{
struct utmpx utx;
const struct passwd *pw;
+ struct stat st;
int ch, howto = 0, i, sverrno;
bool Dflag, fflag, lflag, Nflag, nflag, qflag;
uint64_t pageins;
@@ -294,6 +296,11 @@ main(int argc, char *argv[])
if (argc != 0)
usage();
+ if (!donextboot && !fflag && stat(_PATH_NOSHUTDOWN, &st) == 0) {
+ errx(1, "Reboot cannot be done, " _PATH_NOSHUTDOWN
+ " is present");
+ }
+
if (Dflag && ((howto & ~RB_HALT) != 0 || kernel != NULL))
errx(1, "cannot delete existing nextboot config and do anything else");
if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
diff --git a/sbin/recoverdisk/recoverdisk.1 b/sbin/recoverdisk/recoverdisk.1
index 2999ac6ec409..9f1deb4c0c23 100644
--- a/sbin/recoverdisk/recoverdisk.1
+++ b/sbin/recoverdisk/recoverdisk.1
@@ -27,7 +27,7 @@
.Os
.Sh NAME
.Nm recoverdisk
-.Nd recover data from hard disk or optical media
+.Nd recover data from disk-like devices.
.Sh SYNOPSIS
.Nm
.Op Fl b Ar bigsize
@@ -41,79 +41,101 @@
.Sh DESCRIPTION
The
.Nm
-utility reads data from the
+utility reads all data from the
.Ar source
-file until all blocks could be successfully read.
+and retries read operations until they succeed.
If
.Ar destination
-was specified all data is being written to that file.
-It starts reading in multiples of the sector size.
-Whenever a block fails, it is put to the end of the working queue and will be
-read again, possibly with a smaller read size.
+is specified all data read be written there.
.Pp
-By default it uses block sizes of roughly 1 MB, 32kB, and the native
-sector size (usually 512 bytes).
-These figures are adjusted slightly, for devices whose sectorsize is not a
-power of 2, e.g., audio CDs with a sector size of 2352 bytes.
+The internal work-list can be saved and loaded so that
+.Nm
+sessions can be resumed, for instance when a marginal
+source hard-disk shuts down.
+.Pp
+The work-list is initialized with a single item which covers the entire
+.Ar source
+and
+.Nm
+always chips away at the first item on the work-list.
+
+When a read succeeds, that part of the current chunk is eliminated
+from the work-list.
+
+When a read fails, that part of the item is appended to the worklist
+as a separate item, and will be retried in due order.
+If
+.Ar destination
+is specified, the corresponding range is filled with '_UNREAD_'.
+.Pp
+The first pass attempts to read everything in "big-size" chunks,
+the second pass reads in "medium-size" chunks and third and subsequent
+passes read in "small-size" chunks. This three stage process is
+an attempt to optimize the case where only a few bad blocks exist
+on
+.Ar source .
+If too many read-errors are encountered,
+.Nm
+will fall back to smaller sizes sooner.
+.Pp
+The three sizes default to 128kB (or less if the sector size does
+not divide 128kB cleanly, for instance audio CD media), and the
+reported
+.Dv DIOCGSTRIPESIZE
+and
+.Dv DIOCGSECTORSIZE
+respectively.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl b Ar bigsize
-The size of reads attempted first.
-The middle pass is roughly the logarithmic average of the bigsize and
-the sectorsize.
-.It Fl r Ar readlist
-Read the list of blocks and block sizes to read from the specified file.
-.It Fl s Ar interval
-How often we should update the writelist file while things go OK.
-The default is 60 and the unit is "progress messages" so if things
-go well, this is the same as once per minute.
+The size of reads attempted in first pass.
+.It Fl m Ar mediumsize
+The size of reads attempted in second pass.
+.It Fl s Ar smallsize
+The size of reads attempted in third and subsequent passes.
+.It Fl r Ar work-list-file
+Read the work-list from a file.
+.It Fl w Ar work-list-file
+Write the work-list to a file when a read succeed, but at most once
+every minute.
+.It Fl l Ar log-file
+Each successful read is logged with timestamp, offset and length.
+.It Fl t Ar totalsize
+How many bytes should be recovered. The default is what
+.Dv DIOCGMEDIASIZE
+reports for character and block devices or
+.Dv st_size
+if
+.Ar source
+is a regular file.
+.It Fl p Ar pause
+.Xr sleep 3
+this long whenever a read fails. This makes the
+.Ar source
+device look less sick to the operating system.
.It Fl u Ar pattern
-By default blocks which encounter read errors will be filled with
-the pattern
+By default blocks which cannot be read are filled with the pattern
.Ql _UNREAD_
-in the output file.
-This option can be
-used to specify another pattern.
-Nothing gets written if the string is empty.
+in the output file. This option can be used to specify a different
+pattern. If the pattern is the empty string, nothing is written.
.It Fl v
-Enables nicer status report using ANSI escapes and UTF-8.
-.It Fl w Ar writelist
-Write the list of remaining blocks to read to the specified file if
-.Nm
-is aborted via
-.Dv SIGINT .
+Produce a detailed progress report with ANSI escapes and UTF-8.
.El
.Pp
-The
-.Fl r
-and
-.Fl w
-options can be specified together.
-Especially, they can point to the same file, which will be updated on abort.
-.Sh OUTPUT
-The
.Nm
-utility
-prints several columns, detailing the progress
-.Bl -tag -width remaining
-.It Va start
-Starting offset of the current block.
-.It Va size
-Read size of the current block.
-.It Va len
-Length of the current block.
-.It Va state
-Is increased for every failed read.
-.It Va done
-Number of bytes already read.
-.It Va remaining
-Number of bytes remaining.
-.It Va "% done"
-Percent complete.
-.El
+can be aborted with
+.Dv SIGINT ,
+but with a sick
+.Ar source
+it may take up to several minutes before the current read operation
+returns from the kernel.
+.Pp
.Sh EXAMPLES
.Bd -literal
+# check if all sectors can be read on a USB stick:
+recoverdisk /dev/da0
+
# recover data from failing hard drive ada3
recoverdisk /dev/ada3 /data/disk.img
@@ -129,10 +151,72 @@ recoverdisk -r worklist -w worklist /dev/cd0 /data/cd.iso
# recover a single file from the unreadable media
recoverdisk /cdrom/file.avi file.avi
-# If the disk hangs the system on read-errors try:
-recoverdisk -b 0 /dev/ada3 /somewhere
-
.Ed
+.Sh PRACTICAL ADVICE
+In Datamuseum.dk
+.Nm
+has been used to recover all sorts of data-media for two decades,
+here are some things we have learned:
+.Bl -bullet
+.It
+Interacting with failing hardware has a tendency to crash machines,
+so it is always a good idea to use the
+.Fl -w work-list-file
+so that it is possible to continue.
+.It
+When attempting to recover hard to read data from failing hard disks,
+it pays to pamper the drive as much as possible:
+.It
+It is generally best to keep the drive in it's usual physical orientation,
+but it can also help to try other orientations.
+.It
+Insulate the drive from external vibrations.
+.It
+Keep the drive cool with a fan.
+.It
+If possible, power the drive from a laboratory power supply.
+.It
+Do not loose patience: Let
+.Nm
+run as long as possible.
+.It
+(S)ATA controllers do not handle failing disks well, if this
+is a problem, use a USB-(S)ATA adapter instead.
+.It
+The
+.Nm
+source code is deliberately written to be easily portable to
+older versions of
+.Fx
+and to other operating systems.
+.It
+If you need to read ST-506, RLL or ESDI drives
+.Fx 3.5.1
+is a good compromise.
+.It
+Sometimes forcing the disk to step between reads helps.
+Since
+.Nm
+process the work-list in the order it is read, this
+can be accomplished by sorting the work-list with
+something like:
+.Dl % sort +0.5
+.It
+By default the
+.Xr CAM
+layer will retry failing read operations, but that
+will get stuck on the bad sectors for long time
+and delay recovering what actually can be read from
+a rapidly failing drive.
+In that situation, set the appropriate
+.Dl kern.cam.*.retry_count
+sysctl to zero.
+.It
+For floppies and un-zoned hard disks (ST-506 to
+early IDE) set
+.Fl b Ar bigsize
+to the size of a track.
+.El
.Sh SEE ALSO
.Xr dd 1 ,
.Xr ada 4 ,
@@ -143,7 +227,8 @@ recoverdisk -b 0 /dev/ada3 /somewhere
The
.Nm
utility first appeared in
-.Fx 7.0 .
+.Fx 7.0
+because Somebody™ forgot to make a backup copy.
.Sh AUTHORS
.An -nosplit
The original implementation was done by
@@ -151,34 +236,29 @@ The original implementation was done by
with minor improvements from
.An Ulrich Sp\(:orlein Aq Mt uqs@FreeBSD.org .
.Pp
-This manual page was written by
+This manual page was originally written by
.An Ulrich Sp\(:orlein .
.Sh BUGS
-Reading from media where the sectorsize is not a power of 2 will make all
-1 MB reads fail.
-This is due to the DMA reads being split up into blocks of at most 128kB.
-These reads then fail if the sectorsize is not a divisor of 128kB.
-When reading a full raw audio CD, this leads to roughly 700 error messages
-flying by.
-This is harmless and can be avoided by setting
-.Fl b
-to no more than 128kB.
+If a failing device causes the machine to crash, there is
+a risk that a chunk might have been successfully read
+and removed from the work-list, but not yet flushed to
+the
+.Ar destination .
.Pp
.Nm
-needs to know about read errors as fast as possible, i.e., retries by lower
-layers will usually slow down the operation.
-When using
-.Xr cam 4
-attached drives, you may want to set kern.cam.XX.retry_count to zero, e.g.:
-.Bd -literal
-# sysctl kern.cam.ada.retry_count=0
-# sysctl kern.cam.cd.retry_count=0
-# sysctl kern.cam.da.retry_count=0
-.Ed
-.\".Pp
-.\"When reading from optical media, a bug in the GEOM framework will
-.\"prevent it from seeing that the media has been removed.
-.\"The device can still be opened, but all reads will fail.
-.\"This is usually harmless, but will send
-.\".Nm
-.\"into an infinite loop.
+calls
+.Xr fdatasync 3
+on the destination before writing the work-list to a
+temporary file, and calls it again on the temporary
+file before renaming it to the specified
+.Fl w Ar work-file-list
+filename.
+But even then things dont always work out.
+.Pp
+.Nm
+should have an option for reconstructing the work-list
+from the
+.Ar destination
+by enumerating the
+.Fl u Ar pattern
+filled ranges.
diff --git a/sbin/recoverdisk/recoverdisk.c b/sbin/recoverdisk/recoverdisk.c
index 446266c36d50..e1b283e54a93 100644
--- a/sbin/recoverdisk/recoverdisk.c
+++ b/sbin/recoverdisk/recoverdisk.c
@@ -8,6 +8,7 @@
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*/
+
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/disk.h>
@@ -27,18 +28,10 @@
#include <time.h>
#include <unistd.h>
-/* Safe printf into a fixed-size buffer */
-#define bprintf(buf, fmt, ...) \
- do { \
- int ibprintf; \
- ibprintf = snprintf(buf, sizeof buf, fmt, __VA_ARGS__); \
- assert(ibprintf >= 0 && ibprintf < (int)sizeof buf); \
- } while (0)
-
struct lump {
- off_t start;
- off_t len;
- int state;
+ uint64_t start;
+ uint64_t len;
+ unsigned pass;
TAILQ_ENTRY(lump) list;
};
@@ -46,25 +39,32 @@ struct period {
time_t t0;
time_t t1;
char str[20];
- off_t bytes_read;
+ uint64_t bytes_read;
TAILQ_ENTRY(period) list;
};
TAILQ_HEAD(period_head, period);
static volatile sig_atomic_t aborting = 0;
static int verbose = 0;
-static size_t bigsize = 1024 * 1024;
-static size_t medsize;
-static size_t minsize = 512;
-static off_t tot_size;
-static off_t done_size;
+static uint64_t big_read;
+static uint64_t medium_read;
+static uint64_t small_read;
+static uint64_t total_size;
+static uint64_t done_size;
static char *input;
-static char *wworklist = NULL;
-static char *rworklist = NULL;
+static char *write_worklist_file = NULL;
+static char *read_worklist_file = NULL;
static const char *unreadable_pattern = "_UNREAD_";
-static const int write_errors_are_fatal = 1;
-static int fdr, fdw;
-
+static int write_errors_are_fatal = 1;
+static int read_fd, write_fd;
+static FILE *log_file = NULL;
+static char *work_buf;
+static char *pattern_buf;
+static double error_pause;
+
+static unsigned nlumps;
+static double n_reads, n_good_reads;
+static time_t t_first;
static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
static struct period_head minute = TAILQ_HEAD_INITIALIZER(minute);
static struct period_head quarter = TAILQ_HEAD_INITIALIZER(quarter);
@@ -74,7 +74,8 @@ static struct period_head day = TAILQ_HEAD_INITIALIZER(quarter);
/**********************************************************************/
static void
-report_good_read2(time_t now, size_t bytes, struct period_head *ph, time_t dt)
+account_good_read_period(time_t now, uint64_t bytes,
+ struct period_head *ph, time_t dt)
{
struct period *pp;
const char *fmt;
@@ -82,7 +83,7 @@ report_good_read2(time_t now, size_t bytes, struct period_head *ph, time_t dt)
pp = TAILQ_FIRST(ph);
if (pp == NULL || pp->t1 < now) {
- pp = calloc(1, sizeof(*pp));
+ pp = calloc(1UL, sizeof(*pp));
assert(pp != NULL);
pp->t0 = (now / dt) * dt;
pp->t1 = (now / dt + 1) * dt;
@@ -98,13 +99,13 @@ report_good_read2(time_t now, size_t bytes, struct period_head *ph, time_t dt)
}
static void
-report_good_read(time_t now, size_t bytes)
+account_good_read(time_t now, uint64_t bytes)
{
- report_good_read2(now, bytes, &minute, 60L);
- report_good_read2(now, bytes, &quarter, 900L);
- report_good_read2(now, bytes, &hour, 3600L);
- report_good_read2(now, bytes, &day, 86400L);
+ account_good_read_period(now, bytes, &minute, 60L);
+ account_good_read_period(now, bytes, &quarter, 900L);
+ account_good_read_period(now, bytes, &hour, 3600L);
+ account_good_read_period(now, bytes, &day, 86400L);
}
static void
@@ -114,20 +115,18 @@ report_one_period(const char *period, struct period_head *ph)
int n;
n = 0;
- printf("%s \xe2\x94\x82", period);
+ printf("%s ", period);
TAILQ_FOREACH(pp, ph, list) {
- if (n == 3) {
+ if (++n == 4) {
TAILQ_REMOVE(ph, pp, list);
free(pp);
break;
}
- if (n++)
- printf(" \xe2\x94\x82");
- printf(" %s %14jd", pp->str, pp->bytes_read);
+ printf("\xe2\x94\x82 %s %14ju ",
+ pp->str, (uintmax_t)pp->bytes_read);
}
for (; n < 3; n++) {
- printf(" \xe2\x94\x82");
- printf(" %5s %14s", "", "");
+ printf("\xe2\x94\x82 %5s %14s ", "", "");
}
printf("\x1b[K\n");
}
@@ -146,27 +145,23 @@ report_periods(void)
static void
set_verbose(void)
{
- struct winsize wsz;
- if (!isatty(STDIN_FILENO) || ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz))
- return;
verbose = 1;
}
static void
-report_header(int eol)
+report_header(const char *term)
{
- printf("%13s %7s %13s %5s %13s %13s %9s",
+ printf("%13s %7s %13s %5s %13s %13s %9s%s",
"start",
"size",
"block-len",
"pass",
"done",
"remaining",
- "% done");
- if (eol)
- printf("\x1b[K");
- putchar('\n');
+ "% done",
+ term
+ );
}
#define REPORTWID 79
@@ -186,20 +181,20 @@ report_hline(const char *how)
printf("\x1b[K\n");
}
-static off_t hist[REPORTWID];
-static off_t last_done = -1;
+static uint64_t hist[REPORTWID];
+static uint64_t prev_done = ~0UL;
static void
-report_histogram(const struct lump *lp)
+report_histogram(uint64_t start)
{
- off_t j, bucket, fp, fe, k, now;
+ uint64_t j, bucket, fp, fe, k, now;
double a;
struct lump *lp2;
- bucket = tot_size / REPORTWID;
- if (tot_size > bucket * REPORTWID)
+ bucket = total_size / REPORTWID;
+ if (total_size > bucket * REPORTWID)
bucket += 1;
- if (done_size != last_done) {
+ if (done_size != prev_done) {
memset(hist, 0, sizeof hist);
TAILQ_FOREACH(lp2, &lumps, list) {
fp = lp2->start;
@@ -213,9 +208,9 @@ report_histogram(const struct lump *lp)
fp += k;
}
}
- last_done = done_size;
+ prev_done = done_size;
}
- now = lp->start / bucket;
+ now = start / bucket;
for (j = 0; j < REPORTWID; j++) {
a = round(8 * (double)hist[j] / bucket);
assert (a >= 0 && a < 9);
@@ -228,7 +223,7 @@ report_histogram(const struct lump *lp)
} else {
putchar(0xe2);
putchar(0x96);
- putchar(0x80 + (int)a);
+ putchar(0x80 + (char)a);
}
if (j == now)
printf("\x1b[0m");
@@ -237,34 +232,40 @@ report_histogram(const struct lump *lp)
}
static void
-report(const struct lump *lp, size_t sz)
+report(uint64_t sz)
{
struct winsize wsz;
+ const struct lump *lp = TAILQ_FIRST(&lumps);
int j;
-
- assert(lp != NULL);
+ unsigned pass = 0;
+ uintmax_t start = 0, length = 0;
+ time_t t_now = time(NULL);
+
+ if (lp != NULL) {
+ pass = lp->pass;
+ start = lp->start;
+ length = lp->len;
+ }
if (verbose) {
printf("\x1b[H%s\x1b[K\n", input);
- report_header(1);
- } else {
- putchar('\r');
+ report_header("\x1b[K\n");
}
- printf("%13jd %7zu %13jd %5d %13jd %13jd %9.4f",
- (intmax_t)lp->start,
- sz,
- (intmax_t)lp->len,
- lp->state,
- (intmax_t)done_size,
- (intmax_t)(tot_size - done_size),
- 100*(double)done_size/(double)tot_size
+ printf("%13ju %7ju %13ju %5u %13ju %13ju %9.4f",
+ start,
+ (uintmax_t)sz,
+ length,
+ pass,
+ (uintmax_t)done_size,
+ (uintmax_t)(total_size - done_size),
+ 100*(double)done_size/(double)total_size
);
if (verbose) {
printf("\x1b[K\n");
report_hline(NULL);
- report_histogram(lp);
+ report_histogram(start);
if (TAILQ_EMPTY(&minute)) {
report_hline(NULL);
} else {
@@ -272,27 +273,36 @@ report(const struct lump *lp, size_t sz)
report_periods();
report_hline("\xe2\x94\xb4");
}
+ printf("Missing: %u", nlumps);
+ printf(" Success: %.0f/%.0f =", n_good_reads, n_reads);
+ printf(" %.4f%%", 100 * n_good_reads / n_reads);
+ printf(" Duration: %.3fs", (t_now - t_first) / n_reads);
+ printf("\x1b[K\n");
+ report_hline(NULL);
j = ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz);
if (!j)
printf("\x1b[%d;1H", wsz.ws_row);
+ } else {
+ printf("\n");
}
- fflush(stdout);
}
/**********************************************************************/
static void
-new_lump(off_t start, off_t len, int state)
+new_lump(uint64_t start, uint64_t len, unsigned pass)
{
struct lump *lp;
+ assert(len > 0);
lp = malloc(sizeof *lp);
if (lp == NULL)
err(1, "Malloc failed");
lp->start = start;
lp->len = len;
- lp->state = state;
+ lp->pass = pass;
TAILQ_INSERT_TAIL(&lumps, lp, list);
+ nlumps += 1;
}
/**********************************************************************
@@ -306,98 +316,100 @@ save_worklist(void)
struct lump *llp;
char buf[PATH_MAX];
- if (fdw >= 0 && fdatasync(fdw))
+ if (write_fd >= 0 && fdatasync(write_fd))
err(1, "Write error, probably disk full");
- if (wworklist != NULL) {
- bprintf(buf, "%s.tmp", wworklist);
- (void)fprintf(stderr, "\nSaving worklist ...");
- (void)fflush(stderr);
+ if (write_worklist_file != NULL) {
+ snprintf(buf, sizeof(buf), "%s.tmp", write_worklist_file);
+ fprintf(stderr, "\nSaving worklist ...");
file = fopen(buf, "w");
if (file == NULL)
err(1, "Error opening file %s", buf);
- TAILQ_FOREACH(llp, &lumps, list)
- fprintf(file, "%jd %jd %d\n",
- (intmax_t)llp->start, (intmax_t)llp->len,
- llp->state);
- (void)fflush(file);
+ TAILQ_FOREACH(llp, &lumps, list) {
+ assert (llp->len > 0);
+ fprintf(file, "%ju %ju %u\n",
+ (uintmax_t)llp->start,
+ (uintmax_t)llp->len,
+ llp->pass);
+ }
+ fflush(file);
if (ferror(file) || fdatasync(fileno(file)) || fclose(file))
err(1, "Error writing file %s", buf);
- if (rename(buf, wworklist))
- err(1, "Error renaming %s to %s", buf, wworklist);
- (void)fprintf(stderr, " done.\n");
+ if (rename(buf, write_worklist_file))
+ err(1, "Error renaming %s to %s",
+ buf, write_worklist_file);
+ fprintf(stderr, " done.\n");
}
}
/* Read the worklist if -r was given */
-static off_t
-read_worklist(off_t t)
+static uint64_t
+read_worklist(void)
{
- off_t s, l, d;
- int state, lines;
+ uintmax_t start, length;
+ uint64_t missing = 0;
+ unsigned pass, lines;
FILE *file;
- (void)fprintf(stderr, "Reading worklist ...");
- (void)fflush(stderr);
- file = fopen(rworklist, "r");
+ fprintf(stderr, "Reading worklist ...");
+ file = fopen(read_worklist_file, "r");
if (file == NULL)
- err(1, "Error opening file %s", rworklist);
+ err(1, "Error opening file %s", read_worklist_file);
lines = 0;
- d = t;
for (;;) {
++lines;
- if (3 != fscanf(file, "%jd %jd %d\n", &s, &l, &state)) {
+ if (3 != fscanf(file, "%ju %ju %u\n", &start, &length, &pass)) {
if (!feof(file))
- err(1, "Error parsing file %s at line %d",
- rworklist, lines);
+ err(1, "Error parsing file %s at line %u",
+ read_worklist_file, lines);
else
break;
}
- new_lump(s, l, state);
- d -= l;
+ if (length > 0) {
+ new_lump(start, length, pass);
+ missing += length;
+ }
}
if (fclose(file))
- err(1, "Error closing file %s", rworklist);
- (void)fprintf(stderr, " done.\n");
+ err(1, "Error closing file %s", read_worklist_file);
+ fprintf(stderr, " done.\n");
/*
- * Return the number of bytes already read
- * (at least not in worklist).
+ * Return the number of bytes outstanding
*/
- return (d);
+ return (missing);
}
/**********************************************************************/
static void
-write_buf(int fd, const void *buf, ssize_t len, off_t where)
+write_buf(int fd, const void *buf, uint64_t length, uint64_t where)
{
- ssize_t i;
+ int64_t i;
- i = pwrite(fd, buf, len, where);
- if (i == len)
+ i = pwrite(fd, buf, length, (off_t)where);
+ if (i > 0 && (uint64_t)i == length)
return;
- printf("\nWrite error at %jd/%zu\n\t%s\n",
- where, i, strerror(errno));
+ printf("\nWrite error at %ju/%ju: %jd (%s)\n",
+ (uintmax_t)where,
+ (uintmax_t)length,
+ (intmax_t)i, strerror(errno));
save_worklist();
if (write_errors_are_fatal)
exit(3);
}
static void
-fill_buf(char *buf, ssize_t len, const char *pattern)
+fill_buf(char *buf, int64_t len, const char *pattern)
{
- ssize_t sz = strlen(pattern);
- ssize_t i, j;
+ int64_t sz = strlen(pattern);
+ int64_t i;
for (i = 0; i < len; i += sz) {
- j = len - i;
- if (j > sz)
- j = sz;
- memcpy(buf + i, pattern, j);
+ memcpy(buf + i, pattern, MIN(len - i, sz));
}
}
@@ -406,45 +418,334 @@ fill_buf(char *buf, ssize_t len, const char *pattern)
static void
usage(void)
{
- (void)fprintf(stderr, "usage: recoverdisk [-b bigsize] [-r readlist] "
+ fprintf(stderr, "usage: recoverdisk [-b big_read] [-r readlist] "
"[-s interval] [-w writelist] source [destination]\n");
/* XXX update */
exit(1);
}
static void
-sighandler(__unused int sig)
+sighandler(int sig)
{
+ (void)sig;
aborting = 1;
}
+/**********************************************************************/
+
+static int64_t
+attempt_one_lump(time_t t_now)
+{
+ struct lump *lp;
+ uint64_t sz;
+ int64_t retval;
+ int error;
+
+ lp = TAILQ_FIRST(&lumps);
+ if (lp == NULL)
+ return(0);
+
+ if (lp->pass == 0) {
+ sz = MIN(lp->len, big_read);
+ } else if (lp->pass == 1) {
+ sz = MIN(lp->len, medium_read);
+ } else {
+ sz = MIN(lp->len, small_read);
+ }
+
+ assert(sz != 0);
+
+ n_reads += 1;
+ retval = pread(read_fd, work_buf, sz, lp->start);
+
+#if 0 /* enable this when testing */
+ if (!(random() & 0xf)) {
+ retval = -1;
+ errno = EIO;
+ usleep(20000);
+ } else {
+ usleep(2000);
+ }
+#endif
+
+ error = errno;
+ if (retval > 0) {
+ n_good_reads += 1;
+ sz = retval;
+ done_size += sz;
+ if (write_fd >= 0) {
+ write_buf(write_fd, work_buf, sz, lp->start);
+ }
+ if (log_file != NULL) {
+ fprintf(log_file, "%jd %ju %ju\n",
+ (intmax_t)t_now,
+ (uintmax_t)lp->start,
+ (uintmax_t)sz
+ );
+ fflush(log_file);
+ }
+ } else {
+ printf("%14ju %7ju read error %d: (%s)",
+ (uintmax_t)lp->start,
+ (uintmax_t)sz, error, strerror(error));
+ if (error_pause > 1) {
+ printf(" (Pausing %g s)", error_pause);
+ }
+ printf("\n");
+
+ if (write_fd >= 0 && pattern_buf != NULL) {
+ write_buf(write_fd, pattern_buf, sz, lp->start);
+ }
+ new_lump(lp->start, sz, lp->pass + 1);
+ retval = -sz;
+ }
+ lp->start += sz;
+ lp->len -= sz;
+ if (lp->len == 0) {
+ TAILQ_REMOVE(&lumps, lp, list);
+ nlumps -= 1;
+ free(lp);
+ }
+ errno = error;
+ return (retval);
+}
+
+
+/**********************************************************************/
+
+static void
+determine_total_size(void)
+{
+ struct stat sb;
+ int error;
+
+ if (total_size != 0)
+ return;
+
+ error = fstat(read_fd, &sb);
+ if (error < 0)
+ err(1, "fstat failed");
+
+ if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
+#ifdef DIOCGMEDIASIZE
+ off_t mediasize;
+ error = ioctl(read_fd, DIOCGMEDIASIZE, &mediasize);
+ if (error == 0 && mediasize > 0) {
+ total_size = mediasize;
+ printf("# Got total_size from DIOCGMEDIASIZE: %ju\n",
+ (uintmax_t)total_size);
+ return;
+ }
+#endif
+ } else if (S_ISREG(sb.st_mode) && sb.st_size > 0) {
+ total_size = sb.st_size;
+ printf("# Got total_size from stat(2): %ju\n",
+ (uintmax_t)total_size);
+ return;
+ } else {
+ errx(1, "Input must be device or regular file");
+ }
+ fprintf(stderr, "Specify total size with -t option\n");
+ exit(1);
+}
+
+static void
+determine_read_sizes(void)
+{
+ int error;
+ u_int sectorsize;
+ off_t stripesize;
+
+ determine_total_size();
+
+#ifdef DIOCGSECTORSIZE
+ if (small_read == 0) {
+ error = ioctl(read_fd, DIOCGSECTORSIZE, &sectorsize);
+ if (error >= 0 && sectorsize > 0) {
+ small_read = sectorsize;
+ printf("# Got small_read from DIOCGSECTORSIZE: %ju\n",
+ (uintmax_t)small_read
+ );
+ }
+ }
+#endif
+
+ if (small_read == 0) {
+ printf("Assuming 512 for small_read\n");
+ small_read = 512;
+ }
+
+ if (medium_read && (medium_read % small_read)) {
+ errx(1,
+ "medium_read (%ju) is not a multiple of small_read (%ju)\n",
+ (uintmax_t)medium_read, (uintmax_t)small_read
+ );
+ }
+
+ if (big_read != 0 && (big_read % small_read)) {
+ errx(1,
+ "big_read (%ju) is not a multiple of small_read (%ju)\n",
+ (uintmax_t)big_read, (uintmax_t)small_read
+ );
+ }
+
+#ifdef DIOCGSTRIPESIZE
+ if (medium_read == 0) {
+ error = ioctl(read_fd, DIOCGSTRIPESIZE, &stripesize);
+ if (error < 0 || stripesize < 0) {
+ // nope
+ } else if ((uint64_t)stripesize < small_read) {
+ // nope
+ } else if (stripesize % small_read) {
+ // nope
+ } else if (0 < stripesize && stripesize < (128<<10)) {
+ medium_read = stripesize;
+ printf("# Got medium_read from DIOCGSTRIPESIZE: %ju\n",
+ (uintmax_t)medium_read
+ );
+ }
+ }
+#endif
+#if defined(DIOCGFWSECTORS) && defined(DIOCGFWHEADS)
+ if (medium_read == 0) {
+ u_int fwsectors = 0, fwheads = 0;
+ error = ioctl(read_fd, DIOCGFWSECTORS, &fwsectors);
+ if (error)
+ fwsectors = 0;
+ error = ioctl(read_fd, DIOCGFWHEADS, &fwheads);
+ if (error)
+ fwheads = 0;
+ if (fwsectors && fwheads) {
+ medium_read = fwsectors * fwheads * small_read;
+ printf(
+ "# Got medium_read from DIOCGFW{SECTORS,HEADS}: %ju\n",
+ (uintmax_t)medium_read
+ );
+ }
+ }
+#endif
+
+ if (big_read == 0 && medium_read != 0) {
+ if (medium_read > (64<<10)) {
+ big_read = medium_read;
+ } else {
+ big_read = 128 << 10;
+ big_read -= big_read % medium_read;
+ }
+ printf("# Got big_read from medium_read: %ju\n",
+ (uintmax_t)big_read
+ );
+ }
+
+ if (big_read == 0) {
+ big_read = 128 << 10;
+ printf("# Defaulting big_read to %ju\n",
+ (uintmax_t)big_read
+ );
+ }
+
+ if (medium_read == 0) {
+ /*
+ * We do not want to go directly to single sectors, but
+ * we also dont want to waste time doing multi-sector
+ * reads with high failure probability.
+ */
+ uint64_t h = big_read;
+ uint64_t l = small_read;
+ while (h > l) {
+ h >>= 2;
+ l <<= 1;
+ }
+ medium_read = h;
+ printf("# Got medium_read from small_read & big_read: %ju\n",
+ (uintmax_t)medium_read
+ );
+ }
+ fprintf(stderr,
+ "# Bigsize = %ju, medium_read = %ju, small_read = %ju\n",
+ (uintmax_t)big_read, (uintmax_t)medium_read, (uintmax_t)small_read);
+
+}
+
+
+/**********************************************************************/
+
+static void
+monitor_read_sizes(uint64_t failed_size)
+{
+
+ if (failed_size == big_read && medium_read != small_read) {
+ if (n_reads < n_good_reads + 3)
+ return;
+ fprintf(
+ stderr,
+ "Too many failures for big reads."
+ " (%.0f bad of %.0f)"
+ " Shifting to medium_reads.\n",
+ n_reads - n_good_reads, n_reads
+ );
+ big_read = medium_read;
+ medium_read = small_read;
+ return;
+ }
+
+ if (failed_size > small_read) {
+ if (n_reads < n_good_reads + 100)
+ return;
+ fprintf(
+ stderr,
+ "Too many failures."
+ " (%.0f bad of %.0f)"
+ " Shifting to small_reads.\n",
+ n_reads - n_good_reads, n_reads
+ );
+ big_read = small_read;
+ medium_read = small_read;
+ return;
+ }
+}
+
+/**********************************************************************/
+
int
main(int argc, char * const argv[])
{
int ch;
- size_t sz, j;
+ int64_t sz;
int error;
- char *buf;
- u_int sectorsize;
- off_t stripesize;
- time_t t1, t2;
- struct stat sb;
- u_int n, snapshot = 60;
- static struct lump *lp;
+ time_t t_now, t_report, t_save;
+ unsigned snapshot = 60, unsaved;
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
- while ((ch = getopt(argc, argv, "b:r:w:s:u:v")) != -1) {
+ while ((ch = getopt(argc, argv, "b:l:p:m:r:w:s:t:u:v")) != -1) {
switch (ch) {
case 'b':
- bigsize = strtoul(optarg, NULL, 0);
+ big_read = strtoul(optarg, NULL, 0);
+ break;
+ case 'l':
+ log_file = fopen(optarg, "a");
+ if (log_file == NULL) {
+ err(1, "Could not open logfile for append");
+ }
+ break;
+ case 'p':
+ error_pause = strtod(optarg, NULL);
+ break;
+ case 'm':
+ medium_read = strtoul(optarg, NULL, 0);
break;
case 'r':
- rworklist = strdup(optarg);
- if (rworklist == NULL)
+ read_worklist_file = strdup(optarg);
+ if (read_worklist_file == NULL)
err(1, "Cannot allocate enough memory");
break;
case 's':
- snapshot = strtoul(optarg, NULL, 0);
+ small_read = strtoul(optarg, NULL, 0);
+ break;
+ case 't':
+ total_size = strtoul(optarg, NULL, 0);
break;
case 'u':
unreadable_pattern = optarg;
@@ -453,8 +754,8 @@ main(int argc, char * const argv[])
set_verbose();
break;
case 'w':
- wworklist = strdup(optarg);
- if (wworklist == NULL)
+ write_worklist_file = strdup(optarg);
+ if (write_worklist_file == NULL)
err(1, "Cannot allocate enough memory");
break;
default:
@@ -469,149 +770,106 @@ main(int argc, char * const argv[])
usage();
input = argv[0];
- fdr = open(argv[0], O_RDONLY);
- if (fdr < 0)
+ read_fd = open(argv[0], O_RDONLY);
+ if (read_fd < 0)
err(1, "Cannot open read descriptor %s", argv[0]);
- error = fstat(fdr, &sb);
- if (error < 0)
- err(1, "fstat failed");
- if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
- error = ioctl(fdr, DIOCGSECTORSIZE, &sectorsize);
- if (error < 0)
- err(1, "DIOCGSECTORSIZE failed");
-
- error = ioctl(fdr, DIOCGSTRIPESIZE, &stripesize);
- if (error == 0 && stripesize < sectorsize)
- sectorsize = stripesize;
+ determine_read_sizes();
- minsize = sectorsize;
- bigsize = rounddown(bigsize, sectorsize);
+ work_buf = malloc(big_read);
+ assert (work_buf != NULL);
- error = ioctl(fdr, DIOCGMEDIASIZE, &tot_size);
- if (error < 0)
- err(1, "DIOCGMEDIASIZE failed");
+ if (argc > 1) {
+ write_fd = open(argv[1], O_WRONLY | O_CREAT, DEFFILEMODE);
+ if (write_fd < 0)
+ err(1, "Cannot open write descriptor %s", argv[1]);
+ if (ftruncate(write_fd, (off_t)total_size) < 0)
+ err(1, "Cannot truncate output %s to %ju bytes",
+ argv[1], (uintmax_t)total_size);
} else {
- tot_size = sb.st_size;
+ write_fd = -1;
}
- if (bigsize < minsize)
- bigsize = minsize;
-
- for (ch = 0; (bigsize >> ch) > minsize; ch++)
- continue;
- medsize = bigsize >> (ch / 2);
- medsize = rounddown(medsize, minsize);
-
- fprintf(stderr, "Bigsize = %zu, medsize = %zu, minsize = %zu\n",
- bigsize, medsize, minsize);
-
- buf = malloc(bigsize);
- if (buf == NULL)
- err(1, "Cannot allocate %zu bytes buffer", bigsize);
+ if (strlen(unreadable_pattern)) {
+ pattern_buf = malloc(big_read);
+ assert(pattern_buf != NULL);
+ fill_buf(pattern_buf, big_read, unreadable_pattern);
+ }
- if (argc > 1) {
- fdw = open(argv[1], O_WRONLY | O_CREAT, DEFFILEMODE);
- if (fdw < 0)
- err(1, "Cannot open write descriptor %s", argv[1]);
- if (ftruncate(fdw, tot_size) < 0)
- err(1, "Cannot truncate output %s to %jd bytes",
- argv[1], (intmax_t)tot_size);
- } else
- fdw = -1;
-
- if (rworklist != NULL) {
- done_size = read_worklist(tot_size);
+ if (read_worklist_file != NULL) {
+ done_size = total_size - read_worklist();
} else {
- new_lump(0, tot_size, 0);
+ new_lump(0UL, total_size, 0UL);
done_size = 0;
}
- if (wworklist != NULL)
+ if (write_worklist_file != NULL)
signal(SIGINT, sighandler);
- t1 = time(NULL);
sz = 0;
if (!verbose)
- report_header(0);
+ report_header("\n");
else
printf("\x1b[2J");
- n = 0;
- for (;;) {
- lp = TAILQ_FIRST(&lumps);
- if (lp == NULL)
- break;
- while (lp->len > 0) {
- if (lp->state == 0)
- sz = MIN(lp->len, (off_t)bigsize);
- else if (lp->state == 1)
- sz = MIN(lp->len, (off_t)medsize);
- else
- sz = MIN(lp->len, (off_t)minsize);
- assert(sz != 0);
-
- t2 = time(NULL);
- if (t1 != t2 || lp->len < (off_t)bigsize) {
- t1 = t2;
- if (++n == snapshot) {
- save_worklist();
- n = 0;
- }
- report(lp, sz);
- }
+ t_first = time(NULL);
+ t_report = t_first;
+ t_save = t_first;
+ unsaved = 0;
+ while (!aborting) {
+ t_now = time(NULL);
+ sz = attempt_one_lump(t_now);
+ error = errno;
- j = pread(fdr, buf, sz, lp->start);
-#if 0
-if (!(random() & 0xf)) {
- j = -1;
- errno = EIO;
-}
-#endif
- if (j == sz) {
- done_size += sz;
- if (fdw >= 0)
- write_buf(fdw, buf, sz, lp->start);
- lp->start += sz;
- lp->len -= sz;
- if (verbose && lp->state > 2)
- report_good_read(t2, sz);
- continue;
- }
- error = errno;
-
- printf("%jd %zu %d read error (%s)\n",
- lp->start, sz, lp->state, strerror(error));
- if (verbose)
- report(lp, sz);
- if (fdw >= 0 && strlen(unreadable_pattern)) {
- fill_buf(buf, sz, unreadable_pattern);
- write_buf(fdw, buf, sz, lp->start);
+ if (sz == 0) {
+ break;
+ }
+
+ if (sz > 0) {
+ unsaved += 1;
+ }
+ if (unsaved && (t_save + snapshot) < t_now) {
+ save_worklist();
+ unsaved = 0;
+ t_save = t_now;
+ if (!verbose) {
+ report_header("\n");
+ t_report = t_now;
}
- new_lump(lp->start, sz, lp->state + 1);
- lp->start += sz;
- lp->len -= sz;
- if (error == EINVAL) {
- printf("Try with -b 131072 or lower ?\n");
- aborting = 1;
- break;
+ }
+ if (sz > 0) {
+ if (verbose) {
+ account_good_read(t_now, sz);
}
- if (error == ENXIO) {
- printf("Input device probably detached...\n");
- aborting = 1;
- break;
+ if (t_report != t_now) {
+ report(sz);
+ t_report = t_now;
}
+ continue;
}
- if (aborting)
- save_worklist();
- if (aborting || !TAILQ_NEXT(lp, list))
- report(lp, sz);
- if (aborting)
+
+ monitor_read_sizes(-sz);
+
+ if (error == EINVAL) {
+ printf("Try with -b 131072 or lower ?\n");
+ aborting = 1;
break;
- assert(lp->len == 0);
- TAILQ_REMOVE(&lumps, lp, list);
- free(lp);
+ }
+ if (error == ENXIO) {
+ printf("Input device probably detached...\n");
+ aborting = 1;
+ break;
+ }
+ report(-sz);
+ t_report = t_now;
+ if (error_pause > 0) {
+ usleep((unsigned long)(1e6 * error_pause));
+ }
}
+ save_worklist();
+ free(work_buf);
+ if (pattern_buf != NULL)
+ free(pattern_buf);
printf("%s", aborting ? "Aborted\n" : "Completed\n");
- free(buf);
- return (0);
+ report(0UL);
+ return (0); // XXX
}
diff --git a/sbin/route/route_netlink.c b/sbin/route/route_netlink.c
index 631c2860b547..ba22a2ec1e22 100644
--- a/sbin/route/route_netlink.c
+++ b/sbin/route/route_netlink.c
@@ -738,6 +738,7 @@ print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct snl_msg_info *cinf
print_nlmsg_generic(h, hdr, cinfo);
}
+ fflush(stdout);
snl_clear_lb(&h->ss_cmd);
}
diff --git a/sbin/routed/routed.8 b/sbin/routed/routed.8
index 8cf12d7b60e1..334c828b943e 100644
--- a/sbin/routed/routed.8
+++ b/sbin/routed/routed.8
@@ -27,13 +27,20 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 27, 2022
+.Dd May 20, 2025
.Dt ROUTED 8
.Os
.Sh NAME
.Nm routed ,
.Nm rdisc
.Nd network RIP and router discovery routing daemon
+.Sh DEPRECATION NOTICE
+The
+.Nm routed
+and
+.Nm rdisc
+utilities are deprecated and will be removed in
+.Fx 16.0 .
.Sh SYNOPSIS
.Nm
.Op Fl isqdghmpAtv
diff --git a/sbin/routed/rtquery/rtquery.8 b/sbin/routed/rtquery/rtquery.8
index de5e1fc7cf96..ff46a3414dcf 100644
--- a/sbin/routed/rtquery/rtquery.8
+++ b/sbin/routed/rtquery/rtquery.8
@@ -1,11 +1,16 @@
.\" $Revision: 2.27 $
.\"
-.Dd June 1, 1996
+.Dd May 20, 2025
.Dt RTQUERY 8
.Os
.Sh NAME
.Nm rtquery
.Nd query routing daemons for their routing tables
+.Sh DEPRECATION NOTICE
+The
+.Nm
+utility is deprecated and will be removed in
+.Fx 16.0 .
.Sh SYNOPSIS
.Nm
.Op Fl np1
diff --git a/sbin/savecore/savecore.8 b/sbin/savecore/savecore.8
index 53d2360719dd..1fb79c51f98d 100644
--- a/sbin/savecore/savecore.8
+++ b/sbin/savecore/savecore.8
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 4, 2022
+.Dd July 16, 2025
.Dt SAVECORE 8
.Os
.Sh NAME
@@ -69,7 +69,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl C
Check to see if a dump exists,
@@ -193,7 +193,7 @@ is meant to be called near the end of the initialization file
.Xr zstd 1 ,
.Xr getbootfile 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr mem 4 ,
.Xr textdump 4 ,
.Xr tar 5 ,
diff --git a/sbin/sysctl/tests/sysctl_test.sh b/sbin/sysctl/tests/sysctl_test.sh
index dfc32a87b212..b4cc7180a0f9 100644
--- a/sbin/sysctl/tests/sysctl_test.sh
+++ b/sbin/sysctl/tests/sysctl_test.sh
@@ -41,6 +41,7 @@ sysctl_aflag_body()
# output and it would all otherwise be saved.
sysctl -ao >/dev/null 2>stderr
if [ $? -ne 0 ]; then
+ cat stderr
atf_fail "sysctl -ao failed"
elif [ -s stderr ]; then
cat stderr
diff --git a/share/examples/Makefile b/share/examples/Makefile
index 560fdae6de5b..0a65b8c40d39 100644
--- a/share/examples/Makefile
+++ b/share/examples/Makefile
@@ -10,11 +10,11 @@ LDIRS= BSD_daemon \
FreeBSD_version \
bootforth \
csh \
- drivers \
etc \
find_interface \
flua \
indent \
+ inotify \
ipfw \
jails \
kld \
@@ -73,12 +73,6 @@ SE_DIRS+= csh
SE_CSHPACKAGE= csh
SE_CSH= dot.cshrc
-SE_DIRS+= drivers
-SE_DRIVERS= \
- README \
- make_device_driver.sh \
- make_pseudo_driver.sh
-
SE_DIRS+= etc
SE_ETC= \
README.examples \
@@ -97,6 +91,10 @@ SE_FLUA= libjail.lua
SE_DIRS+= indent
SE_INDENT= indent.pro
+SE_DIRS+= inotify
+SE_INOTIFY= inotify.c \
+ Makefile
+
.if ${MK_IPFILTER} != "no"
SUBDIR+= ipfilter
.endif
diff --git a/share/examples/drivers/README b/share/examples/drivers/README
deleted file mode 100644
index 8628029a62f8..000000000000
--- a/share/examples/drivers/README
+++ /dev/null
@@ -1,42 +0,0 @@
-
-Author: Julian Elischer
-
-The files in this directory are shell scripts.
-
-They will, when run, create an example skeleton driver
-for you. You can use this driver as a starting point for
-writing drivers for your own devices. They have all the hooks needed
-for initialization, probing, attaching, as well as DEVFS
-node creation. They also create sample ioctl commands and a sample
-ioctl definition .h file in /sys/sys. In other words they are fully
-functional in a 'skeleton' sort of a way. They support multiple devices
-so that you may have several of your 'foobar' devices probed and attached
-at once.
-
-I expect that these scripts will improve with time.
-
-At present these scripts also link the newly created driver into
-the kernel sources in /sys. Possibly a better way would be
-to make them interactive. (and ask what kernel tree to use as well as
-a name for the driver.).
-
-There are presently two scripts.
-One for making a real device driver for ISA devices, and
-one for making a device driver for pseudo devices (e.g. /dev/null).
-Hopefully they will be joined by similar scripts for creating
-skeletons for PCI devices as well.
-
-Give them a single argument: the name of the driver.
-They will use this given name in many places within the driver,
-both in lower and upper case form. (conforming to normal usage).
-
-The skeleton driver should already link with the kernel
-and in fact the shell script will compile a kernel with the new
-drive linked in.. The new kernel should still be
-runnable and the new driver should be
-fully callable (once you get your device to probe).
-You should simply edit the driver and continue to use
-'make' (as done in the script) until your driver does what you want.
-
-The driver will end up in /sys/i386/isa for the device driver script,
-and in /sys/dev for the pseudo driver script.
diff --git a/share/examples/drivers/make_pseudo_driver.sh b/share/examples/drivers/make_pseudo_driver.sh
deleted file mode 100644
index 5d6d09aa9648..000000000000
--- a/share/examples/drivers/make_pseudo_driver.sh
+++ /dev/null
@@ -1,435 +0,0 @@
-#!/bin/sh
-# This writes a skeleton driver and puts it into the kernel tree for you
-#
-# arg1 is lowercase "foo"
-# arg2 path to the kernel sources, "/sys" if omitted
-#
-# Trust me, RUN THIS SCRIPT :)
-#
-#
-#-------cut here------------------
-
-if [ "${1}X" = "X" ]
-then
- echo "Hey , how about some help here.. give me a device name!"
- exit 1
-fi
-if [ "X${2}" = "X" ]; then
- TOP=`cd /sys; pwd -P`
- echo "Using ${TOP} as the path to the kernel sources!"
-else
- TOP=${2}
-fi
-
-for i in "" "conf" "i386" "i386/conf" "dev" "sys" "modules"
-do
- if [ -d ${TOP}/${i} ]
- then
- continue
- fi
- echo "${TOP}/${i}: no such directory."
- echo "Please, correct the error and try again."
- exit 1
-done
-
-UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"`
-
-if [ -d ${TOP}/modules/${1} ]; then
- echo "There appears to already be a module called ${1}"
- echo -n "Should it be overwritten? [Y]"
- read VAL
- if [ "-z" "$VAL" ]; then
- VAL=YES
- fi
- case ${VAL} in
- [yY]*)
- echo "Cleaning up from prior runs"
- rm -rf ${TOP}/dev/${1}
- rm -rf ${TOP}/modules/${1}
- rm ${TOP}/conf/files.${UPPER}
- rm ${TOP}/i386/conf/${UPPER}
- rm ${TOP}/sys/${1}io.h
- ;;
- *)
- exit 1
- ;;
- esac
-fi
-
-echo "The following files will be created:"
-echo ${TOP}/modules/${1}
-echo ${TOP}/conf/files.${UPPER}
-echo ${TOP}/i386/conf/${UPPER}
-echo ${TOP}/dev/${1}
-echo ${TOP}/dev/${1}/${1}.c
-echo ${TOP}/sys/${1}io.h
-echo ${TOP}/modules/${1}
-echo ${TOP}/modules/${1}/Makefile
-
-mkdir ${TOP}/modules/${1}
-
-cat >${TOP}/conf/files.${UPPER} <<DONE
-dev/${1}/${1}.c optional ${1}
-DONE
-
-cat >${TOP}/i386/conf/${UPPER} <<DONE
-# Configuration file for kernel type: ${UPPER}
-
-files "${TOP}/conf/files.${UPPER}"
-
-include GENERIC
-
-ident ${UPPER}
-
-# trust me, you'll need this
-options KDB
-options DDB
-device ${1}
-DONE
-
-if [ ! -d ${TOP}/dev/${1} ]; then
- mkdir -p ${TOP}/dev/${1}
-fi
-
-cat >${TOP}/dev/${1}/${1}.c <<DONE
-/*
- * Copyright (c) [year] [your name]
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * ${1} driver
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h> /* SYSINIT stuff */
-#include <sys/uio.h> /* SYSINIT stuff */
-#include <sys/conf.h> /* cdevsw stuff */
-#include <sys/malloc.h> /* malloc region definitions */
-#include <sys/proc.h>
-#include <sys/${1}io.h> /* ${1} IOCTL definitions */
-
-#include <machine/clock.h> /* DELAY() */
-
-#define N${UPPER} 3 /* defines number of instances */
-
-/* XXX These should be defined in terms of bus-space ops. */
-#define ${UPPER}_INB(port) inb(port)
-#define ${UPPER}_OUTB(port, val) (port, (val))
-
-/* Function prototypes (these should all be static) */
-static d_open_t ${1}open;
-static d_close_t ${1}close;
-static d_read_t ${1}read;
-static d_write_t ${1}write;
-static d_ioctl_t ${1}ioctl;
-static d_mmap_t ${1}mmap;
-static d_poll_t ${1}poll;
-
-#define CDEV_MAJOR 20
-static struct cdevsw ${1}_cdevsw = {
- .d_version = D_VERSION,
- .d_open = ${1}open,
- .d_close = ${1}close,
- .d_read = ${1}read,
- .d_write = ${1}write,
- .d_ioctl = ${1}ioctl,
- .d_poll = ${1}poll,
- .d_mmap = ${1}mmap,
- .d_name = "${1}",
-};
-
-/*
- * device specific Misc defines
- */
-#define BUFFERSIZE 1024
-#define UNIT(dev) dev2unit(dev) /* assume one minor number per unit */
-
-/*
- * One of these per allocated device
- */
-struct ${1}_softc {
- u_long iobase;
- char buffer[BUFFERSIZE];
- struct cdev *dev;
-};
-
-typedef struct ${1}_softc *sc_p;
-
-static sc_p sca[N${UPPER}];
-
-/*
- * Macro to check that the unit number is valid
- * Often this isn't needed as once the open() is performed,
- * the unit number is pretty much safe.. The exception would be if we
- * implemented devices that could "go away". in which case all these routines
- * would be wise to check the number, DIAGNOSTIC or not.
- */
-#define CHECKUNIT(RETVAL) \
-do { /* the do-while is a safe way to do this grouping */ \
- if (unit > N${UPPER}) { \
- printf("%s: bad unit %d\n", __func__, unit); \
- return (RETVAL); \
- } \
- if (scp == NULL) { \
- printf("%s: unit %d not attached\n", __func__, unit); \
- return (RETVAL); \
- } \
-} while (0)
-
-#ifdef DIAGNOSTIC
-#define CHECKUNIT_DIAG(RETVAL) CHECKUNIT(RETVAL)
-#else /* DIAGNOSTIC */
-#define CHECKUNIT_DIAG(RETVAL)
-#endif /* DIAGNOSTIC */
-
-static int
-${1}ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT_DIAG(ENXIO);
-
- switch (cmd) {
- case DHIOCRESET:
- /* whatever resets it */
- (void)scp; /* Delete this line after using scp. */
-#if 0
- ${UPPER}_OUTB(scp->iobase, 0xff);
-#endif
- break;
- default:
- return ENXIO;
- }
- return (0);
-}
-
-/*
- * You also need read, write, open, close routines.
- * This should get you started
- */
-static int
-${1}open(struct cdev *dev, int oflags, int devtype, struct thread *td)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT(ENXIO);
-
- (void)scp; /* Delete this line after using scp. */
- /*
- * Do processing
- */
- return (0);
-}
-
-static int
-${1}close(struct cdev *dev, int fflag, int devtype, struct thread *td)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT_DIAG(ENXIO);
-
- (void)scp; /* Delete this line after using scp. */
- /*
- * Do processing
- */
- return (0);
-}
-
-static int
-${1}read(struct cdev *dev, struct uio *uio, int ioflag)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
- int toread;
-
-
- CHECKUNIT_DIAG(ENXIO);
-
- /*
- * Do processing
- * read from buffer
- */
- toread = (min(uio->uio_resid, sizeof(scp->buffer)));
- return(uiomove(scp->buffer, toread, uio));
-}
-
-static int
-${1}write(struct cdev *dev, struct uio *uio, int ioflag)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
- int towrite;
-
- CHECKUNIT_DIAG(ENXIO);
-
- /*
- * Do processing
- * write to buffer
- */
- towrite = (min(uio->uio_resid, sizeof(scp->buffer)));
- return(uiomove(scp->buffer, towrite, uio));
-}
-
-static int
-${1}mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT_DIAG(-1);
-
- (void)scp; /* Delete this line after using scp. */
- /*
- * Do processing
- */
-#if 0 /* if we had a frame buffer or whatever.. do this */
- if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) {
- return (-1);
- }
- return i386_btop((FRAMEBASE + offset));
-#else
- return (-1);
-#endif
-}
-
-static int
-${1}poll(struct cdev *dev, int which, struct thread *td)
-{
- int unit = UNIT(dev);
- sc_p scp = sca[unit];
-
- CHECKUNIT_DIAG(ENXIO);
-
- (void)scp; /* Delete this line after using scp. */
- /*
- * Do processing
- */
- return (0); /* this is the wrong value I'm sure */
-}
-
-/*
- * Now for some driver initialisation.
- * Occurs ONCE during boot (very early).
- */
-static void
-${1}_drvinit(void *unused)
-{
- int unit;
- sc_p scp;
-
- for (unit = 0; unit < N${UPPER}; unit++) {
- /*
- * Allocate storage for this instance .
- */
- scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT | M_ZERO);
- if( scp == NULL) {
- printf("${1}%d failed to allocate strorage\n", unit);
- return;
- }
- sca[unit] = scp;
- scp->dev = make_dev(&${1}_cdevsw, unit,
- UID_ROOT, GID_KMEM, 0640, "${1}%d", unit);
- }
-}
-
-SYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
- ${1}_drvinit, NULL);
-DONE
-
-cat >${TOP}/sys/${1}io.h <<DONE
-/*
- * Definitions needed to access the ${1} device (ioctls etc)
- * see mtio.h , ioctl.h as examples
- */
-#ifndef SYS_DHIO_H
-#define SYS_DHIO_H
-
-#ifndef KERNEL
-#include <sys/types.h>
-#endif
-#include <sys/ioccom.h>
-
-/*
- * define an ioctl here
- */
-#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */
-#endif
-DONE
-
-if [ ! -d ${TOP}/modules/${1} ]; then
- mkdir -p ${TOP}/modules/${1}
-fi
-
-cat >${TOP}/modules/${1}/Makefile <<DONE
-# ${UPPER} Loadable Kernel Module
-
-.PATH: \${.CURDIR}/../../dev/${1}
-KMOD = ${1}
-SRCS = ${1}.c
-
-.include <bsd.kmod.mk>
-DONE
-
-echo -n "Do you want to build the '${1}' module? [Y]"
-read VAL
-if [ "-z" "$VAL" ]; then
- VAL=YES
-fi
-case ${VAL} in
-[yY]*)
- (cd ${TOP}/modules/${1}; make depend; make )
- ;;
-*)
-# exit
- ;;
-esac
-
-echo ""
-echo -n "Do you want to build the '${UPPER}' kernel? [Y]"
-read VAL
-if [ "-z" "$VAL" ]; then
- VAL=YES
-fi
-case ${VAL} in
-[yY]*)
- (
- cd ${TOP}/i386/conf; \
- config ${UPPER}; \
- cd ${TOP}/i386/compile/${UPPER}; \
- make depend; \
- make; \
- )
- ;;
-*)
-# exit
- ;;
-esac
-
-#--------------end of script---------------
-#
-#edit to your taste..
-#
-#
diff --git a/share/examples/inotify/Makefile b/share/examples/inotify/Makefile
new file mode 100644
index 000000000000..c54c629c58d7
--- /dev/null
+++ b/share/examples/inotify/Makefile
@@ -0,0 +1,6 @@
+PROG= inotify
+MAN=
+
+LIBADD= xo
+
+.include <bsd.prog.mk>
diff --git a/share/examples/inotify/inotify.c b/share/examples/inotify/inotify.c
new file mode 100644
index 000000000000..ea63ccd1f337
--- /dev/null
+++ b/share/examples/inotify/inotify.c
@@ -0,0 +1,172 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Klara, Inc.
+ */
+
+/*
+ * A simple program to demonstrate inotify. Given one or more paths, it watches
+ * all events on those paths and prints them to standard output.
+ */
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/inotify.h>
+
+#include <assert.h>
+#include <err.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <libxo/xo.h>
+
+static void
+usage(void)
+{
+ xo_errx(1, "usage: inotify <path1> [<path2> ...]");
+}
+
+static const char *
+ev2str(uint32_t event)
+{
+ switch (event & IN_ALL_EVENTS) {
+ case IN_ACCESS:
+ return ("IN_ACCESS");
+ case IN_ATTRIB:
+ return ("IN_ATTRIB");
+ case IN_CLOSE_WRITE:
+ return ("IN_CLOSE_WRITE");
+ case IN_CLOSE_NOWRITE:
+ return ("IN_CLOSE_NOWRITE");
+ case IN_CREATE:
+ return ("IN_CREATE");
+ case IN_DELETE:
+ return ("IN_DELETE");
+ case IN_DELETE_SELF:
+ return ("IN_DELETE_SELF");
+ case IN_MODIFY:
+ return ("IN_MODIFY");
+ case IN_MOVE_SELF:
+ return ("IN_MOVE_SELF");
+ case IN_MOVED_FROM:
+ return ("IN_MOVED_FROM");
+ case IN_MOVED_TO:
+ return ("IN_MOVED_TO");
+ case IN_OPEN:
+ return ("IN_OPEN");
+ default:
+ switch (event) {
+ case IN_IGNORED:
+ return ("IN_IGNORED");
+ case IN_Q_OVERFLOW:
+ return ("IN_Q_OVERFLOW");
+ case IN_UNMOUNT:
+ return ("IN_UNMOUNT");
+ }
+ warnx("unknown event %#x", event);
+ assert(0);
+ }
+}
+
+static void
+set_handler(int kq, int sig)
+{
+ struct kevent kev;
+
+ (void)signal(sig, SIG_IGN);
+ EV_SET(&kev, sig, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+ if (kevent(kq, &kev, 1, NULL, 0, NULL) < 0)
+ xo_err(1, "kevent");
+}
+
+int
+main(int argc, char **argv)
+{
+ struct inotify_event *iev, *iev1;
+ struct kevent kev;
+ size_t ievsz;
+ int ifd, kq;
+
+ argc = xo_parse_args(argc, argv);
+ if (argc < 2)
+ usage();
+ argc--;
+ argv++;
+
+ ifd = inotify_init1(IN_NONBLOCK);
+ if (ifd < 0)
+ xo_err(1, "inotify");
+ for (int i = 0; i < argc; i++) {
+ int wd;
+
+ wd = inotify_add_watch(ifd, argv[i], IN_ALL_EVENTS);
+ if (wd < 0)
+ xo_err(1, "inotify_add_watch(%s)", argv[i]);
+ }
+
+ xo_set_version("1");
+ xo_open_list("events");
+
+ kq = kqueue();
+ if (kq < 0)
+ xo_err(1, "kqueue");
+
+ /*
+ * Handle signals in the event loop so that we can close the xo list.
+ */
+ set_handler(kq, SIGINT);
+ set_handler(kq, SIGTERM);
+ set_handler(kq, SIGHUP);
+ set_handler(kq, SIGQUIT);
+
+ /*
+ * Monitor the inotify descriptor for events.
+ */
+ EV_SET(&kev, ifd, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ if (kevent(kq, &kev, 1, NULL, 0, NULL) < 0)
+ xo_err(1, "kevent");
+
+ ievsz = sizeof(*iev) + NAME_MAX + 1;
+ iev = malloc(ievsz);
+ if (iev == NULL)
+ err(1, "malloc");
+
+ for (;;) {
+ ssize_t n;
+ const char *ev;
+
+ if (kevent(kq, NULL, 0, &kev, 1, NULL) < 0)
+ xo_err(1, "kevent");
+ if (kev.filter == EVFILT_SIGNAL)
+ break;
+
+ n = read(ifd, iev, ievsz);
+ if (n < 0)
+ xo_err(1, "read");
+ assert(n >= (ssize_t)sizeof(*iev));
+
+ for (iev1 = iev; n > 0;) {
+ assert(n >= (ssize_t)sizeof(*iev1));
+
+ ev = ev2str(iev1->mask);
+ xo_open_instance("event");
+ xo_emit("{:wd/%3d} {:event/%16s} {:name/%s}\n",
+ iev1->wd, ev, iev1->len > 0 ? iev1->name : "");
+ xo_close_instance("event");
+
+ n -= sizeof(*iev1) + iev1->len;
+ iev1 = (struct inotify_event *)(void *)
+ ((char *)iev1 + sizeof(*iev1) + iev1->len);
+ }
+ (void)xo_flush();
+ }
+
+ xo_close_list("events");
+
+ if (xo_finish() < 0)
+ xo_err(1, "stdout");
+ exit(0);
+}
diff --git a/share/examples/oci/Containerfile.pkg b/share/examples/oci/Containerfile.pkg
index 074c470affc9..f6699c79af71 100644
--- a/share/examples/oci/Containerfile.pkg
+++ b/share/examples/oci/Containerfile.pkg
@@ -6,7 +6,7 @@
ARG version=14.snap
# Select freebsd-runtime as our starting point.
-FROM localhost/freebsd-runtime:${version}
+FROM ghcr.io/freebsd/freebsd-runtime:${version}
# A list of package(s) to install
ARG packages
@@ -15,7 +15,10 @@ ARG packages
# use for downloading pkg since the freebsd-runtime image has both FreeBSD and
# FreeBSD-base pkg repo configs installed and FreeBSD-base does not contain the
# pkg package.
-RUN env ASSUME_ALWAYS_YES=yes pkg bootstrap -r FreeBSD && pkg update
+#
+# Set IGNORE_OSVERSION to allow building e.g. FreeBSD-14 images on
+# FreeBSD-15 hosts.
+RUN pkg bootstrap -y -r FreeBSD && pkg -o IGNORE_OSVERSION=yes update -f
# Install some package(s).
RUN pkg install -y ${packages}
diff --git a/share/man/man1/Makefile b/share/man/man1/Makefile
index e5ab6597ead2..5b1d3ac1091d 100644
--- a/share/man/man1/Makefile
+++ b/share/man/man1/Makefile
@@ -55,6 +55,7 @@ MLINKS= builtin.1 alias.1 \
builtin.1 if.1 \
builtin.1 jobid.1 \
builtin.1 jobs.1 \
+ builtin.1 keybinds.1 \
builtin.1 limit.1 \
builtin.1 log.1 \
builtin.1 logout.1 \
diff --git a/share/man/man1/builtin.1 b/share/man/man1/builtin.1
index d546548ab4e5..ee89006caea5 100644
--- a/share/man/man1/builtin.1
+++ b/share/man/man1/builtin.1
@@ -1,4 +1,6 @@
.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
.\" Copyright (c) 1999 Sheldon Hearn
.\"
.\" All rights reserved.
@@ -24,175 +26,33 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 21, 2010
+.Dd March 29, 2025
.Dt BUILTIN 1
.Os
.Sh NAME
.Nm builtin ,
-.Nm \&! ,
-.Nm % ,
-.Nm \&. ,
-.Nm \&: ,
-.Nm @ ,
-.Nm \&[ ,
-.Nm { ,
-.Nm } ,
-.Nm alias ,
-.Nm alloc ,
-.Nm bg ,
-.Nm bind ,
-.Nm bindkey ,
-.Nm break ,
-.Nm breaksw ,
-.Nm builtins ,
-.Nm case ,
-.Nm cd ,
-.Nm chdir ,
-.Nm command ,
-.Nm complete ,
-.Nm continue ,
-.Nm default ,
-.Nm dirs ,
-.Nm do ,
-.Nm done ,
-.Nm echo ,
-.Nm echotc ,
-.Nm elif ,
-.Nm else ,
-.Nm end ,
-.Nm endif ,
-.Nm endsw ,
-.Nm esac ,
-.Nm eval ,
-.Nm exec ,
-.Nm exit ,
-.Nm export ,
-.Nm false ,
-.Nm fc ,
-.Nm fg ,
-.Nm filetest ,
-.Nm fi ,
-.Nm for ,
-.Nm foreach ,
-.Nm getopts ,
-.Nm glob ,
-.Nm goto ,
-.Nm hash ,
-.Nm hashstat ,
-.Nm history ,
-.Nm hup ,
-.Nm if ,
-.Nm jobid ,
-.Nm jobs ,
-.Nm kill ,
-.Nm limit ,
-.Nm local ,
-.Nm log ,
-.Nm login ,
-.Nm logout ,
-.Nm ls-F ,
-.Nm nice ,
-.Nm nohup ,
-.Nm notify ,
-.Nm onintr ,
-.Nm popd ,
-.Nm printenv ,
-.Nm printf ,
-.Nm pushd ,
-.Nm pwd ,
-.Nm read ,
-.Nm readonly ,
-.Nm rehash ,
-.Nm repeat ,
-.Nm return ,
-.Nm sched ,
-.Nm set ,
-.Nm setenv ,
-.Nm settc ,
-.Nm setty ,
-.Nm setvar ,
-.Nm shift ,
-.Nm source ,
-.Nm stop ,
-.Nm suspend ,
-.Nm switch ,
-.Nm telltc ,
-.Nm test ,
-.Nm then ,
-.Nm time ,
-.Nm times ,
-.Nm trap ,
-.Nm true ,
-.Nm type ,
-.Nm ulimit ,
-.Nm umask ,
-.Nm unalias ,
-.Nm uncomplete ,
-.Nm unhash ,
-.Nm unlimit ,
-.Nm unset ,
-.Nm unsetenv ,
-.Nm until ,
-.Nm wait ,
-.Nm where ,
-.Nm which ,
-.Nm while
-.Nd shell built-in commands
+.Nm keybinds
+.Nd index of FreeBSD shell built-in commands
.Sh SYNOPSIS
-See the built-in command description in the appropriate shell manual page.
+See the manual for your shell for operation details.
.Sh DESCRIPTION
-Shell builtin commands are commands that can be executed within the
-running shell's process.
-Note that, in the case of
-.Xr csh 1
-builtin commands, the command is executed in a subshell if it occurs as
-any component of a pipeline except the last.
-.Pp
-If a command specified to the shell contains a slash
-.Ql / ,
-the shell will not execute a builtin command, even if the last component
-of the specified command matches the name of a builtin command.
-Thus, while specifying
-.Dq Li echo
-causes a builtin command to be executed under shells that support the
-.Nm echo
-builtin command,
-specifying
-.Dq Li /bin/echo
-or
-.Dq Li ./echo
-does not.
-.Pp
-While some builtin commands may exist in more than one shell, their
-operation may be different under each shell which supports them.
-Below is a table which lists shell builtin commands, the standard shells
-that support them and whether they exist as standalone utilities.
-.Pp
-Only builtin commands for the
+This page provides an index of
+.Nm
+commands, keywords, and keyboard bindings provided by
.Xr csh 1
and
-.Xr sh 1
-shells are listed here.
-Consult a shell's manual page for
-details on the operation its builtin commands.
-Beware that the
-.Xr sh 1
-manual page, at least, calls some of these commands
-.Dq built-in commands
-and some of them
-.Dq reserved words .
-Users of other shells may need to consult an
-.Xr info 1
-page or other sources of documentation.
-.Pp
-Commands marked
-.Dq Li No**
-under
-.Em External
-do exist externally,
-but are implemented as scripts using a builtin command of the same name.
-.Bl -column ".Ic uncomplete" ".Em External" ".Xr csh 1" ".Xr sh 1" -offset indent
-.It Em Command Ta Em External Ta Xr csh 1 Ta Xr sh 1
+.Xr sh 1 ,
+the command line interpreters which comprise the
+.Bx
+user environment.
+.Ss Commands
+Below is a table which lists
+.Nm
+commands and keywords,
+whether they exist as standalone utilities,
+and the standard shells that provide them.
+.Bl -column "uncomplete" "Standalone" "csh(1)" "sh(1)" -offset indent
+.It Em Command Ta Em Standalone Ta Xr csh 1 Ta Xr sh 1
.It Ic \&! Ta \&No Ta \&No Ta Yes
.It Ic % Ta \&No Ta Yes Ta \&No
.It Ic \&. Ta \&No Ta \&No Ta Yes
@@ -201,9 +61,9 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic \&[ Ta Yes Ta \&No Ta Yes
.It Ic { Ta \&No Ta \&No Ta Yes
.It Ic } Ta \&No Ta \&No Ta Yes
-.It Ic alias Ta No** Ta Yes Ta Yes
+.It Ic alias Ta No* Ta Yes Ta Yes
.It Ic alloc Ta \&No Ta Yes Ta \&No
-.It Ic bg Ta No** Ta Yes Ta Yes
+.It Ic bg Ta No* Ta Yes Ta Yes
.It Ic bind Ta \&No Ta \&No Ta Yes
.It Ic bindkey Ta \&No Ta Yes Ta \&No
.It Ic break Ta \&No Ta Yes Ta Yes
@@ -211,9 +71,9 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic builtin Ta \&No Ta \&No Ta Yes
.It Ic builtins Ta \&No Ta Yes Ta \&No
.It Ic case Ta \&No Ta Yes Ta Yes
-.It Ic cd Ta No** Ta Yes Ta Yes
+.It Ic cd Ta No* Ta Yes Ta Yes
.It Ic chdir Ta \&No Ta Yes Ta Yes
-.It Ic command Ta No** Ta \&No Ta Yes
+.It Ic command Ta No* Ta \&No Ta Yes
.It Ic complete Ta \&No Ta Yes Ta \&No
.It Ic continue Ta \&No Ta Yes Ta Yes
.It Ic default Ta \&No Ta Yes Ta \&No
@@ -233,22 +93,22 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic exit Ta \&No Ta Yes Ta Yes
.It Ic export Ta \&No Ta \&No Ta Yes
.It Ic false Ta Yes Ta \&No Ta Yes
-.It Ic fc Ta No** Ta \&No Ta Yes
-.It Ic fg Ta No** Ta Yes Ta Yes
+.It Ic fc Ta No* Ta \&No Ta Yes
+.It Ic fg Ta No* Ta Yes Ta Yes
.It Ic filetest Ta \&No Ta Yes Ta \&No
.It Ic fi Ta \&No Ta \&No Ta Yes
.It Ic for Ta \&No Ta \&No Ta Yes
.It Ic foreach Ta \&No Ta Yes Ta \&No
-.It Ic getopts Ta No** Ta \&No Ta Yes
+.It Ic getopts Ta No* Ta \&No Ta Yes
.It Ic glob Ta \&No Ta Yes Ta \&No
.It Ic goto Ta \&No Ta Yes Ta \&No
-.It Ic hash Ta No** Ta \&No Ta Yes
+.It Ic hash Ta No* Ta \&No Ta Yes
.It Ic hashstat Ta \&No Ta Yes Ta \&No
.It Ic history Ta \&No Ta Yes Ta \&No
.It Ic hup Ta \&No Ta Yes Ta \&No
.It Ic if Ta \&No Ta Yes Ta Yes
.It Ic jobid Ta \&No Ta \&No Ta Yes
-.It Ic jobs Ta No** Ta Yes Ta Yes
+.It Ic jobs Ta No* Ta Yes Ta Yes
.It Ic kill Ta Yes Ta Yes Ta Yes
.It Ic limit Ta \&No Ta Yes Ta \&No
.It Ic local Ta \&No Ta \&No Ta Yes
@@ -265,7 +125,7 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic printf Ta Yes Ta \&No Ta Yes
.It Ic pushd Ta \&No Ta Yes Ta \&No
.It Ic pwd Ta Yes Ta \&No Ta Yes
-.It Ic read Ta No** Ta \&No Ta Yes
+.It Ic read Ta No* Ta \&No Ta Yes
.It Ic readonly Ta \&No Ta \&No Ta Yes
.It Ic rehash Ta \&No Ta Yes Ta \&No
.It Ic repeat Ta \&No Ta Yes Ta \&No
@@ -288,26 +148,68 @@ but are implemented as scripts using a builtin command of the same name.
.It Ic times Ta \&No Ta \&No Ta Yes
.It Ic trap Ta \&No Ta \&No Ta Yes
.It Ic true Ta Yes Ta \&No Ta Yes
-.It Ic type Ta No** Ta \&No Ta Yes
-.It Ic ulimit Ta No** Ta \&No Ta Yes
-.It Ic umask Ta No** Ta Yes Ta Yes
-.It Ic unalias Ta No** Ta Yes Ta Yes
+.It Ic type Ta No* Ta \&No Ta Yes
+.It Ic ulimit Ta No* Ta \&No Ta Yes
+.It Ic umask Ta No* Ta Yes Ta Yes
+.It Ic unalias Ta No* Ta Yes Ta Yes
.It Ic uncomplete Ta \&No Ta Yes Ta \&No
.It Ic unhash Ta \&No Ta Yes Ta \&No
.It Ic unlimit Ta \&No Ta Yes Ta \&No
.It Ic unset Ta \&No Ta Yes Ta Yes
.It Ic unsetenv Ta \&No Ta Yes Ta \&No
.It Ic until Ta \&No Ta \&No Ta Yes
-.It Ic wait Ta No** Ta Yes Ta Yes
+.It Ic wait Ta No* Ta Yes Ta Yes
.It Ic where Ta \&No Ta Yes Ta \&No
.It Ic which Ta Yes Ta Yes Ta \&No
.It Ic while Ta \&No Ta Yes Ta Yes
.El
+.Pp
+\&No*: Commands marked
+.Ql No*
+exist externally, but are implemented as scripts using a
+.Nm
+command of the same name.
+.Ss Keybinds
+The command line environment also provides the following
+default keyboard bindings:
+.Bl -column "Process Info (SIGINFO)" "^M | ^J" "^M | ^J" -offset indent
+.It Em Signal Ta Xr csh 1 Ta Xr sh 1
+.It Ic Backspace Ta ^H Ta ^H
+.It Ic Carriage Return Ta ^M | ^J Ta ^M | ^J
+.It Ic Tab Ta ^I Ta ^I
+.It Ic Beginning of Line Ta ^A Ta ^A
+.It Ic End of Line Ta ^E Ta ^E
+.It Ic Cursor Forward Ta ^F Ta ^F
+.It Ic Cursor Backward Ta ^B Ta ^B
+.It Ic Clear Screen Ta ^L Ta ^L
+.It Ic Cut Line Ta ^U Ta ^U
+.It Ic Cut Word Backwards Ta ^W Ta ^W
+.It Ic Cut Rest of Line Ta ^K Ta ^K
+.It Ic Paste Last Cut Ta ^Y Ta ^Y
+.It Ic Typo Ta ^T Ta ^T
+.It End of File Po Ic EOF Pc Ta ^D Ta ^D
+.It Interupt Po Ic SIGINT Pc Ta ^C Ta ^C
+.It Process info Po Ic SIGINFO Pc Ta ^T Ta ^T
+.It Ic Search History Ta \&No Ta ^R
+.It Ic Exit Search History Ta \&No Ta ^G
+.It Ic Previous Command Ta ^P Ta ^P
+.It Ic Next Command Ta ^N Ta ^N
+.It Ic Print Next Character Ta ^V Ta ^V
+.It Ic Pause Job Ta ^S Ta ^S
+.It Ic Resume Job Ta ^Q Ta ^Q
+.It Suspend Job Ic (SIGTSTP) Ta ^Z Ta ^Z
+.It Ic Scrollback Mode Ta ScrLk* Ta ScrLk*
+.El
+.Pp
+\&*: Bindings marked
+.Ql *
+are provided by
+.Xr vt 4 ,
+the console driver.
.Sh SEE ALSO
.Xr csh 1 ,
.Xr echo 1 ,
.Xr false 1 ,
-.Xr info 1 ,
.Xr kill 1 ,
.Xr login 1 ,
.Xr nice 1 ,
@@ -326,5 +228,18 @@ The
manual page first appeared in
.Fx 3.4 .
.Sh AUTHORS
+.An -nosplit
This manual page was written by
+.An Alexander Ziaee Aq Mt ziaee@FreeBSD.org
+from an earlier version by
.An Sheldon Hearn Aq Mt sheldonh@FreeBSD.org .
+.Sh CAVEATS
+While
+.Nm
+commands may exist in more than one shell or standalone,
+each may be implemented differently.
+.Pp
+Standalone utilities and their manuals must be called by their path
+from a shell with a
+.Nm
+command of the same name.
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 4f12e70f2ae4..505e83a67369 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -213,6 +213,7 @@ MAN= aac.4 \
${_hv_vmbus.4} \
${_hv_vss.4} \
hwpmc.4 \
+ ${_hwt.4} \
${_hwpstate_intel.4} \
i2ctinyusb.4 \
iavf.4 \
@@ -593,6 +594,7 @@ MAN= aac.4 \
tws.4 \
udp.4 \
udplite.4 \
+ ${_ufshci.4} \
unionfs.4 \
ure.4 \
vale.4 \
@@ -745,7 +747,6 @@ MLINKS+=lge.4 if_lge.4
MLINKS+=lo.4 loop.4
MLINKS+=lp.4 plip.4
MLINKS+=malo.4 if_malo.4
-MLINKS+=md.4 vn.4
MLINKS+=mem.4 kmem.4
MLINKS+=mfi.4 mfi_linux.4 \
mfi.4 mfip.4
@@ -926,6 +927,21 @@ _vmm.4= vmm.4
.endif
.endif
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "aarch64"
+_hwt.4= hwt.4
+.if ${MACHINE_CPUARCH} == "amd64"
+MLINKS+=hwt.4 intel_pt.4
+.endif
+.if ${MACHINE_CPUARCH} == "aarch64"
+MLINKS+=hwt.4 coresight.4
+MLINKS+=hwt.4 spe.4
+.endif
+.endif
+
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "aarch64"
+_ufshci.4= ufshci.4
+.endif
+
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" || \
${MACHINE_CPUARCH} == "aarch64"
_gve.4= gve.4
@@ -968,11 +984,14 @@ _ccd.4= ccd.4
.if ${MK_CDDL} != "no"
_dtrace_provs= dtrace_audit.4 \
+ dtrace_dtrace.4 \
+ dtrace_fbt.4 \
dtrace_io.4 \
dtrace_ip.4 \
dtrace_kinst.4 \
dtrace_lockstat.4 \
dtrace_proc.4 \
+ dtrace_profile.4 \
dtrace_sched.4 \
dtrace_sctp.4 \
dtrace_tcp.4 \
diff --git a/share/man/man4/bridge.4 b/share/man/man4/bridge.4
index 7ce734ae87eb..2dff393ebc29 100644
--- a/share/man/man4/bridge.4
+++ b/share/man/man4/bridge.4
@@ -36,7 +36,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd May 28, 2025
+.Dd July 5, 2025
.Dt IF_BRIDGE 4
.Os
.Sh NAME
@@ -271,6 +271,54 @@ by setting the
.Va net.link.bridge.log_stp
node using
.Xr sysctl 8 .
+.Sh VLAN SUPPORT
+The
+.Nm
+driver has full support for virtual LANs (VLANs).
+The bridge implements independent VLAN learning, i.e. MAC addresses are
+learned on a per-VLAN basis, and the same MAC address may be learned on
+multiple interfaces on different VLANs.
+Incoming frames with an 802.1Q tag will be assigned to the appropriate
+VLAN.
+.Pp
+Traffic sent to or from the host is not assigned to a VLAN by default.
+To allow the host to communicate on a VLAN, configure a
+.Xr vlan 4
+interface on the bridge and (if necessary) assign IP addresses there.
+.Pp
+By default no access control is enabled, so any interface may
+participate in any VLAN.
+.Pp
+VLAN filtering may be enabled on an interface using the
+.Xr ifconfig 8
+.Cm vlanfilter
+option.
+When VLAN filtering is enabled, an interface may only send and receive
+frames based on its configured VLAN access list.
+.Pp
+The interface's untagged VLAN ID may be configured using the
+.Xr ifconfig 8
+.Cm untagged
+option.
+If an untagged VLAN ID is configured, incoming frames will be assigned
+to that VLAN, and the interface may receive outgoing untagged frames
+in that VLAN.
+.Pp
+The tagged VLAN access list may be configured using the
+.Cm tagged ,
+.Cm +tagged
+and
+.Cm -tagged
+options to
+.Xr ifconfig 8 .
+An interface may send and receive tagged frames for any VLAN in its
+access list.
+.Pp
+The bridge will automatically insert or remove 802.1q tags as needed,
+based on the interface configuration, when forwarding frames between
+interfaces.
+This tag processing is only done for interfaces with VLAN filtering
+enabled.
.Sh PACKET FILTERING
Packet filtering can be used with any firewall package that hooks in via the
.Xr pfil 9
@@ -538,6 +586,7 @@ ifconfig bridge0 addm fxp0 addm gif0 up
.Xr ipfw 4 ,
.Xr netmap 4 ,
.Xr pf 4 ,
+.Xr vlan 4 ,
.Xr ifconfig 8
.Sh HISTORY
The
diff --git a/share/man/man4/dtrace_dtrace.4 b/share/man/man4/dtrace_dtrace.4
new file mode 100644
index 000000000000..b8c31005b47e
--- /dev/null
+++ b/share/man/man4/dtrace_dtrace.4
@@ -0,0 +1,191 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Mateusz Piotrowski <0mp@FreeBSD.org>
+.\"
+.Dd July 14, 2025
+.Dt DTRACE_DTRACE 4
+.Os
+.Sh NAME
+.Nm dtrace_dtrace
+.Nd a DTrace provider for BEGIN, END, and ERROR probes
+.Sh SYNOPSIS
+.Nm dtrace Ns Cm :::BEGIN
+.Nm dtrace Ns Cm :::END
+.Nm dtrace Ns Cm :::ERROR
+.Sh DESCRIPTION
+The
+.Nm dtrace
+provider implements three special probes related to the life cycle of the
+DTrace program itself.
+.Ss dtrace:::BEGIN
+The
+.Nm dtrace Ns Cm :::BEGIN
+probe fires at the beginning of a
+.Xr dtrace 1 ,
+program before tracing has begun.
+It provides a convenient place for initializing variables
+and printing column headers.
+.Pp
+Variables such as
+.Va stack
+or
+.Va execname
+cannot be relied upon in the execution context of the
+.Nm dtrace Ns Cm :::BEGIN
+probe.
+.Ss dtrace:::END
+The
+.Nm dtrace Ns Cm :::END
+probe fires at the end of a
+.Xr dtrace 1
+program, when all tracing has stopped.
+.Ss dtrace:::ERROR
+The
+.Nm dtrace Ns Cm :::ERROR
+probe fires when an unexpected runtime error occurs in another probe.
+.Pp
+The following table describes the arguments to
+.Nm dtrace Ns Cm :::ERROR .
+.Bl -column -offset indent "Argument" "Definition"
+.It Sy Argument Ta Sy Definition
+.It Fa arg1 Ta Enabled probe identifier (EPID)
+of the probe where the runtime error occurred
+.It Fa arg2 Ta Index of the action statement that caused the error
+.It Fa arg3 Ta DIF offset into the action if available (otherwise -1)
+.It Fa arg4 Ta Fault type
+.It Fa arg5 Ta Accessed address (or 0 if not applicable) when
+.Va arg4
+is of fault type
+.Dv DTRACEFLT_BADADDR , DTRACEFLT_BADALIGN , DTRACEFLT_KPRIV ,
+or
+.Dv DTRACEFLT_UPRIV
+.El
+.Pp
+The fault types are:
+.Bl -tag -offset indent -width "DTRACEFLT_NOSCRATCH" -compact
+.It Dv DTRACEFLT_UNKNOWN
+Unknown fault
+.It Dv DTRACEFLT_BADADDR
+Bad address
+.It Dv DTRACEFLT_BADALIGN
+Bad alignment
+.It Dv DTRACEFLT_ILLOP
+Illegal operation
+.It Dv DTRACEFLT_DIVZERO
+Divide-by-zero
+.It Dv DTRACEFLT_NOSCRATCH
+Out of scratch space
+.It Dv DTRACEFLT_KPRIV
+Illegal kernel access
+.It Dv DTRACEFLT_UPRIV
+Illegal user access
+.It Dv DTRACEFLT_TUPOFLOW
+Tuple stack overflow
+.It Dv DTRACEFLT_BADSTACK
+Bad stack
+.El
+.Sh FILES
+.Bl -tag -width '<sys/dtrace.h>'
+.It In sys/dtrace.h
+The header file containing the definitions of DTrace fault types.
+.El
+.Sh EXAMPLES
+.Ss Example 1 : Custom Column Headers
+The following script uses the
+.Nm dtrace Ns Cm :::BEGIN
+probe to print column headers.
+Note the pragma line setting the
+.Ql quiet
+option to disable the default column headers.
+.Bd -literal -offset 2n
+#pragma D option quiet
+
+dtrace:::BEGIN
+{
+ printf(" %12s %-20s %-20s %s\en",
+ "DELTA(us)", "OLD", "NEW", "TIMESTAMP");
+}
+.Ed
+.Ss Example 2 : Handling Runtime Errors with dtrace:::ERROR
+The following script causes a runtime error by dereferencing a pointer
+on address
+.Ad 19930908
+in the
+.Cm BEGIN
+probe.
+As a result, the
+.Cm ERROR
+probe fires and prints out
+.Dq Oops
+along with the probe arguments.
+At that point, the program ends and fires the
+.Cm END
+probe.
+.\" It might look weird to define ERROR first, but that is on purpose.
+.\" This way the probe IDs and EPIDs are a bit more mixed up
+.\" and are easier to understand.
+.Bd -literal -offset 2n
+ERROR
+{
+ printf("Oops\en");
+ printf("EPID (arg1): %d\en", arg1);
+ printf("Action index (arg2): %d\en", arg2);
+ printf("DIF offset (arg3): %d\en", arg3);
+ printf("Fault type (arg4): %d\en", arg4);
+ printf("Accessed address (arg5): %X\en", arg5);
+ exit(1);
+}
+BEGIN
+{
+ *(int *)0x19931101;
+}
+END {
+ printf("Bye");
+}
+.Ed
+.Pp
+This script will result in the following output:
+.Bd -literal -offset 2n
+CPU ID FUNCTION:NAME
+ 2 3 :ERROR Oops
+EPID (arg1): 2
+Action index (arg2): 1
+DIF offset (arg3): 16
+Fault type: 1
+arg5: 19931101
+
+dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): invalid address (0x19931101) in action #1 at DIF offset 16
+ 2 2 :END Bye
+.Ed
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr tracing 7
+.Rs
+.%B The illumos Dynamic Tracing Guide
+.%O Chapter dtrace Provider
+.%D 2008
+.%U https://illumos.org/books/dtrace/chp-dtrace.html
+.Re
+.Sh AUTHORS
+This manual page was written by
+.An Mateusz Piotrowski Aq Mt 0mp@FreeBSD.org .
+.Sh CAVEATS
+The
+.Nm dtrace Ns Cm :::ERROR
+probe arguments cannot be accessed through the typed
+.Va args[]
+array.
+.Pp
+.Xr dtrace 1
+will not fire the
+.Nm dtrace Ns Cm :::ERROR
+probe recursively.
+If an error occurs in one of the action statements of the
+.Nm dtrace Ns Cm :::ERROR ,
+then
+.Xr dtrace 1
+will abort further processing of
+the
+.Nm dtrace Ns Cm :::ERROR
+probe's actions.
diff --git a/share/man/man4/dtrace_fbt.4 b/share/man/man4/dtrace_fbt.4
new file mode 100644
index 000000000000..3e35bb8c5bbc
--- /dev/null
+++ b/share/man/man4/dtrace_fbt.4
@@ -0,0 +1,332 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Mateusz Piotrowski <0mp@FreeBSD.org>
+.\"
+.Dd July 16, 2025
+.Dt DTRACE_FBT 4
+.Os
+.Sh NAME
+.Nm dtrace_fbt
+.Nd a DTrace provider for dynamic kernel tracing based on function boundaries
+.Sh SYNOPSIS
+.Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:entry
+.Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:return
+.Sh DESCRIPTION
+The Function Boundary Tracing
+.Pq Nm fbt
+provider instruments the entry and return of almost every kernel function
+corresponding to an
+.Xr elf 5
+symbol in the kernel and loaded kernel modules.
+.Pp
+.Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:entry
+fires whenever the
+.Ar function
+is called.
+.Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:return
+fires when the
+.Ar function
+returns.
+.Pp
+The
+.Ar module
+in the probe description is either the name of the loaded kernel module
+or
+.Ql kernel
+for functions compiled into the kernel.
+.Ss Function Boundary Instrumentation
+The
+.Nm fbt
+will always instrument a function's entry, but
+its return will be intsrumented so long as it can find a
+.Ql ret
+instruction.
+.Pp
+In some cases,
+.Nm fbt
+cannot instrument a function's entry and/or return.
+Refer to subsection
+.Sx Frame Pointer
+for more details.
+.Ss Probe Arguments
+The arguments of the entry probe
+.Pq Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:entry
+are the arguments of the traced function call.
+.Bl -column -offset indent "Entry Probe Argument" "Definition"
+.It Sy Entry Probe Argument Ta Sy Definition
+.It Fa args[0] Ta Function's first argument, typed
+.Pq e.g., Xr malloc 9 Ap s Ft size_t Fa size
+.It Fa args[1] Ta Function's second argument, typed
+.Pq e.g., Xr malloc 9 Ap s Ft struct malloc_type Fa *type
+.It Fa args[2] Ta Function's third argument, typed
+.Pq e.g., Xr malloc 9 Ap s Ft int Fa flags
+.It Fa ... Ta ...
+.El
+.Pp
+The arguments of the return probe
+.Pq Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:return
+are
+.Fa args[0]
+.Po
+the offset of the firing return instruction within the function;
+useful to tell apart two different return statements in a single function
+.Pc
+and
+.Fa args[1]
+.Pq the return value, if any .
+.Bl -column -offset indent "Return Probe Argument" "Definition"
+.It Sy Return Probe Argument Ta Sy Definition
+.It Fa args[0] Ta Offset of the traced return instruction
+.It Fa args[1] Ta Function's return value
+.Po e.g., a kernel virtual address if returning from a successful
+.Xr malloc 9
+.Pc
+.El
+.Pp
+Subsection
+.Sx Example 2 : Getting Details About Probe's Arguments
+shows how to get probe's argument count and types directly with
+.Xr dtrace 1
+without having to resort to the reading function's source code
+or documentation.
+.Sh EXAMPLES
+.Ss Example 1 : Listing Available FBT Probes
+The following example shows how to list all the available
+.Nm fbt
+probes.
+.Bd -literal -offset 2n
+# dtrace -l -P fbt
+ ID PROVIDER MODULE FUNCTION NAME
+[...]
+31868 fbt kernel hammer_time entry
+31869 fbt kernel hammer_time return
+[...]
+.Ed
+.Pp
+Since
+.Fn hammer_time
+is a part of the kernel and not a separate loaded module, the
+.Ar module
+column displays
+.Ql kernel .
+.Ss Example 2 : Getting Details About Probe's Arguments
+The following example shows how to generate a program stability report of
+.Xr malloc 9 Ap s
+entry and return probes.
+Those reports are useful to view
+the probe's number of arguments and their types.
+.Bd -literal -offset 2n
+# dtrace -l -v -n fbt::malloc:entry
+[...]
+ Argument Types
+ args[0]: size_t
+ args[1]: struct malloc_type *
+ args[2]: int
+.Ed
+.Pp
+The count and types of
+.Nm fbt Ns Cm \&::malloc:entry
+arguments
+match the function signature of
+.Xr malloc 9 :
+.Va args[0]
+is
+.Ft size_t ,
+.Va args[1]
+is
+.Ft "struct malloc_type *" ,
+and
+.Va "args[2]"
+is
+.Ft int .
+.Bd -literal -offset 2n
+# dtrace -l -v -n fbt::malloc:return
+[...]
+ Argument Types
+ args[0]: int
+ args[1]: void *
+.Ed
+.Pp
+The
+.Cm return
+probe reports two arguments and their types:
+the return instruction offset
+.Pq the usual Ft int
+and the function's return value, which in this case is
+.Ft void * ,
+as
+.Xr malloc 9
+returns a kernel virtual address.
+.Ss Example 3 : Counting Kernel Slab Memory Allocation by Function
+.Bd -literal -offset 2n
+# dtrace -n 'fbt::kmem*:entry { @[probefunc] = count(); }'
+dtrace: description 'fbt::kmem*:entry ' matched 47 probes
+^C
+ kmem_alloc_contig 1
+ kmem_alloc_contig_domainset 1
+ kmem_cache_reap_active 1
+ kmem_alloc_contig_pages 2
+ kmem_free 2
+ kmem_std_destructor 19
+ kmem_std_constructor 26
+ kmem_cache_free 151
+ kmem_cache_alloc 181
+.Ed
+.Ss Example 4 : Counting Kernel Slab Memory Allocation by Calling Function
+.Bd -literal -offset 2n
+# dtrace -q -n 'fbt::kmem*:entry { @[caller] = count(); } END { printa("%40a %@16d\en", @); }'
+^C
+ kernel`contigmalloc+0x33 1
+ kernel`free+0xd3 1
+ kernel`kmem_alloc_contig+0x29 1
+kernel`kmem_alloc_contig_domainset+0x19a 1
+ zfs.ko`arc_reap_cb_check+0x16 1
+.Ed
+.Ss Example 5 : Counting Kernel malloc()'s by Calling Function
+.Bd -literal -offset 2n
+# dtrace -q -n 'fbt::malloc:entry { @[caller] = count(); } END { printa("%45a %@16d\en", @); }'
+^C
+ kernel`devclass_get_devices+0xa8 1
+ kernel`sys_ioctl+0xb7 1
+ dtrace.ko`dtrace_ioctl+0x15c1 1
+ dtrace.ko`dtrace_ioctl+0x972 2
+ dtrace.ko`dtrace_dof_create+0x35 2
+ kernel`kern_poll_kfds+0x2f0 4
+ kernel`kern_poll_kfds+0x28a 19
+.Ed
+.Ss Example 6 : Counting Kernel malloc()'s by Kernel Stack Trace
+.Bd -literal -offset 2n
+# dtrace -q -n 'fbt::malloc:entry { @[stack()] = count(); }'
+^C
+ dtrace.ko`dtrace_dof_create+0x35
+ dtrace.ko`dtrace_ioctl+0x827
+ kernel`devfs_ioctl+0xd1
+ kernel`VOP_IOCTL_APV+0x2a
+ kernel`vn_ioctl+0xb6
+ kernel`devfs_ioctl_f+0x1e
+ kernel`kern_ioctl+0x286
+ kernel`sys_ioctl+0x12f
+ kernel`amd64_syscall+0x169
+ kernel`0xffffffff81092b0b
+ 2
+.Ed
+.Ss Example 7 : Summarizing vmem_alloc()'s by Arena Name and Size Distribution
+.Bd -literal -offset 2n
+# dtrace -q -n 'fbt::vmem_alloc:entry { @[args[0]->vm_name] = quantize(arg1); }'
+^C
+
+ kernel arena dom
+ value ------------- Distribution ------------- count
+ 2048 | 0
+ 4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 8192 |@@@@@@@@@@@@@ 2
+ 16384 | 0
+.Ed
+.Ss Example 8 : Measuring Total Time Spent Executing a Function
+This DTrace script measures the total time spent in
+.Fn vm_page*
+kernel functions.
+The
+.Fn quantize
+aggregation organizes the measurements into power-of-two buckets,
+providing a time distribution in nanoseconds for each function.
+.Bd -literal -offset 2n
+fbt::vm_page*:entry {
+ self->start = timestamp;
+}
+
+fbt::vm_page*:return /self->start/ {
+ @[probefunc] = quantize(timestamp - self->start);
+ self->start = 0;
+}
+.Ed
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr dtrace_kinst 4 ,
+.Xr tracing 7
+.Rs
+.%A Brendan Gregg
+.%A Jim Mauro
+.%B DTrace: Dynamic Tracing in Oracle Solaris, Mac OS X and FreeBSD
+.%I Prentice Hall
+.%P pp. 898\(en903
+.%D 2011
+.%U https://www.brendangregg.com/dtracebook/
+.Re
+.Rs
+.%B The illumos Dynamic Tracing Guide
+.%O Chapter fbt Provider
+.%D 2008
+.%U https://illumos.org/books/dtrace/chp-fbt.html#chp-fbt
+.Re
+.Sh AUTHORS
+This manual page was written by
+.An Mateusz Piotrowski Aq Mt 0mp@FreeBSD.org .
+.Sh CAVEATS
+.Ss Stability and Portability
+.Nm fbt
+probes are by definition tightly coupled to kernel code; if the code underlying
+a script changes, the script may fail to run or may produce incorrect results.
+Scripts written for one version of
+.Fx
+might not work on others,
+and almost certainly will not work on other operating systems.
+.Pp
+Individual
+.Nm fbt
+probes often do not correspond nicely to logical system events.
+For example, consider a DTrace script which prints the destination
+address of every IP packet as the kernel hands them over
+to the network card driver (NIC).
+An
+.Nm fbt Ns -based
+implementation of such a script is a discouragingly difficult task:
+it involves instrumenting at least four different functions in different parts
+of the IPv4 and IPv6 code.
+At the same time, with the
+.Xr dtrace_ip 4
+provider the script is a simple one-liner:
+.Dl dtrace -n 'ip:::send {printf("%s", args[2]->ip_daddr);}'
+.Pp
+Make sure to review available
+.Xr dtrace 1
+providers first
+before implementing a custom script with the
+.Nm fbt
+provider.
+If none of the DTrace providers offer the desired probes,
+consider adding new statically-defined tracing probes
+.Pq Xr SDT 9 .
+.Ss Frame Pointer
+Inline functions are not instrumentable by
+.Nm fbt
+as they lack a frame pointer.
+A developer might explicitly disable inlining by adding the
+.Ql __noinline
+attribute to a function definition,
+but of course this requires a recompilation of the kernel.
+Building the kernel with
+.Fl fno-omit-frame-pointer
+is another way of preserving frame pointers.
+Note, that sometimes compilers will omit the frame pointer in leaf functions,
+even when configured with
+.Fl fno-omit-frame-pointer .
+.Pp
+Function returns via a tail call are also not instrumentable by
+.Nm fbt .
+As a result,
+a function might have an entry probe
+and a mix of instrumented and uninstrumentable returns.
+.Pp
+Use
+.Xr dtrace_kinst 4
+to trace arbitrary instructions inside kernel functions
+and work around some of the
+limitations
+of
+.Nm fbt .
+.Ss Tracing DTrace
+The
+.Nm fbt
+provider cannot attach to functions inside DTrace provider kernel modules.
diff --git a/share/man/man4/dtrace_kinst.4 b/share/man/man4/dtrace_kinst.4
index 9debbc1bd106..c2187689749b 100644
--- a/share/man/man4/dtrace_kinst.4
+++ b/share/man/man4/dtrace_kinst.4
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 27, 2023
+.Dd July 16, 2025
.Dt DTRACE_KINST 4
.Os
.Sh NAME
@@ -43,10 +43,13 @@ creates probes on-demand, meaning it searches for and parses the function's
instructions each time
.Xr dtrace 1
is run, and not at module load time.
-This is in contrast to FBT's load-time parsing, since
+This is in contrast to
+.Xr dtrace_fbt 4 Ap s
+load-time parsing, since
.Nm kinst
can potentially create thousands of probes for just a single function, instead
-of up to two (entry and return) in the case of FBT.
+of up to two (entry and return) in the case of
+.Xr dtrace_fbt 4 .
A result of this is that
.Cm dtrace -l -P kinst
will not match any probes.
@@ -79,7 +82,8 @@ Trace all instructions in
# dtrace -n 'kinst::amd64_syscall:'
.Ed
.Sh SEE ALSO
-.Xr dtrace 1
+.Xr dtrace 1 ,
+.Xr dtrace_fbt 4
.Sh HISTORY
The
.Nm kinst
diff --git a/share/man/man4/dtrace_profile.4 b/share/man/man4/dtrace_profile.4
new file mode 100644
index 000000000000..07f86663d60a
--- /dev/null
+++ b/share/man/man4/dtrace_profile.4
@@ -0,0 +1,129 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Mateusz Piotrowski <0mp@FreeBSD.org>
+.\"
+.Dd July 14, 2025
+.Dt DTRACE_PROFILE 4
+.Os
+.Sh NAME
+.Nm dtrace_profile
+.Nd a DTrace provider for firing probes at a given time interval
+.Sh SYNOPSIS
+.Nm profile Ns Cm :::profile- Ns Ar rate Ns Op Ar unit
+.Nm profile Ns Cm :::tick- Ns Ar rate Ns Op Ar unit
+.Sh DESCRIPTION
+The
+.Nm profile
+provider implements three special probes related to the life cycle of the
+DTrace program itself.
+.Ss Probes
+The
+.Nm profile Ns Cm :::profile
+probes fire on all CPUs and are suitable for measuring the whole system
+periodically.
+.Pp
+The
+.Nm profile Ns Cm :::tick
+probes fire on a single CPU, potentially a different one every time.
+They are useful, e.g., for printing partial results periodically.
+.Ss Rate and Time Units
+The
+.Nm profile
+provider probes will fire at the specified
+.Ar rate .
+.Pp
+The default unit is
+.Cm hz .
+The
+.Nm profile
+provider supports the following time units:
+.Bl -column -offset indent "ns, nsec" "Definition"
+.It Sy Time Unit Ta Sy Definition
+.It Cm ns , nsec Ta nanoseconds
+.It Cm us , usec Ta microseconds
+.It Cm ms , msec Ta milliseconds
+.It Cm s , sec Ta seconds
+.It Cm m , min Ta minutes
+.It Cm h , hour Ta hours
+.It Cm d , day Ta days
+.It Cm hz Ta Hertz (frequency per second)
+.El
+.Ss Probe Arguments
+The arguments of the
+.Nm profile
+provider probes
+are:
+.Bl -tag -width arg0
+.It Va arg0
+The PC (program counter) in the kernel when the probe triggered,
+or 0 if the process was not in the kernel at that time.
+.It Va arg1
+The PC in the user process when the probe triggered,
+or 0 if the process was in the kernel when the probe triggered.
+.El
+.Pp
+Use arguments
+.Va arg0
+and
+.Va arg1
+to tell if the
+.Nm profile
+provider probe fired in the kernel or in the userspace context.
+.Sh IMPLEMENTATION NOTES
+The
+.Xr sysctl 8
+variable
+.Va kern.dtrace.profile.aframes
+controls the number of skipped artificial frames for
+the
+.Nm profile
+provider.
+.Sh EXAMPLES
+.Ss Example 1 : Profiling On-CPU Kernel Stack Traces
+The following DTrace one-liner uses the
+.Nm profile
+provider to collect stack traces over 60 seconds.
+.\" XXX: Keep on one line for easier copy-pasting.
+.Bd -literal -offset indent
+dtrace -x stackframes=100 -n 'profile-197 /arg0/ {@[stack()] = count();} tick-60s {exit(0);}
+.Ed
+.Pp
+The system is profiled at the 197 Hz to avoid sampling in lockstep
+with other periodic activities.
+This unnatural frequency minimizes the chance of overlapping with other events.
+.Pp
+Option
+.Fl x Cm stackframes=100
+increases the maximum number of kernel stack frames to unwind during
+.Fn stack .
+.Pp
+Checking if
+.Ar arg0
+is not zero makes sure that profiling happens
+when the program is in the kernel context.
+.Pp
+Refer to
+.Lk https://www.brendangregg.com/flamegraphs.html
+to learn about generating flame graphs from the obtained stack traces.
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr tracing 7
+.Rs
+.%B The illumos Dynamic Tracing Guide
+.%O Chapter profile Provider
+.%D 2008
+.%U https://www.illumos.org/books/dtrace/chp-profile.html
+.Re
+.Rs
+.%A Brendan Gregg
+.%A Jim Mauro
+.%B DTrace: Dynamic Tracing in Oracle Solaris, Mac OS X and FreeBSD
+.%I Prentice Hall
+.%P pp. 24\(en25
+.%D 2011
+.%U https://www.brendangregg.com/dtracebook/
+.Re
+.Sh AUTHORS
+This manual page was written by
+.An Mateusz Piotrowski Aq Mt 0mp@FreeBSD.org .
diff --git a/share/man/man4/gif.4 b/share/man/man4/gif.4
index 959510451011..ad33d5d21e81 100644
--- a/share/man/man4/gif.4
+++ b/share/man/man4/gif.4
@@ -1,6 +1,7 @@
.\" $KAME: gif.4,v 1.28 2001/05/18 13:15:56 itojun Exp $
.\"
.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" Copyright (C) 2024 Hiroki Sato <hrs@FreeBSD.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -27,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 21, 2018
+.Dd July 14, 2025
.Dt GIF 4
.Os
.Sh NAME
@@ -67,8 +68,8 @@ variable in
.Pp
To use
.Nm ,
-the administrator needs to configure the protocol and addresses used for the outer
-header.
+the administrator needs to configure the protocol and addresses used for
+the outer header.
This can be done by using
.Xr ifconfig 8
.Cm tunnel ,
@@ -79,8 +80,7 @@ The administrator also needs to configure the protocol and addresses for the
inner header, with
.Xr ifconfig 8 .
Note that IPv6 link-local addresses
-(those that start with
-.Li fe80:: )
+.Pq those that start with Li fe80\&:\&:
will be automatically configured whenever possible.
You may need to remove IPv6 link-local addresses manually using
.Xr ifconfig 8 ,
@@ -89,12 +89,139 @@ if you want to disable the use of IPv6 as the inner header
Finally, you must modify the routing table to route the packets through the
.Nm
interface.
+.Ss MTU Configuration and Path MTU Discovery
+The
+.Nm
+interface uses the fixed length,
+.Li 1280 ,
+to determine whether the outgoing IPv6 packets are split.
+This means the MTU value configured on the interface will be ignored
+when the outer protocol is IPv6.
+When the
+.Dv NOCLAMP
+interface flag is set,
+.Nm
+uses the same configured value as IPv4 communications.
+This behavior prevents potential issues when the path MTU is
+smaller than the interface MTU.
+This section describes the reason why the default behavior is different.
+The
+.Dv NOCLAMP
+interface flag can be set using the following command:
+.Pp
+.Dl ifconfig Ar gif0 Cm noclamp
+.Pp
+and clear the flag using the following:
+.Pp
+.Dl ifconfig Ar gif0 Cm -noclamp
+.Pp
+where
+.Ar gif0
+is the actual interface name.
+.Pp
+A tunnel interface always has an implicit smaller MTU for the inner protocol
+than the outer protocol because of the additional header.
+Note that the interface MTU on a
+.Nm
+interface,
+the default value is
+.Li 1280 ,
+is used as MTU for the outer protocol.
+This means that the MTU for the inner protocol varies depending on the
+outer protocol header length.
+If an outgoing packet bigger than the inner protocol MTU arrives at a
+.Nm
+interface for encapsulation,
+it will be split into fragments.
+Specifically,
+if IPv4 is used as the outer protocol,
+the inner is 20 octets smaller than the interface MTU.
+In the case of the default interface MTU,
+.Li 1280 ,
+inner packets bigger than
+.Li 1260
+will be fragmented.
+In the case of IPv6,
+the inner is 40 octets smaller than the outer.
+.Pp
+This fragmentation is not harmful though it can degrade the
+performance.
+Note that while an increased MTU on
+.Nm
+interface helps to mitigate this reduced performance issue,
+it can also cause packet losses on the intermediate narrowest path
+between the two communication endpoints in IPv6.
+IPv6 allows fragmentation only on the sender,
+not on the routers in the communication path.
+A big outgoing packet will be dropped on a router with a smaller MTU.
.Pp
+In normal IPv6 communication,
+an ICMPv6 Packet Too Big error will be sent back to the sender,
+who can adjust the packet length and re-send it.
+This process is performed in the upper protocols than L3,
+such as TCP,
+and makes the packet length shorter so that packets go through
+the path without fragmentation.
+This behavior is known as path MTU discovery.
+.Pp
+When using a
+.Nm
+interface,
+the Packet Too Big message is generated for the outer protocol.
+Since the
+.Nm
+interface does not translate this error to the inner protocol,
+the inner protocol sees it just as a packet loss with no useful
+information to adjust the length of the next packets.
+In this situation,
+path MTU discovery does not work,
+and communications of the inner protocol
+become stalled.
+.Pp
+In order to avoid this,
+a
+.Nm
+interface silently splits a packet of over 1240 octets into fragments to make
+the outer protocol packets equal or shorter than 1280 octets,
+even when the interface MTU is configured as larger than 1280.
+Note that this occurs only when the outer protocol is IPv6.
+.Li 1280
+is the smallest MTU in IPv6 and guarantees no packet loss occurs
+on intermediate routers.
+.Pp
+As mentioned earlier,
+the performance is sub-optimal if the actual path MTU is larger than
+.Li 1280 .
+A typical confusing scenario is as follows.
The
.Nm
-device can be configured to be ECN friendly.
-This can be configured by
-.Dv IFF_LINK1 .
+interface can have Ethernet,
+whose MTU is usually 1500,
+as the inner protocol.
+It is called an EtherIP tunnel,
+and can be configured by adding the
+.Nm
+interface as a member of
+.Xr if_bridge 4
+interface.
+The
+.Xr if_bridge 4
+interface forcibly changes the MTU of the
+.Nm
+interface with those for the other member interfaces,
+which are likely 1500.
+In this case,
+a situation in which the MTU of the
+.Nm
+interface is 1500 but fragmentation in 1280 octets always occurs.
+.Pp
+The default behavior is most conservative to prevent confusing packet loss.
+Depending on the network configuration,
+enabling the
+.Dv NOCLAMP
+interface flag might be helpful for better performance.
+It is crucial to ensure that the path MTU is equal to or larger than
+the interface MTU when enabling this flag.
.Ss ECN friendly behavior
The
.Nm
@@ -169,6 +296,7 @@ variable
to the desired level of nesting.
.Sh SEE ALSO
.Xr gre 4 ,
+.Xr if_bridge 4 ,
.Xr inet 4 ,
.Xr inet6 4 ,
.Xr ifconfig 8
@@ -199,7 +327,8 @@ There are many tunnelling protocol specifications, all
defined differently from each other.
The
.Nm
-device may not interoperate with peers which are based on different specifications,
+device may not interoperate with peers which are based on different
+specifications,
and are picky about outer header fields.
For example, you cannot usually use
.Nm
@@ -219,11 +348,14 @@ to 1240 or smaller, when the outer header is IPv6 and the inner header is IPv4.
.Pp
The
.Nm
-device does not translate ICMP messages for the outer header into the inner header.
+device does not translate ICMP messages for the outer header into the inner
+header.
.Pp
In the past,
.Nm
had a multi-destination behavior, configurable via
-.Dv IFF_LINK0
+.Dv NOCLAMP
flag.
The behavior is obsolete and is no longer supported.
+This flag is now used to determine whether performing fragmentation when
+the outer protocol is IPv6.
diff --git a/share/man/man4/hwt.4 b/share/man/man4/hwt.4
new file mode 100644
index 000000000000..299332c72542
--- /dev/null
+++ b/share/man/man4/hwt.4
@@ -0,0 +1,144 @@
+.\"
+.\" Copyright (c) 2025 Ruslan Bukin <br@bsdpad.com>
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd July 12, 2025
+.Dt HWT 4
+.Os
+.Sh NAME
+.Nm hwt
+.Nd Hardware Trace Framework
+.Sh SYNOPSIS
+.Cd "options HWT_HOOKS"
+.Cd "device hwt"
+.Pp
+At least one of:
+.Cd "device intel_pt"
+.Pq amd64
+.Cd "device coresight"
+.Pq arm64
+.Cd "device spe"
+.Pq arm64
+.Pp
+In
+.Xr rc.conf 5 :
+.Cd kld_list="hwt"
+.Sh DESCRIPTION
+The
+.Nm
+framework provides infrastructure for hardware-assisted tracing.
+It collects detailed information about software execution and stores it as
+events in highly compressed format into DRAM.
+The events cover information about control flow changes of a program, whether
+branches taken or not, exceptions taken, timing information, cycles elapsed and
+more.
+The information collected allows to reconstruct entire program flow of a given
+application without noticeable performance impact.
+.Sh HARDWARE
+The framework supports several tracing technologies found on
+.Cd arm64
+and
+.Cd amd64
+systems:
+.Pp
+.Bl -bullet -compact
+.It
+ARM Coresight
+.It
+ARM Statistical Profiling Extension (SPE)
+.It
+Intel Processor Trace (PT)
+.El
+.Pp
+The
+.Nm
+framework supports two modes of operation:
+.Bl -tag -width "Thread mode"
+.It Em CPU mode
+Capture CPU activity in kernel mode.
+.It Em Thread mode
+Capture activity of each of a process's threads in user mode.
+.El
+.Sh MANAGEMENT
+When loaded into kernel, the
+.Nm
+framework provides
+.Pa /dev/hwt
+character device.
+The only
+.Xr ioctl 2
+request it accepts is
+.Dv HWT_IOC_ALLOC .
+This request allocates kernel tracing context (CTX) based on requested mode of
+operation, set of CPUs and/or pid.
+.Pp
+Upon successful CTX allocation, the ioctl returns a CTX identification
+number (ident).
+.Pp
+Each CTX is then managed using its own dedicated character device found at
+.Pa "/dev/hwt_${ident}_${d}",
+where ident is a unique identification number of tracing context, d is either
+cpu_id (in HWT CPU mode) or process pid (in HWT Thread mode).
+.Sh HOOKS
+During tracing of a target process, HWT records runtime events such as threads
+creation, exec and mmap system calls.
+These events are logged as "records" within a particular CTX associated with
+traced process.
+.Pp
+Additionally, HWT can suspend the target thread upon exec or mmap system calls
+if requested by the user.
+This pause allows user-space tools to retrieve the records and adjust tracing
+settings before execution continues.
+This feature is especially useful when address range filtering is enabled,
+allowing tracing of specific functions within the target executable or a
+dynamic library.
+.Sh KERNEL OPTIONS
+The following options in the kernel configuration file are mandatory and
+related to
+.Nm
+operation:
+.Pp
+.Bl -tag -width ".Dv HWT_HOOKS" -compact
+.It Dv HWT_HOOKS
+Enable kernel hooks.
+.El
+.Sh IOCTL INTERFACE
+Once a CTX is allocated, its management character device accepts several
+.Xr ioctl 2
+requests:
+.Bl -tag -width "HWT_IOC_RECORD_GET"
+.It Dv HWT_IOC_START
+Start tracing.
+In HWT CPU mode the tracing does actually start with this
+.Xr ioctl 2
+request.
+In the Thread mode, the tracing "running" flag set, but tracing begins after
+scheduler switches the target thread onto CPU and return to user mode.
+.It Dv HWT_IOC_STOP
+Stop tracing of the particular CTX.
+.It Dv HWT_IOC_RECORD_GET
+Copy all or part of records collected during hook invocation and associated
+with this CTX to userspace.
+.It Dv HWT_IOC_BUFPTR_GET
+Get current pointer in buffer that is filled by tracing units in real-time.
+.It Dv HWT_IOC_SET_CONFIG
+Set architecture-specific config (optional).
+.It Dv HWT_IOC_WAKEUP
+Wake up a thread that has been put to sleep by HWT framework hooks.
+.It Dv HWT_IOC_SVC_BUF
+For SPE-only, the kernel is waiting for userspace to notify that it has copied
+out a buffer to avoid data loss/overwriting buffers.
+.El
+.Sh SEE ALSO
+.Xr tracing 7 ,
+.Xr hwt 8
+.Sh HISTORY
+The
+.Nm
+framework first appeared in
+.Fx 15.0 .
+.Sh AUTHORS
+.An Ruslan Bukin Aq Mt br@FreeBSD.org
+.An Bojan Novković Aq Mt bnovkov@freebsd.org
+.An Zachary Leaf Aq Mt zachary.leaf@arm.com
diff --git a/share/man/man4/md.4 b/share/man/man4/md.4
index 0c99d61f8392..1da26ddda037 100644
--- a/share/man/man4/md.4
+++ b/share/man/man4/md.4
@@ -5,7 +5,7 @@
.\" this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
.\" ----------------------------------------------------------------------------
.\"
-.Dd January 8, 2020
+.Dd July 16, 2025
.Dt MD 4
.Os
.Sh NAME
@@ -158,7 +158,7 @@ installation process.
The
.Nm
driver did a hostile takeover of the
-.Xr vn 4
+.Sy vn
driver in
.Fx 5.0 .
.Sh AUTHORS
diff --git a/share/man/man4/mtw.4 b/share/man/man4/mtw.4
index 17722be73203..6aa59d848d36 100644
--- a/share/man/man4/mtw.4
+++ b/share/man/man4/mtw.4
@@ -24,23 +24,41 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd Feb 03, 2025
+.Dd May 3, 2025
.Dt MTW 4
.Os
.Sh NAME
-.Nm if_mtw
-.Nd "Mediatek MT7601U"
-.Ed
+.Nm mtw
+.Nd MediaTek MT7601U USB IEEE 802.11n wireless network driver
+.Sh SYNOPSIS
+.Cd device usb
+.Cd device mtw
+.Cd device wlan
+.Pp
+In
+.Xr rc.conf 5 :
+.Cd kld_list="if_mtw"
.Sh DESCRIPTION
-This module provides support for Mediatek MT7601U with the firmware from net/wifi-firmware-mtw-kmod
-
+This module provides support for
+MediaTek MT7601U USB wireless network adapters.
+If the appropriate hardware is detected,
+the driver will be automatically loaded with
+.Xr devmatch 8 .
+If driver autoloading is explicitly disabled, enable the module in
+.Xr rc.conf 5 .
+The
+.Nm
+driver can be configured at runtime with
+.Xr ifconfig 8
+or at boot with
+.Xr rc.conf 5 .
.Sh HARDWARE
The
.Nm
-driver supports Mediatek MT7601U
-based USB wireless network adapters including (but not all of them tested):
+driver supports MediaTek MT7601U based USB wireless network adapters
+including (but not all of them tested):
.Pp
-.Bl -column -compact
+.Bl -bullet -compact
.It
ASUS USB-N10 v2
.It
@@ -58,17 +76,43 @@ TP-LINK TL-WN727N v4 (tested working)
.It
Yealink WF40
.El
+.Sh FILES
+The
+.Nm
+driver requires firmware from
+.Pa ports/net/wifi-firmware-mt7601u-kmod .
+This firmware package will be installed automatically with
+.Xr fwget 8
+if the appropriate hardware is detected at installation or runtime.
.Sh SEE ALSO
-.Xr usb 4
-.Sh BUGS
+.Xr usb 4 ,
+.Xr wlan 4 ,
+.Xr networking 7 ,
+.Xr fwget 8 ,
+.Xr wpa_supplicant 8
+.Sh HISTORY
The
.Nm
-only works in station mode and monitor mode. The firmware does not always reinitialize when reloading the module, or when rebooting, without first unplugging the device.
-.Sh History
-The mtw driver first appeared in OpenBSD 7.1. The mtw driver was ported to FreeBSD in FreeBSD 15.0.
+driver first appeared in
+.Ox 7.1
+and
+.Fx 15.0 .
.Sh AUTHORS
.An -nosplit
-The mtw driver was written by
+The
+.Nm
+driver was written by
.An James Hastings Aq Mt hastings@openbsd.org
-ported to FreeBSD by
-.An Jesper Schmitz Mouridsen Aq Mt jsm@FreeBSD.org
+and ported to
+.Fx
+by
+.An Jesper Schmitz Mouridsen Aq Mt jsm@FreeBSD.org .
+.Sh BUGS
+.Nm
+only works in
+.Cm station
+mode and
+.Cm monitor
+mode.
+The firmware does not always reinitialize when reloading the module,
+or when rebooting, without first unplugging the device.
diff --git a/share/man/man4/pf.4 b/share/man/man4/pf.4
index 422600a6fa44..03a4ba2bbe7f 100644
--- a/share/man/man4/pf.4
+++ b/share/man/man4/pf.4
@@ -26,7 +26,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 1, 2025
+.Dd July 2, 2025
.Dt PF 4
.Os
.Sh NAME
@@ -1114,7 +1114,7 @@ will be set to the length of the buffer actually used.
.It Dv DIOCCLRSRCNODES
Clear the tree of source tracking nodes.
.It Dv DIOCIGETIFACES Fa "struct pfioc_iface *io"
-Get the list of interfaces and interface drivers known to
+Get the list of interfaces and interface groups known to
.Nm .
All the ioctls that manipulate interfaces
use the same structure described below:
@@ -1131,7 +1131,7 @@ struct pfioc_iface {
.Pp
If not empty,
.Va pfiio_name
-can be used to restrict the search to a specific interface or driver.
+can be used to restrict the search to a specific interface or group.
.Va pfiio_buffer[pfiio_size]
is the user-supplied buffer for returning the data.
On entry,
diff --git a/share/man/man4/rights.4 b/share/man/man4/rights.4
index 0c24f6b45f88..8f5f6ad9c2d2 100644
--- a/share/man/man4/rights.4
+++ b/share/man/man4/rights.4
@@ -30,7 +30,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 1, 2024
+.Dd May 22, 2025
.Dt RIGHTS 4
.Os
.Sh NAME
@@ -319,6 +319,14 @@ Permit
.It Dv CAP_GETSOCKOPT
Permit
.Xr getsockopt 2 .
+.It Dv CAP_INOTIFY_ADD
+Permit
+.Xr inotify_add_watch 2
+and
+.Xr inotify_add_watch_at 2 .
+.It Dv CAP_INOTIFY_RM
+Permit
+.Xr inotify_rm_watch 2 .
.It Dv CAP_IOCTL
Permit
.Xr ioctl 2 .
diff --git a/share/man/man4/sa.4 b/share/man/man4/sa.4
index 96b11ebe5360..699a940a34d1 100644
--- a/share/man/man4/sa.4
+++ b/share/man/man4/sa.4
@@ -457,7 +457,8 @@ One EOM notification will be sent, BPEW status will be set for one position
query, and then the driver state will be reset to normal.
.Sh SEE ALSO
.Xr mt 1 ,
-.Xr cam 4
+.Xr cam 4 ,
+.Xr mtio 4
.Sh AUTHORS
.An -nosplit
The
diff --git a/share/man/man4/snd_uaudio.4 b/share/man/man4/snd_uaudio.4
index 00329a6d8e40..7193c85fa4f0 100644
--- a/share/man/man4/snd_uaudio.4
+++ b/share/man/man4/snd_uaudio.4
@@ -1,3 +1,6 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
.\" $NetBSD: uaudio.4,v 1.15 2002/02/12 19:53:57 jdolecek Exp $
.\"
.\" Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -27,32 +30,30 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd February 15, 2025
+.Dd July 17, 2025
.Dt SND_UAUDIO 4
.Os
.Sh NAME
.Nm snd_uaudio
.Nd USB audio and MIDI device driver
.Sh SYNOPSIS
-To compile this driver into the kernel, place the following lines in your
-kernel configuration file:
-.Bd -ragged -offset indent
.Cd "device sound"
.Cd "device usb"
.Cd "device snd_uaudio"
-.Ed
.Pp
-Alternatively, to load the driver as a module at boot time, place the
-following line in
-.Xr loader.conf 5 :
-.Bd -literal -offset indent
-snd_uaudio_load="YES"
-.Ed
-.Sh DESCRIPTION
-The
-.Nm
-driver provides support for USB audio class devices and USB MIDI class devices.
+In
+.Xr rc.conf 5 :
+.Cd kld_list="snd_uaudio"
.Pp
+In
+.Xr sysctl.conf 5 :
+.Cd hw.usb.uaudio.buffer_ms
+.Cd hw.usb.uaudio.default_bits
+.Cd hw.usb.uaudio.default_channels
+.Cd hw.usb.uaudio.default_rate
+.Cd hw.usb.uaudio.handle_hid
+.Cd hw.usb.uaudio.debug
+.Sh DESCRIPTION
A USB audio device consists of a number of components: input terminals (e.g.\&
USB digital input), output terminals (e.g.\& speakers), and a number of units
in between (e.g.\& volume control).
@@ -68,6 +69,11 @@ sample rate and sample size.
Refer to the
.Ql USB Audio Class Specification
for more information.
+.Sh HARDWARE
+The
+.Nm
+driver provides support for USB audio class devices and
+USB MIDI class devices.
.Sh SYSCTL VARIABLES
The following settings can be entered at the
.Xr loader 8
diff --git a/share/man/man4/ufshci.4 b/share/man/man4/ufshci.4
new file mode 100644
index 000000000000..d722c9902b98
--- /dev/null
+++ b/share/man/man4/ufshci.4
@@ -0,0 +1,181 @@
+.\"
+.\" Copyright (c) 2025, Samsung Electronics Co., Ltd.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" ufshci driver man page.
+.\"
+.\" Author: Jaeyoon Choi <j_yoon.choi@samsung.com>
+.\"
+.Dd July 17, 2025
+.Dt UFSHCI 4
+.Os
+.Sh NAME
+.Nm ufshci
+.Nd Universal Flash Storage Host Controller Interface driver
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following line in the kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device ufshci"
+.Ed
+.Pp
+Or, to load the driver as a module at boot, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+ufshci_load="YES"
+.Ed
+.Sh DESCRIPTION
+Universal Flash Storage (UFS) is a low-power, high-performance storage
+standard composed of a host controller and a single target device.
+.Pp
+The driver currently provides:
+.Bl -bullet
+.It
+Initialization of the host controller and the target device
+.It
+Handling of UFS Interconnect (UIC) commands
+.It
+Support for UTP Transfer Requests (UTR) and UTP Task Management Requests (UTMR)
+.It
+Support for the SCSI command set
+.It
+Operation in the legacy single-doorbell queue mode
+.It
+Support for the PCI Express bus
+.El
+.Pp
+After initialization, the controller is registered with the
+.Xr cam 4
+subsystem and its logical unit appears as the device node
+.Pa /dev/daX .
+.Pp
+The driver is under active development; upcoming work includes full
+UFS 4.1 feature coverage, additional power-management modes, and
+ACPI/FDT-based attach support.
+.Sh HARDWARE
+The
+.Nm
+driver supports both host controllers and devices implementing the
+Universal Flash Storage Host Controller Interface 4.1 and earlier.
+.Sh CONFIGURATION
+The
+.Nm
+driver currently operates with a single doorbell (one I/O-queue), so any
+tunables that change the queue count are ignored.
+When Multi-Circular Queue (MCQ) support is added and multiple queues
+become available, the following queue count tunable values will take effect:
+.Pp
+To force a single I/O queue pair shared by all CPUs, set the following
+tunable value in loader.conf(5):
+.Bd -literal -offset indent
+hw.ufshci.per_cpu_io_queues=0
+.Ed
+.Pp
+To assign more than one CPU per I/O queue pair, thereby reducing the
+number of MSI-X vectors consumed by the device, set the following tunable
+value in loader.conf(5):
+.Bd -literal -offset indent
+hw.ufshci.min_cpus_per_ioq=X
+.Ed
+.Pp
+To change the I/O command timeout value (in seconds), set the following tunable
+value in loader.conf(5):
+.Bd -literal -offset indent
+hw.ufshci.timeout_period=X
+.Ed
+.Pp
+To change the I/O command retry count, set the following tunable value in
+loader.conf(5):
+.Bd -literal -offset indent
+hw.ufshci.retry_count=X
+.Ed
+.Pp
+To force the driver to use legacy INTx interrupts, set the following tunable
+value in loader.conf(5):
+.br
+(Note: until MCQ support is available the driver always uses legacy INTx, so
+this value effectively remains 1)
+.Bd -literal -offset indent
+hw.ufshci.force_intx=1
+.Ed
+.Sh SYSCTL VARIABLES
+The following controller-level
+.Xr sysctl 8
+nodes are currently implemented:
+.Bl -tag -width indent
+.It Va dev.ufshci.0.num_failures
+(R) Number of command failures for the entire controller.
+.It Va dev.ufshci.0.num_retries
+(R) Number of command retries for the entire controller.
+.It Va dev.ufshci.0.num_intr_handler_calls
+(R) Number of times the interrupt handler has been called.
+.It Va dev.ufshci.0.num_cmds
+(R) Total number of commands issued by the controller.
+.It Va dev.ufshci.0.timeout_period
+(RW) Configured timeout period (in seconds).
+.It Va dev.ufshci.0.cap
+(R) Host controller capabilities register value.
+.It Va dev.ufshci.0.num_io_queues
+(R) Number of I/O-queue pairs.
+.It Va dev.ufshci.0.io_queue_mode
+(R) Indicates single doorbell mode or multi circular queue mode.
+.It Va dev.ufshci.0.minor_version
+(R) Host controller minor version.
+.It Va dev.ufshci.0.major_version
+(R) Host controller major version.
+.It Va dev.ufshci.0.utmrq.num_failures
+(R) Number of failed UTP task-management requests.
+.It Va dev.ufshci.0.utmrq.ioq.num_retries
+(R) Number of retried UTP task-management requests.
+.It Va dev.ufshci.0.utmrq.num_intr_handler_calls
+(R) Number of interrupt handler calls caused by UTP task-management requests.
+.It Va dev.ufshci.0.utmrq.num_cmds
+(R) Number of UTP task-management requests issued.
+.It Va dev.ufshci.0.utmrq.cq_head
+(R) Current location of the UTP task-management completion queue head.
+.It Va dev.ufshci.0.utmrq.sq_tail
+(R) Current location of the UTP task-management submission queue tail.
+.It Va dev.ufshci.0.utmrq.sq_head
+(R) Current location of the UTP task-management submission queue head.
+.It Va dev.ufshci.0.utmrq.num_trackers
+(R) Number of trackers in the UTP task-management queue.
+.It Va dev.ufshci.0.utmrq.num_entries
+(R) Number of entries in the UTP task-management queue.
+.It Va dev.ufshci.0.ioq.0.num_failures
+(R) Number of failed UTP transfer requests.
+.It Va dev.ufshci.0.ioq.0.num_retries
+(R) Number of retried UTP transfer requests.
+.It Va dev.ufshci.0.ioq.0.num_intr_handler_calls
+(R) Number of interrupt-handler calls caused by UTP transfer requests.
+.It Va dev.ufshci.0.ioq.0.num_cmds
+(R) Number of UTP transfer requests issued.
+.It Va dev.ufshci.0.ioq.0.cq_head
+(R) Current location of the UTP transfer completion queue head.
+.It Va dev.ufshci.0.ioq.0.sq_tail
+(R) Current location of the UTP transfer submission queue tail.
+.It Va dev.ufshci.0.ioq.0.sq_head
+(R) Current location of the UTP transfer submission queue head.
+.It Va dev.ufshci.0.ioq.0.num_trackers
+(R) Number of trackers in the UTP transfer queue.
+.It Va dev.ufshci.0.ioq.0.num_entries
+(R) Number of entries in the UTP transfer queue.
+.El
+.Sh SEE ALSO
+.Xr cam 4 ,
+.Xr pci 4 ,
+.Xr disk 9
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 15.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was developed by Samsung Electronics and originally written by
+.An Jaeyoon Choi Aq Mt j_yoon.choi@samsung.com .
+.Pp
+This manual page was written by
+.An Jaeyoon Choi Aq Mt j_yoon.choi@samsung.com .
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index 3c9706063a65..8954e872c231 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -27,7 +27,7 @@
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd June 26, 2025
+.Dd July 9, 2025
.Dt PF.CONF 5
.Os
.Sh NAME
@@ -365,7 +365,7 @@ set timeout { adaptive.start 60000, adaptive.end 120000 }
set limit states 100000
.Ed
.Pp
-With 9000 state table entries, the timeout values are scaled to 50%
+With 90000 state table entries, the timeout values are scaled to 50%
(tcp.first 60, tcp.established 43200).
.It Ar set loginterface
Enable collection of packet and byte count statistics for the given
@@ -542,6 +542,9 @@ an ICMP UNREACHABLE is returned for blocked UDP packets,
and all other packets are silently dropped.
.El
.Pp
+The default value is
+.Cm drop .
+.Pp
For example:
.Bd -literal -offset indent
set block-policy return
@@ -666,6 +669,8 @@ but can be overridden via this option.
Setting this option may leave a small period of time where the fingerprints
referenced by the currently active ruleset are inconsistent until the new
ruleset finishes loading.
+The default location for fingerprints is
+.Pa /etc/pf.os .
.Pp
For example:
.Pp
@@ -1382,7 +1387,7 @@ part of the new destination address according to the specified subnet.
It is possible to embed a complete IPv4 address into an IPv6 address
using a network prefix of /96 or smaller.
.Pp
-When a destination address is not specified it is assumed that the host
+When a destination address is not specified, it is assumed that the host
part is 32-bit long.
For IPv6 to IPv4 translation this would mean using only the lower 32
bits of the original IPv6 destination address.
@@ -2042,6 +2047,21 @@ connections:
block out proto { tcp, udp } all
pass out proto { tcp, udp } all user { < 1000, dhartmei }
.Ed
+.Pp
+The example below permits users with uid between 1000 and 1500
+to open connections:
+.Bd -literal -offset indent
+block out proto tcp all
+pass out proto tcp from self user { 999 >< 1501 }
+.Ed
+.Pp
+The
+.Sq \&:
+operator, which works for port number matching, does not work for
+.Cm user
+and
+.Cm group
+match.
.It Xo Ar flags Aq Ar a
.Pf / Ns Aq Ar b
.No \*(Ba / Ns Aq Ar b
@@ -2102,10 +2122,10 @@ options, or scrubbed with
will also not be recoverable from intermediate packets.
Such connections will stall and time out.
.It Xo Ar icmp-type Aq Ar type
-.Ar code Aq Ar code
+.Ar Op code Aq Ar code
.Xc
.It Xo Ar icmp6-type Aq Ar type
-.Ar code Aq Ar code
+.Ar Op code Aq Ar code
.Xc
This rule only applies to ICMP or ICMPv6 packets with the specified type
and code.
@@ -2554,6 +2574,7 @@ will not work if
.Xr pf 4
operates on a
.Xr bridge 4 .
+Also they act on incoming SYN packets only.
.Pp
Example:
.Bd -literal -offset indent
@@ -2763,8 +2784,8 @@ This means that it will not work on other protocols and will not match
a currently established connection.
.Pp
Caveat: operating system fingerprints are occasionally wrong.
-There are three problems: an attacker can trivially craft his packets to
-appear as any operating system he chooses;
+There are three problems: an attacker can trivially craft packets to
+appear as any operating system;
an operating system patch could change the stack behavior and no fingerprints
will match it until the database is updated;
and multiple operating systems may have the same fingerprint.
@@ -3091,7 +3112,7 @@ rule can also contain a filter ruleset in a brace-delimited block.
In that case, no separate loading of rules into the anchor
is required.
Brace delimited blocks may contain rules or other brace-delimited blocks.
-When an anchor is populated this way the anchor name becomes optional.
+When an anchor is populated this way, the anchor name becomes optional.
.Bd -literal -offset indent
anchor "external" on $ext_if {
block
diff --git a/share/man/man5/rc.conf.5 b/share/man/man5/rc.conf.5
index 2fd63e4f743d..de2181d638d1 100644
--- a/share/man/man5/rc.conf.5
+++ b/share/man/man5/rc.conf.5
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 21, 2025
+.Dd July 15, 2025
.Dt RC.CONF 5
.Os
.Sh NAME
@@ -1164,8 +1164,8 @@ and
is not found.
Multiple rules can be set as follows:
.Bd -literal
-pf_fallback_rules="\\
- block drop log all\\
+pf_fallback_rules="
+ block drop log all
pass in quick on em0"
.Pp
.Ed
diff --git a/share/man/man5/src.conf.5 b/share/man/man5/src.conf.5
index aecdde416578..a3db00aed42f 100644
--- a/share/man/man5/src.conf.5
+++ b/share/man/man5/src.conf.5
@@ -1,5 +1,5 @@
.\" DO NOT EDIT-- this file is @generated by tools/build/options/makeman.
-.Dd June 20, 2025
+.Dd July 14, 2025
.Dt SRC.CONF 5
.Os
.Sh NAME
@@ -493,7 +493,7 @@ Do not build
.Xr cxgbetool 8
.Pp
This is a default setting on
-arm/armv7, powerpc/powerpc and riscv/riscv64.
+arm/armv7 and riscv/riscv64.
.It Va WITH_CXGBETOOL
Build
.Xr cxgbetool 8
@@ -655,7 +655,7 @@ and
.Xr efivar 8 .
.Pp
This is a default setting on
-i386/i386, powerpc/powerpc, powerpc/powerpc64 and powerpc/powerpc64le.
+i386/i386, powerpc/powerpc64 and powerpc/powerpc64le.
.It Va WITH_EFI
Build
.Xr efivar 3
@@ -687,7 +687,7 @@ Build Flattened Device Tree support as part of the base system.
This includes the device tree compiler (dtc) and libfdt support library.
.Pp
This is a default setting on
-arm/armv7, arm64/aarch64, powerpc/powerpc, powerpc/powerpc64, powerpc/powerpc64le and riscv/riscv64.
+arm/armv7, arm64/aarch64, powerpc/powerpc64, powerpc/powerpc64le and riscv/riscv64.
.It Va WITHOUT_FILE
Do not build
.Xr file 1
@@ -750,7 +750,7 @@ Do not build HTML docs.
Do not build or install HyperV utilities.
.Pp
This is a default setting on
-arm/armv7, powerpc/powerpc, powerpc/powerpc64, powerpc/powerpc64le and riscv/riscv64.
+arm/armv7, powerpc/powerpc64, powerpc/powerpc64le and riscv/riscv64.
.It Va WITH_HYPERV
Build or install HyperV utilities.
.Pp
@@ -916,7 +916,7 @@ On 64-bit platforms, do not build 32-bit library set and a
runtime linker.
.Pp
This is a default setting on
-arm/armv7, i386/i386, powerpc/powerpc, powerpc/powerpc64le and riscv/riscv64.
+arm/armv7, i386/i386, powerpc/powerpc64le and riscv/riscv64.
.It Va WITH_LIB32
On 64-bit platforms, build the 32-bit library set and a
.Nm ld-elf32.so.1
@@ -935,7 +935,7 @@ arm/armv7 and riscv/riscv64.
Build the LLDB debugger.
.Pp
This is a default setting on
-amd64/amd64, arm64/aarch64, i386/i386, powerpc/powerpc, powerpc/powerpc64 and powerpc/powerpc64le.
+amd64/amd64, arm64/aarch64, i386/i386, powerpc/powerpc64 and powerpc/powerpc64le.
.It Va WITHOUT_LLD_BOOTSTRAP
Do not build the LLD linker during the bootstrap phase of
the build.
@@ -1038,7 +1038,7 @@ with support for verification based on certificates obtained from UEFI.
Disable inclusion of GELI crypto support in the boot chain binaries.
.Pp
This is a default setting on
-powerpc/powerpc, powerpc/powerpc64 and powerpc/powerpc64le.
+powerpc/powerpc64 and powerpc/powerpc64le.
.It Va WITH_LOADER_GELI
Build GELI bootloader support.
.Pp
@@ -1048,7 +1048,7 @@ amd64/amd64, arm/armv7, arm64/aarch64, i386/i386 and riscv/riscv64.
Do not build the 32-bit UEFI loader.
.Pp
This is a default setting on
-arm/armv7, arm64/aarch64, i386/i386, powerpc/powerpc, powerpc/powerpc64, powerpc/powerpc64le and riscv/riscv64.
+arm/armv7, arm64/aarch64, i386/i386, powerpc/powerpc64, powerpc/powerpc64le and riscv/riscv64.
.It Va WITH_LOADER_IA32
Build the 32-bit UEFI loader.
.Pp
@@ -1058,7 +1058,7 @@ amd64/amd64.
Do not build kboot, a linuxboot environment loader
.Pp
This is a default setting on
-arm/armv7, i386/i386, powerpc/powerpc, powerpc/powerpc64le and riscv/riscv64.
+arm/armv7, i386/i386, powerpc/powerpc64le and riscv/riscv64.
.It Va WITH_LOADER_KBOOT
Build kboot, a linuxboot environment loader
.Pp
@@ -1068,7 +1068,7 @@ amd64/amd64, arm64/aarch64 and powerpc/powerpc64.
Do not build LUA bindings for the boot loader.
.Pp
This is a default setting on
-powerpc/powerpc, powerpc/powerpc64 and powerpc/powerpc64le.
+powerpc/powerpc64 and powerpc/powerpc64le.
.It Va WITH_LOADER_LUA
Build LUA bindings for the boot loader.
.Pp
@@ -1083,7 +1083,7 @@ amd64/amd64, arm/armv7, arm64/aarch64, i386/i386 and riscv/riscv64.
Build openfirmware bootloader components.
.Pp
This is a default setting on
-powerpc/powerpc, powerpc/powerpc64 and powerpc/powerpc64le.
+powerpc/powerpc64 and powerpc/powerpc64le.
.It Va WITHOUT_LOADER_PXEBOOT
Do not build pxeboot on i386/amd64.
When the pxeboot is too large, or unneeded, it may be disabled with this option.
@@ -1104,7 +1104,7 @@ amd64/amd64, arm64/aarch64, i386/i386, powerpc/powerpc64le and riscv/riscv64.
Build ubldr.
.Pp
This is a default setting on
-arm/armv7, powerpc/powerpc and powerpc/powerpc64.
+arm/armv7 and powerpc/powerpc64.
.It Va WITH_LOADER_VERBOSE
Build with extra verbose debugging in the loader.
May explode already nearly too large loader over the limit.
@@ -1309,7 +1309,7 @@ Do not build
.Xr mlx5tool 8
.Pp
This is a default setting on
-arm/armv7, powerpc/powerpc and riscv/riscv64.
+arm/armv7 and riscv/riscv64.
.It Va WITH_MLX5TOOL
Build
.Xr mlx5tool 8
@@ -1401,7 +1401,7 @@ Build the
InfiniBand software stack, including kernel modules and userspace libraries.
.Pp
This is a default setting on
-amd64/amd64, arm64/aarch64, i386/i386, powerpc/powerpc, powerpc/powerpc64, powerpc/powerpc64le and riscv/riscv64.
+amd64/amd64, arm64/aarch64, i386/i386, powerpc/powerpc64, powerpc/powerpc64le and riscv/riscv64.
.It Va WITH_OFED_EXTRA
Build the non-essential components of the
.Dq "OpenFabrics Enterprise Distribution"
@@ -1412,7 +1412,7 @@ Enable building LDAP support for kerberos using an openldap client from ports.
Do not build LLVM's OpenMP runtime.
.Pp
This is a default setting on
-arm/armv7 and powerpc/powerpc.
+arm/armv7.
.It Va WITH_OPENMP
Build LLVM's OpenMP runtime.
.Pp
@@ -1465,7 +1465,7 @@ is set explicitly)
Do not include kernel TLS support in OpenSSL.
.Pp
This is a default setting on
-arm/armv7, i386/i386, powerpc/powerpc and riscv/riscv64.
+arm/armv7, i386/i386 and riscv/riscv64.
.It Va WITH_OPENSSL_KTLS
Include kernel TLS support in OpenSSL.
.Pp
@@ -1502,7 +1502,7 @@ Do not build dynamically linked binaries as
Position-Independent Executable (PIE).
.Pp
This is a default setting on
-arm/armv7, i386/i386 and powerpc/powerpc.
+arm/armv7 and i386/i386.
.It Va WITH_PIE
Build dynamically linked binaries as
Position-Independent Executable (PIE).
@@ -1570,6 +1570,8 @@ utility.
Build
.Xr rpcbind 8
with warmstart support.
+.It Va WITH_RUN_TESTS
+Run tests as part of the build.
.It Va WITHOUT_SCTP_SUPPORT
Disable support in the kernel for the
.Xr sctp 4
diff --git a/share/man/man5/style.Makefile.5 b/share/man/man5/style.Makefile.5
index cc5d2f6bb28a..fe8754924575 100644
--- a/share/man/man5/style.Makefile.5
+++ b/share/man/man5/style.Makefile.5
@@ -1,3 +1,6 @@
+.\"
+.\" SPDX-License-Identifier: BSD-3-Clause
+.\"
.\" Copyright (c) 2002-2003, 2023 David O'Brien <obrien@FreeBSD.org>
.\" All rights reserved.
.\"
@@ -30,10 +33,7 @@
.Os
.Sh NAME
.Nm style.Makefile
-.Nd
-.Fx
-.Pa Makefile
-file style guide
+.Nd FreeBSD Makefile style guide
.Sh DESCRIPTION
This file specifies the preferred style for makefiles in the
.Fx
diff --git a/share/man/man7/Makefile b/share/man/man7/Makefile
index 021bf9251bda..1e50242a1754 100644
--- a/share/man/man7/Makefile
+++ b/share/man/man7/Makefile
@@ -6,6 +6,7 @@ MAN= arch.7 \
bsd.snmpmod.mk.7 \
build.7 \
c.7 \
+ d.7 \
clocks.7 \
crypto.7 \
development.7 \
@@ -17,6 +18,7 @@ MAN= arch.7 \
intro.7 \
maclabel.7 \
mitigations.7 \
+ named_attribute.7 \
operator.7 \
orders.7 \
ports.7 \
diff --git a/share/man/man7/arch.7 b/share/man/man7/arch.7
index 91f6953370d9..fe4e8055a8b1 100644
--- a/share/man/man7/arch.7
+++ b/share/man/man7/arch.7
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 12, 2025
+.Dd July 14, 2025
.Dt ARCH 7
.Os
.Sh NAME
@@ -67,8 +67,7 @@ and
should be avoided.
.Pp
On some architectures, e.g.,
-.Dv powerpc
-and AIM variants of
+AIM variants of
.Dv powerpc64 ,
the kernel uses a separate address space.
On other architectures, kernel and a user mode process share a
@@ -88,9 +87,6 @@ release to support each architecture.
.It aarch64 Ta 11.0
.It amd64 Ta 5.1
.It armv7 Ta 12.0
-.It i386 Ta 1.0
-.It powerpc Ta 6.0
-.It powerpcspe Ta 12.0
.It powerpc64 Ta 9.0
.It powerpc64le Ta 13.0
.It riscv64 Ta 12.0
@@ -104,6 +100,7 @@ Discontinued architectures are shown in the following table.
.It armeb Ta 8.0 Ta 11.4
.It armv6 Ta 10.0 Ta 14.x
.It ia64 Ta 5.0 Ta 10.4
+.It i386 Ta 1.0 Ta 14.x
.It mips Ta 8.0 Ta 13.5
.It mipsel Ta 9.0 Ta 13.5
.It mipselhf Ta 12.0 Ta 13.5
@@ -114,6 +111,8 @@ Discontinued architectures are shown in the following table.
.It mips64elhf Ta 12.0 Ta 13.5
.It mips64hf Ta 12.0 Ta 13.5
.It pc98 Ta 2.2 Ta 11.4
+.It powerpc Ta 6.0 Ta 14.x
+.It powerpcspe Ta 12.0 Ta 14.x
.It riscv64sf Ta 12.0 Ta 13.5
.It sparc64 Ta 5.0 Ta 12.4
.El
diff --git a/share/man/man7/d.7 b/share/man/man7/d.7
new file mode 100644
index 000000000000..f4686d98b1d1
--- /dev/null
+++ b/share/man/man7/d.7
@@ -0,0 +1,287 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Mateusz Piotrowski <0mp@FreeBSD.org>
+.\"
+.Dd June 14, 2025
+.Dt D 7
+.Os
+.Sh NAME
+.Nm D
+.Nd DTrace scripting language overview
+.Sh SYNOPSIS
+.Sm off
+.Ar provider Cm \&:
+.Ar module Cm \&:
+.Ar function Cm \&:
+.Ar name
+.Sm on
+.Sm off
+.Oo
+.Cm /
+.Ar predicate
+.Cm /
+.Sm on
+.Oc
+.Op Cm \&{ Ns Ar action Ns Cm \&}
+.Sh DESCRIPTION
+.Nm D
+is the
+.Xr dtrace 1
+scripting language.
+This manual provides a brief reference of the
+.Nm
+language and scripting.
+.Pp
+This manual page serves as a short reference of the language.
+Refer to books listed in
+.Sx SEE ALSO
+for a complete reference.
+.Sh PROBE'S DESCRIPTION
+A probe's description consists of four elements:
+.Sm off
+.D1 Ar provider Ns Cm \&: Ns Ar module Cm \&: Ar function Cm \&: Ar name
+.Sm on
+.Pp
+The exact meaning of
+.Ar module ,
+.Ar function ,
+and
+.Ar name
+depends on
+.Ar provider .
+.Sh USER-DEFINED VARIABLE TYPES
+.Bl -column "thread-local" "Syntax"
+.It Sy Type Ta Sy Syntax
+.It global Ta Va variable_name
+.It thread-local Ta Sy self-> Ns Va variable_name
+.It clause-local Ta Sy this-> Ns Va variable_name
+.It aggregate Ta Sy @ Ns Va variable_name
+.El
+.Pp
+.Em Tips :
+.Bl -dash -compact
+.It
+Always use the variable type with the smallest scope
+to minimize processing overhead.
+.It
+Use aggregate variables instead of global variables when possible.
+Aggregate variables are multi-CPU safe in contrast to global variables.
+.El
+.Sh BUILT-IN VARIABLES
+.Ss Probe Arguments
+.Bl -tag -width "arg0, ..., arg9"
+.It Va args[]
+The array of typed probe arguments.
+.It Va arg0 , ... , arg9
+The untyped probe arguments represented as 64-bit unsigned integers.
+Only the first ten arguments are available this way.
+.El
+.Ss Probe Information
+.Bl -tag -width probeprov
+.It Va epid
+The enabled probe ID which uniquely identifies an enabled probe.
+An enabled probe is defined by its probe ID, its predicates, and its actions.
+.It Va id
+The probe ID which uniquely identifies a probe available to DTrace.
+.It Va probeprov
+The
+.Ar provider
+in the probe's description
+.Sm off
+.Pq Ar provider Cm \&: Ar module Cm \&: Ar function Cm \&: Ar name
+.Sm on .
+.It Va probemod
+The
+.Ar module
+in the probe's description
+.Sm off
+.Pq Ar provider Cm \&: Ar module Cm \&: Ar function Cm \&: Ar name
+.Sm on .
+.It Va probefunc
+The
+.Ar function
+in the probe's description
+.Sm off
+.Pq Ar provider Cm \&: Ar module Cm \&: Ar function Cm \&: Ar name
+.Sm on .
+.It Va probename
+The
+.Ar name
+in the probe's description
+.Sm off
+.Pq Ar provider Cm \&: Ar module Cm \&: Ar function Cm \&: Ar name
+.Sm on .
+.El
+.Ss Process Information
+.Bl -tag -width execname
+.It Va execargs
+The process arguments.
+Effectively,
+.Ql curthread->td_proc->p_args .
+.It Va execname
+The name of the current process.
+Effectively,
+.Ql curthread->td_proc->p_comm .
+.It Va gid
+The group ID of the current process.
+.It Va pid
+The process ID of the current process.
+.It Va ppid
+The parent process ID of the current process.
+.It Va uid
+The user ID of the current process.
+.El
+.Ss Thread Information
+.Bl -tag -width curlwpsinfo
+.It Va uregs[]
+The saved user-mode register values.
+.It Va cpu
+The ID of the current CPU.
+.It Va stackdepth
+The kernel stack frame depth.
+.It Va ustackdepth
+The userspace counterpart of
+.Va stackdepth .
+.It Va tid
+The thread ID.
+Depending on the context,
+this can be either the ID of a kernel thread or a thread in a user process.
+.It Va errno
+The
+.Xr errno 2
+value of the last system call performed by the current thread.
+.It Va curlwpsinfo
+A pointer to the
+.Vt lwpsinfo_t
+representation of the current thread.
+Refer to
+.Xr dtrace_proc 4
+for more details.
+.It Va curpsinfo
+A pointer to the
+.Vt psinfo_t
+representation of the current process.
+Refer to
+.Xr dtrace_proc 4
+for more details.
+.It Va curthread
+A pointer to the thread struct that is currently on-CPU.
+E.g.,
+.Ql curthread->td_name
+returns the thread name.
+The
+.In sys/proc.h
+header documents all members of
+.Vt struct thread .
+.It Va caller
+The address of the kernel thread instruction at the time of execution
+of the current probe.
+.It Va ucaller
+The userspace counterpart of
+.Va caller .
+.El
+.Ss Timestamps
+.Bl -tag -width walltimestamp
+.It Va timestamp
+The number of nanoseconds since boot.
+Suitable for calculating relative time differences of elapsed time and latency.
+.It Va vtimestamp
+The number of nanoseconds that the current thread spent on CPU.
+The counter is not increased during handling of a fired DTrace probe.
+Suitable for calculating relative time differences of on-CPU time.
+.It Va walltimestamp
+The number of nanoseconds since the Epoch
+.Pq 1970-01-01T00+00:00 .
+Suitable for timestamping logs.
+.El
+.Sh BUILT-IN FUNCTIONS
+.Ss Aggregation Functions
+.Bl -tag -compact -width "llquantize(value, factor, low, high, nsteps)"
+.It Fn avg value
+Average
+.It Fn count
+Count
+.It Fn llquantize value factor low high nsteps
+Log-linear quantization
+.It Fn lquantize value low high nsteps
+Linear quantization
+.It Fn max value
+Maximum
+.It Fn min value
+Minimum
+.It Fn quantize value
+Power-of-two frequency distribution
+.It Fn stddev value
+Standard deviation
+.It Fn sum value
+Sum
+.El
+.Ss Kernel Destructive Functions
+By default,
+.Xr dtrace 1
+does not permit the use of destructive actions.
+.Bl -tag -width "chill(nanoseconds)"
+.It Fn breakpoint
+Set a kernel breakpoint and transfer control to
+the
+.Xr ddb 4
+kernel debugger.
+.It Fn chill nanoseconds
+Spin on the CPU for the specified number of
+.Fa nanoseconds .
+.It Fn panic
+Panic the kernel.
+.El
+.Sh FILES
+.Bl -tag -width /usr/share/dtrace
+.It Pa /usr/share/dtrace
+DTrace scripts shipped with
+.Fx
+base.
+.El
+.Sh SEE ALSO
+.Xr awk 1 ,
+.Xr dtrace 1 ,
+.Xr tracing 7
+.Rs
+.%B The illumos Dynamic Tracing Guide
+.%D 2008
+.%U https://illumos.org/books/dtrace/
+.Re
+.Rs
+.%A Brendan Gregg
+.%A Jim Mauro
+.%B DTrace: Dynamic Tracing in Oracle Solaris, Mac OS X and FreeBSD
+.%I Prentice Hall
+.%D 2011
+.%U https://www.brendangregg.com/dtracebook/
+.Re
+.Rs
+.%A George Neville-Neil
+.%A Jonathan Anderson
+.%A Graeme Jenkinson
+.%A Brian Kidney
+.%A Domagoj Stolfa
+.%A Arun Thomas
+.%A Robert N. M. Watson
+.%C Cambridge, United Kingdom
+.%D August 2018
+.%T Univeristy of Cambridge Computer Laboratory
+.%R OpenDTrace Specification version 1.0
+.%U https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-924.pdf
+.Re
+.Sh HISTORY
+This manual page first appeared in
+.Fx 15.0 .
+.Sh AUTHORS
+.An -nosplit
+This manual page was written by
+.An Mateusz Piotrowski Aq Mt 0mp@FreeBSD.org .
+.Sh BUGS
+The
+.Va cwd
+variable which typically provides the current working directory is
+not supported on
+.Fx
+at the moment.
diff --git a/share/man/man7/intro.7 b/share/man/man7/intro.7
index d889c2dd299f..43e48de87bc5 100644
--- a/share/man/man7/intro.7
+++ b/share/man/man7/intro.7
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 23, 2025
+.Dd July 14, 2025
.Dt INTRO 7
.Os
.Sh NAME
@@ -49,6 +49,9 @@ system timekeeping clocks available in
.It Xr crypto 7
cryptographic algorithms provided by OpenCrypto in
.Fx
+.It Xr d 7
+.Xr dtrace 1
+scripting language overview
.It Xr development 7
development introduction to
.Fx
diff --git a/share/man/man7/named_attribute.7 b/share/man/man7/named_attribute.7
new file mode 100644
index 000000000000..7cd778620357
--- /dev/null
+++ b/share/man/man7/named_attribute.7
@@ -0,0 +1,275 @@
+.\"
+.\" Copyright (c) 2025 Rick Macklem
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd July 3, 2025
+.Dt NAMED_ATTRIBUTE 7
+.Os
+.Sh NAME
+.Nm named_attribute
+.Nd Solaris-like extended attribute system interface
+.Sh DESCRIPTION
+Description of the system interface for named attributes
+(the NFS Version 4 terminology).
+.Ss Introduction
+This document describes an alternate system interface for extended
+attributes as compared to
+.Xr extattr 2 .
+It is based on the interface provided by Solaris and NFS Version 4.
+.Pp
+This interface associates a directory, known as a named attribute directory,
+to a file system object.
+This directory is read in the same manner as a normal directory via the
+.Xr getdents 2
+or
+.Xr getdirentries 2
+system calls.
+The
+.Pa .\&
+and
+.Pa ..\&
+entries refer to the directory itself and to the associated file object,
+respectively.
+The other entries in this directory
+are the names of the extended attributes for the associated file object
+and are referred to as named attributes.
+These named attributes are regular files used to store the attribute's
+value.
+.Pp
+A named attribute directory does not live in the file system's name space.
+It is accessed via an
+.Xr open 2
+or
+.Xr openat 2
+system call done on a file to query the named attributes for the file,
+with the
+.Dv O_NAMEDATTR
+flag specified and a
+.Fa path
+argument of
+.Pa .\& .
+This file descriptor can be used as the
+.Fa fd
+argument for a variety of system calls, such as:
+.Xr fchdir 2 ,
+.Xr unlinkat 2
+and
+.Xr renameat 2 .
+.Xr renameat 2
+is only permitted to rename a named attribute within the same named
+attribute directory.
+.Pp
+When a file descriptor for a file object in the file system's namespace
+is used as the
+.Fa fd
+argument of an
+.Xr openat 2
+along with the
+.Fa flag
+.Dv O_NAMEDATTR
+and a
+.Fa path
+argument that is the name of a named attribute (not
+.Pa .\&
+or
+.Pa ..\&
+), a file descriptor for the named attribute is returned.
+If the
+.Fa flag
+.Dv O_CREAT
+is specified, the named attribute will be created if it does not exist.
+The
+.Fa path
+argument must be a single component name, with no embedded
+.Dq /
+in it.
+I/O on these named attribute file descriptors may be performed by
+standard I/O system calls
+such as:
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr lseek 2
+and
+.Xr ftruncate 2 .
+.Pp
+The
+.Dv _PC_NAMEDATTR_ENABLED
+.Fa name
+argument to
+.Xr pathconf 2
+will return 1 if the file system supports named attributes.
+The
+.Dv _PC_HAS_NAMEDATTR
+.Fa name
+argument to
+.Xr pathconf 2
+will return 1 if there are one or more named attributes for the file.
+If an application does a
+.Xr openat 2
+of
+.Dq .\&
+to open a named attribute directory when no named attribute directory exists,
+an empty named attribute directory will be created.
+Testing
+.Dv _PC_HAS_NAMEDATTR
+can be done to avoid creating these named attribute directories unnecessarily.
+.Pp
+The named attribute interface is a different mechanism/system call interface for
+manipulating extended attributes compared with
+.Xr extattr 2 .
+Although the named attribute machanism might require different internal
+implementation
+of extended attributes within a file system, both ZFS and NFSv4 provide
+both mechanisms, which can be used interchangeably to manipulate
+extended attributes, but with a couple of limitations.
+.Bl -bullet
+.It
+The
+.Xr extattr 2
+interface requires that an extended attribute's value be set or acquired
+via a single system call using a single buffer.
+This limits the size of the attribute's value.
+.It
+The named attribute interface does not support system namespace
+extended attributes and,
+as such, system namespace extended attributes must be manipulated via
+.Xr extattr 2 .
+.El
+.Pp
+The named attribute mechanism/system call interface provides certain
+advantages over
+.Xr extattr 2 .
+Since the attribute's value is updated via
+.Xr read 2
+and
+.Xr write 2
+system calls, the attribute's data may be as large as any regular file
+and may be partially updated.
+(Note that this interface does not provide the atomicity guarantee that
+.Xr extattr 2
+does.)
+The permission to access a named attribute directory is determined from
+the access control information for the associated file object.
+However, access control information can be set on each individual attribute
+in a manner similar to a regular file.
+This provides
+.Dq per attribute
+granular control over attribute permissions via
+.Xr fchown 2 .
+.Pp
+At this time, the only local file system which supports this interface
+is ZFS and only if the
+.Dv xattr
+property is set to
+.Dq dir .
+(Note that, even when
+.Dq zfs get xattr <file-system>
+shows
+.Dq on
+the command
+.Dq zfs set xattr=dir <file-system>
+must be done, followed by a remount to make the setting take effect.)
+A NFSv4 mount will also support this interface, but only if the NFSv4
+server file system supports named attributes (the openattr operation).
+The
+.Fx
+NFSv4 server supports named attributes only
+for ZFS exported file systems where the
+.Dq xattr
+property is set to
+.Dq dir
+for the file system.
+.Sh EXAMPLES
+.Bd -literal
+#include <stdio.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+\&...
+
+/* For a file called "myfile". Failure checks removed for brevity. */
+int file_fd, nameddir_fd, namedattr_fd;
+ssize_t siz;
+char buf[DIRBLKSIZ], *cp;
+struct dirent *dp;
+long named_enabled, has_named_attrs;
+
+\&...
+/* Check to see if named attributes are supported. */
+named_enabled = pathconf("myfile", _PC_NAMEDATTR_ENABLED);
+if (named_enabled <= 0)
+ err(1, "Named attributes not enabled");
+/* Test to see if named attribute(s) exist for the file. */
+has_named_attrs = pathconf("myfile", _PC_HAS_NAMEDATTR);
+if (has_named_attrs == 1)
+ printf("myfile has named attribute(s)\\n");
+else
+ printf("myfile does not have any named attributes\\n");
+/* Open a named attribute directory. */
+file_fd = open("myfile", O_RDONLY, 0);
+nameddir_fd = openat(file_fd, ".", O_NAMEDATTR, 0);
+\&...
+/* and read it, assuming it all fits in DIRBLKSIZ for simplicity. */
+siz = getdents(fd, buf, sizeof(buf));
+cp = buf;
+while (cp < &buf[siz]) {
+ dp = (struct dirent *)cp;
+ printf("name=%s\\n", dp->d_name);
+ cp += dp->d_reclen;
+}
+\&...
+/* Open/create a named attribute called "foo". */
+namedattr_fd = openat(file_fd, "foo", O_CREAT | O_RDWR |
+ O_TRUNC | O_NAMEDATTR, 0600);
+\&...
+/* Write foo's attribute value. */
+write(namedattr_fd, "xxxyyy", 6);
+\&...
+/* Read foo's attribute value. */
+lseek(namedattr_fd, 0, SEEK_SET);
+siz = read(namedattr_fd, buf, sizeof(buf));
+\&...
+/* And close "foo". */
+close(namedattr_fd);
+\&...
+/* Rename "foo" to "oldfoo". */
+renameat(nameddir_fd, "foo", nameddir_fd, "oldfoo");
+/* and delete "oldfoo". */
+unlinkat(nameddir_fd, "oldfoo", AT_RESOLVE_BENEATH);
+.Ed
+.Pp
+The
+.Xr runat 1
+command may be used to perform shell commands on named attributes.
+For example:
+.Bd -literal
+$ runat myfile cp /etc/hosts attrhosts # creates attrhosts
+$ runat myfile cat attrhosts # displays contents of attrhosts
+$ runat myfile ls -l # lists the attributes for myfile
+.Ed
+.Pp
+If using the
+.Xr bash 1
+shell, the command
+.Dq cd -@ foo
+enters the named attribute directory for the file object
+.Dq foo .
+.Sh SEE ALSO
+.Xr bash 1 ,
+.Xr runat 1 ,
+.Xr chdir 2 ,
+.Xr extattr 2 ,
+.Xr lseek 2 ,
+.Xr open 2 ,
+.Xr pathconf 2 ,
+.Xr read 2 ,
+.Xr rename 2 ,
+.Xr truncate 2 ,
+.Xr unlinkat 2 ,
+.Xr write 2 ,
+.Xr zfsprops 7
+.Sh HISTORY
+This interface first appeared in
+.Fx 15.0 .
diff --git a/share/man/man7/tracing.7 b/share/man/man7/tracing.7
index 0bd64f197084..7085bac78385 100644
--- a/share/man/man7/tracing.7
+++ b/share/man/man7/tracing.7
@@ -3,12 +3,12 @@
.\"
.\" Copyright (c) 2025 Mateusz Piotrowski <0mp@FreeBSD.org>
.\"
-.Dd June 19, 2025
+.Dd July 12, 2025
.Dt TRACING 7
.Os
.Sh NAME
.Nm tracing
-.Nd introduction to tracing and performance monitoring facilities
+.Nd introduction to FreeBSD tracing and performance monitoring
.Sh DESCRIPTION
.Fx
features a large variety of tracing and performance monitoring facilities.
@@ -34,7 +34,6 @@ for more details.
is a user-friendly wrapper for DTrace.
It simplifies common DTrace usage patterns and requires less expert knowledge
to operate.
-.Pp
.Ss Userland Tracing
.Xr truss 1
traces system calls.
@@ -55,7 +54,8 @@ it asynchronously logs entries to a trace file configured with
.Xr ktrace 2
(typically
.Pa ktrace.out ) ,
-and it can log other types of kernel events, such as page faults and name lookups
+and it can log other types of kernel events, such as page faults
+and name lookups
.Po refer to
.Fl t
in
@@ -73,11 +73,14 @@ It comes in handy for some niche purposes during kernel development.
It lets kernel programmers log events to a global ring buffer,
which can later be dumped using
.Xr ktrdump 8 .
+.Ss Hardware-Accelerated Tracing
+.Xr hwt 4
+is a kernel trace framework providing infrastructure
+for hardware-assisted tracing.
.Ss Hardware Counters
-.Pp
.Xr pmcstat 8 ,
and its kernel counterpart,
-.Xr hwmpc 4 ,
+.Xr hwpmc 4 ,
is the
.Fx
facility for conducting performance measurements with hardware counters.
diff --git a/share/man/man8/nanobsd.8 b/share/man/man8/nanobsd.8
index 2ba072541ada..838f9ddc9afa 100644
--- a/share/man/man8/nanobsd.8
+++ b/share/man/man8/nanobsd.8
@@ -1,3 +1,6 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
.\" Copyright (c) 2006 Daniel Gerzo <danger@FreeBSD.org>
.\" All rights reserved.
.\"
@@ -22,13 +25,12 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 10, 2024
+.Dd July 14, 2025
.Dt NANOBSD 8
.Os
.Sh NAME
.Nm nanobsd.sh
-.Nd utility used to create a FreeBSD system image suitable for embedded
-applications
+.Nd create an embedded FreeBSD system image
.Sh SYNOPSIS
.Nm
.Op Fl BbfhIiKknqvWwX
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index badaee1479f7..f709a4818dd5 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -434,6 +434,7 @@ MAN= accept_filter.9 \
VOP_GETEXTATTR.9 \
VOP_GETPAGES.9 \
VOP_INACTIVE.9 \
+ VOP_INOTIFY.9 \
VOP_IOCTL.9 \
VOP_LINK.9 \
VOP_LISTEXTATTR.9 \
@@ -2460,6 +2461,7 @@ MLINKS+=VOP_CREATE.9 VOP_MKDIR.9 \
MLINKS+=VOP_FSYNC.9 VOP_FDATASYNC.9
MLINKS+=VOP_GETPAGES.9 VOP_PUTPAGES.9
MLINKS+=VOP_INACTIVE.9 VOP_RECLAIM.9
+MLINKS+=VOP_INOTIFY.9 VOP_INOTIFY_ADD_WATCH.9
MLINKS+=VOP_LOCK.9 vn_lock.9 \
VOP_LOCK.9 VOP_ISLOCKED.9 \
VOP_LOCK.9 VOP_UNLOCK.9
diff --git a/share/man/man9/VOP_INOTIFY.9 b/share/man/man9/VOP_INOTIFY.9
new file mode 100644
index 000000000000..43b644682153
--- /dev/null
+++ b/share/man/man9/VOP_INOTIFY.9
@@ -0,0 +1,60 @@
+.\"-
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Klara, Inc.
+.\"
+.Dd May 27, 2025
+.Dt VOP_INOTIFY 9
+.Os
+.Sh NAME
+.Nm VOP_INOTIFY
+.Nd vnode inotify interface
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/vnode.h
+.Ft int
+.Fo VOP_INOTIFY
+.Fa struct vnode *vp
+.Fa struct vnode *dvp
+.Fa struct componentname *cnp
+.Fa int event
+.Fa uint32_t cookie
+.Fc
+.Ft int
+.Fo VOP_INOTIFY_ADD_WATCH
+.Fa struct vnode *vp
+.Fa struct inotify_softc *sc
+.Fa uint32_t mask
+.Fa uint32_t *wdp
+.Fa struct thread *td
+.Fc
+.Sh DESCRIPTION
+The
+.Fn VOP_INOTIFY
+operation notifies the
+.Xr inotify 2
+subsystem of a file system event on a vnode.
+The
+.Fa dvp
+and
+.Fa cnp
+arguments are optional and are only used to obtain a file name for the event.
+If they are omitted, the inotify subsystem will use the file name cache to
+find a name for the vnode, but this is more expensive.
+.Pp
+The
+.Fn VOP_INOTIFY_ADD_WATCH
+operation is for internal use by the inotify subsystem to add a watch to a
+vnode.
+.Sh LOCKS
+The
+.Fn VOP_INOTIFY
+operation does not assume any particular vnode lock state.
+The
+.Fn VOP_INOTIFY_ADD_WATCH
+operation should be called with the vnode locked.
+.Sh RETURN VALUES
+Zero is returned on success, otherwise an error code is returned.
+.Sh SEE ALSO
+.Xr inotify 2 ,
+.Xr vnode 9
diff --git a/share/man/man9/vnode.9 b/share/man/man9/vnode.9
index 5dd087725e92..d17492668298 100644
--- a/share/man/man9/vnode.9
+++ b/share/man/man9/vnode.9
@@ -24,7 +24,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd October 9, 2024
+.Dd July 15, 2025
.Dt VNODE 9
.Os
.Sh NAME
@@ -113,7 +113,7 @@ The
function declarations and definitions are generated from
.Pa sys/kern/vnode_if.src
by the
-.Pa sys/tools/vndoe_if.awk
+.Pa sys/tools/vnode_if.awk
script.
The interfaces are documented in their respective manual pages like
.Xr VOP_READ 9
diff --git a/share/misc/committers-src.dot b/share/misc/committers-src.dot
index 313f40ad8e51..0f9f8242c5c2 100644
--- a/share/misc/committers-src.dot
+++ b/share/misc/committers-src.dot
@@ -299,6 +299,7 @@ nork [label="Norikatsu Shigemura\nnork@FreeBSD.org\n2009/06/09"]
np [label="Navdeep Parhar\nnp@FreeBSD.org\n2009/06/05"]
nwhitehorn [label="Nathan Whitehorn\nnwhitehorn@FreeBSD.org\n2008/07/03"]
n_hibma [label="Nick Hibma\nn_hibma@FreeBSD.org\n1998/11/26"]
+obiwac [label="Aymeric Wibo\nobiwac@FreeBSD.org\n2025/07/15"]
obrien [label="David E. O'Brien\nobrien@FreeBSD.org\n1996/10/29"]
oh [label="Oskar Holmlund\noh@FreeBSD.org\n2021/04/21"]
olce [label="Olivier Certner\nolce@FreeBSD.org\n2023/12/01"]
@@ -711,6 +712,8 @@ joerg -> schweikh
jtl -> ngie
jtl -> thj
+jrm -> obiwac
+
julian -> glebius
julian -> davidxu
julian -> archie
@@ -799,6 +802,8 @@ mav -> eugen
mav -> freqlabs
mav -> ram
+mckusick -> obiwac
+
mdf -> gleb
mdodd -> jake
diff --git a/share/mk/bsd.subdir.mk b/share/mk/bsd.subdir.mk
index cf19c9d66201..289e3d591c8c 100644
--- a/share/mk/bsd.subdir.mk
+++ b/share/mk/bsd.subdir.mk
@@ -76,13 +76,14 @@ obj: .PHONY
.endif
.if !defined(NEED_SUBDIR)
+.if ${MK_DIRDEPS_BUILD} == "yes"
+# ignore this
+_SUBDIR:
# .MAKE.DEPENDFILE==/dev/null is set by bsd.dep.mk to avoid reading
# Makefile.depend
-.if ${.MAKE.LEVEL} == 0 && ${MK_DIRDEPS_BUILD} == "yes" && !empty(SUBDIR) && \
- ${.MAKE.DEPENDFILE} != "/dev/null"
+.if ${.MAKE.LEVEL} == 0 && !empty(SUBDIR) && ${.MAKE.DEPENDFILE} != "/dev/null"
.include <meta.subdir.mk>
-# ignore this
-_SUBDIR:
+.endif
.endif
.endif
diff --git a/share/mk/local.sys.machine.mk b/share/mk/local.sys.machine.mk
index 5e40dfe805f9..961362cb048a 100644
--- a/share/mk/local.sys.machine.mk
+++ b/share/mk/local.sys.machine.mk
@@ -7,9 +7,9 @@ TARGET_MACHINE_LIST?= amd64 arm arm64 i386 powerpc riscv
MACHINE_ARCH_host?= ${_HOST_ARCH}
MACHINE_ARCH_host32?= ${_HOST_ARCH32}
-MACHINE_ARCH_LIST_arm?= armv7 ${EXTRA_ARCHES_arm}
+MACHINE_ARCH_LIST_arm?= armv7
MACHINE_ARCH_LIST_arm64?= aarch64
-MACHINE_ARCH_LIST_powerpc?= powerpc powerpc64 powerpc64le ${EXTRA_ARCHES_powerpc}
+MACHINE_ARCH_LIST_powerpc?= powerpc64 powerpc64le ${EXTRA_ARCHES_powerpc}
MACHINE_ARCH_LIST_riscv?= riscv64
.for m in ${TARGET_MACHINE_LIST}
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index 387e570f8518..ef43d3c939b2 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -143,6 +143,7 @@ __DEFAULT_YES_OPTIONS = \
MAIL \
MAILWRAPPER \
MAKE \
+ MITKRB5 \
MLX5TOOL \
NETCAT \
NETGRAPH \
@@ -211,7 +212,6 @@ __DEFAULT_NO_OPTIONS = \
LOADER_VERIEXEC_PASS_MANIFEST \
LLVM_FULL_DEBUGINFO \
MALLOC_PRODUCTION \
- MITKRB5 \
OFED_EXTRA \
OPENLDAP \
REPRODUCIBLE_BUILD \
diff --git a/share/termcap/termcap b/share/termcap/termcap
index 9704d85c942f..46b89d0b3ddf 100644
--- a/share/termcap/termcap
+++ b/share/termcap/termcap
@@ -3549,8 +3549,7 @@ ti931|ti 931:\
# using \EPC\\ and \EPD\\, but I don't think there is a
# capability for that.
ti703|ti707|Texas Instruments Silent 703/707, 80 cols:\
- :am:hc:os:xn:\
- :co#80:it#8:\
+ :am:hc:os:xn:co#80:\
:do=\n:le=\b:cr=\r:nd= :bl=^G:ta=\t:is=\EPC\\:
ti703-w|ti707-w|Texas Instruments Silent 703/707, 132 cols:\
:co#132:is=\EPD\\:tc=ti703:
@@ -4808,6 +4807,26 @@ alacritty+common|base fragment for alacritty:\
:te=\E[?1049l\E[23;0;0t:ti=\E[?1049h\E[22;0;0t:\
:ts=\E]2;:ue=\E[24m:up=\E[A:us=\E[4m:vb=\E[?5h\E[?5l:\
:ve=\E[?12l\E[?25h:vi=\E[?25l:vs=\E[?12;25h:
+
+# From Tim Culverhouse <tim@timculverhouse.com>
+xterm-ghostty|ghostty|Ghostty:\
+ :am:hs:km:mi:ms:xn:\
+ :co#80:it#8:li#24:\
+ :AL=\E[%dL:DC=\E[%dP:DL=\E[%dM:DO=\E[%dB:IC=\E[%d@:\
+ :LE=\E[%dD:RI=\E[%dC:SF=\E[%dS:SR=\E[%dT:UP=\E[%dA:\
+ :ae=\E(B:al=\E[L:as=\E(0:bl=^G:bt=\E[Z:cd=\E[J:ce=\E[K:\
+ :cl=\E[H\E[2J:cm=\E[%i%d;%dH:cr=\r:cs=\E[%i%d;%dr:\
+ :ct=\E[3g:dc=\E[P:dl=\E[M:do=\n:ds=\E]2;\007:ec=\E[%dX:\
+ :ei=\E[4l:fs=^G:ho=\E[H:ic=\E[@:im=\E[4h:k1=\EOP:k2=\EOQ:\
+ :k3=\EOR:k4=\EOS:k5=\E[15~:k6=\E[17~:k7=\E[18~:k8=\E[19~:\
+ :k9=\E[20~:kD=\E[3~:kI=\E[2~:kN=\E[6~:kP=\E[5~:kb=\177:\
+ :kd=\EOB:ke=\E[?1l\E>:kh=\EOH:kl=\EOD:kr=\EOC:\
+ :ks=\E[?1h\E=:ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:me=\E[0m:\
+ :mh=\E[2m:mr=\E[7m:nd=\E[C:rc=\E8:sc=\E7:se=\E[27m:sf=\n:\
+ :so=\E[7m:sr=\EM:st=\EH:ta=^I:te=\E[?1049l:ti=\E[?1049h:\
+ :ts=\E]2;:ue=\E[24m:up=\E[A:us=\E[4m:vb=\E[?5h\E[?5l:\
+ :ve=\E[?12l\E[?25h:vi=\E[?25l:vs=\E[?12;25h:
+
#
# END OF TERMCAP
# ------------------------
diff --git a/stand/common/bootstrap.h b/stand/common/bootstrap.h
index dca0cf6bb2d5..17887919089c 100644
--- a/stand/common/bootstrap.h
+++ b/stand/common/bootstrap.h
@@ -372,6 +372,8 @@ extern struct arch_switch archsw;
/* This must be provided by the MD code, but should it be in the archsw? */
void delay(int delay);
+int setprint_delay(struct env_var *ev, int flags, const void *value);
+
/* common code to set currdev variable. */
int gen_setcurrdev(struct env_var *ev, int flags, const void *value);
int mount_currdev(struct env_var *, int, const void *);
diff --git a/stand/common/console.c b/stand/common/console.c
index 82cb552b4ef2..65ab7ffad622 100644
--- a/stand/common/console.c
+++ b/stand/common/console.c
@@ -44,6 +44,8 @@ static int twiddle_set(struct env_var *ev, int flags, const void *value);
#endif
int module_verbose = MODULE_VERBOSE;
+static uint32_t print_delay_usec = 0;
+
static int
module_verbose_set(struct env_var *ev, int flags, const void *value)
{
@@ -66,6 +68,23 @@ module_verbose_set(struct env_var *ev, int flags, const void *value)
}
/*
+ * Hook to set the print delay
+ */
+int
+setprint_delay(struct env_var *ev, int flags, const void *value)
+{
+ char *end;
+ int usec = strtol(value, &end, 10);
+
+ if (*(char *)value == '\0' || *end != '\0')
+ return (EINVAL);
+ if (usec < 0)
+ return (EINVAL);
+ print_delay_usec = usec;
+ return (0);
+}
+
+/*
* Detect possible console(s) to use. If preferred console(s) have been
* specified, mark them as active. Else, mark the first probed console
* as active. Also create the console variable.
@@ -178,6 +197,10 @@ putchar(int c)
(C_PRESENTOUT | C_ACTIVEOUT))
consoles[cons]->c_out(c);
}
+
+ /* Pause after printing newline character if a print delay is set */
+ if (print_delay_usec != 0 && c == '\n')
+ delay(print_delay_usec);
}
/*
diff --git a/stand/common/dev_net.c b/stand/common/dev_net.c
index fc6b43ec7a40..964fa514cac5 100644
--- a/stand/common/dev_net.c
+++ b/stand/common/dev_net.c
@@ -66,10 +66,6 @@
#include "dev_net.h"
#include "bootstrap.h"
-#ifdef NETIF_DEBUG
-int debug = 0;
-#endif
-
static char *netdev_name;
static int netdev_sock = -1;
static int netdev_opens;
@@ -143,11 +139,8 @@ net_open(struct open_file *f, ...)
return (ENXIO);
}
netdev_name = strdup(devname);
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: netif_open() succeeded\n",
- __func__);
-#endif
+ DEBUG_PRINTF(1,("%s: netif_open() succeeded %#x\n",
+ __func__, rootip.s_addr));
}
/*
* If network params were not set by netif_open(), try to get
@@ -200,10 +193,7 @@ net_close(struct open_file *f)
{
struct devdesc *dev;
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: opens=%d\n", __func__, netdev_opens);
-#endif
+ DEBUG_PRINTF(1,("%s: opens=%d\n", __func__, netdev_opens));
dev = f->f_devdata;
dev->d_opendata = NULL;
@@ -216,10 +206,7 @@ net_cleanup(void)
{
if (netdev_sock >= 0) {
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: calling netif_close()\n", __func__);
-#endif
+ DEBUG_PRINTF(1,("%s: calling netif_close()\n", __func__));
rootip.s_addr = 0;
free(netdev_name);
netif_close(netdev_sock);
@@ -271,10 +258,7 @@ net_getparams(int sock)
bootp(sock);
if (myip.s_addr != 0)
goto exit;
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: BOOTP failed, trying RARP/RPC...\n", __func__);
-#endif
+ DEBUG_PRINTF(1,("%s: BOOTP failed, trying RARP/RPC...\n", __func__));
#endif
/*
@@ -292,10 +276,7 @@ net_getparams(int sock)
printf("%s: bootparam/whoami RPC failed\n", __func__);
return (EIO);
}
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: client name: %s\n", __func__, hostname);
-#endif
+ DEBUG_PRINTF(1,("%s: client name: %s\n", __func__, hostname));
/*
* Ignore the gateway from whoami (unreliable).
@@ -309,16 +290,12 @@ net_getparams(int sock)
}
if (smask) {
netmask = smask;
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: subnet mask: %s\n", __func__,
- intoa(netmask));
-#endif
+ DEBUG_PRINTF(1,("%s: subnet mask: %s\n", __func__,
+ intoa(netmask)));
}
-#ifdef NETIF_DEBUG
- if (gateip.s_addr && debug)
- printf("%s: net gateway: %s\n", __func__, inet_ntoa(gateip));
-#endif
+ if (gateip.s_addr)
+ DEBUG_PRINTF(1,("%s: net gateway: %s\n", __func__,
+ inet_ntoa(gateip)));
/* Get the root server and pathname. */
if (bp_getfile(sock, "root", &rootip, rootpath)) {
@@ -329,12 +306,10 @@ exit:
if ((rootaddr = net_parse_rootpath()) != INADDR_NONE)
rootip.s_addr = rootaddr;
-#ifdef NETIF_DEBUG
- if (debug) {
- printf("%s: server addr: %s\n", __func__, inet_ntoa(rootip));
- printf("%s: server path: %s\n", __func__, rootpath);
- }
-#endif
+ DEBUG_PRINTF(1,("%s: proto: %d\n", __func__, netproto));
+ DEBUG_PRINTF(1,("%s: server addr: %s\n", __func__, inet_ntoa(rootip)));
+ DEBUG_PRINTF(1,("%s: server port: %d\n", __func__, rootport));
+ DEBUG_PRINTF(1,("%s: server path: %s\n", __func__, rootpath));
return (0);
}
@@ -410,6 +385,8 @@ net_parse_rootpath(void)
(void)strsep(&ptr, ":");
if (ptr != NULL) {
addr = inet_addr(rootpath);
+ DEBUG_PRINTF(1,("rootpath=%s addr=%#x\n",
+ rootpath, addr));
bcopy(ptr, rootpath, strlen(ptr) + 1);
}
} else {
diff --git a/stand/common/install.c b/stand/common/install.c
index 249eca1648f3..d07c4c6fc620 100644
--- a/stand/common/install.c
+++ b/stand/common/install.c
@@ -137,7 +137,9 @@ read_metatags(int fd)
}
*p++ = '\0';
- if (strcmp(tag, "KERNEL") == 0)
+ if (strncmp(tag, "ENV_", 4) == 0)
+ setenv(&tag[4], val, 1);
+ else if (strcmp(tag, "KERNEL") == 0)
error = setpath(&inst_kernel, val);
else if (strcmp(tag, "MODULES") == 0)
error = setmultipath(&inst_modules, val);
diff --git a/stand/defaults/loader.conf b/stand/defaults/loader.conf
index 1834e3ba3b34..f0843f3e930b 100644
--- a/stand/defaults/loader.conf
+++ b/stand/defaults/loader.conf
@@ -95,6 +95,8 @@ audit_event_type="etc_security_audit_event"
# Default is unset and disabled (no delay).
#autoboot_delay="10" # Delay in seconds before autobooting,
# -1 for no user interrupts, NO to disable
+#print_delay="1000000" # Slow printing of loader messages, useful for
+ # debugging. Given in microseconds.
#password="" # Prevent changes to boot options
#bootlock_password="" # Prevent booting (see check-password.4th(8))
#geom_eli_passphrase_prompt="NO" # Prompt for geli(8) passphrase to mount root
diff --git a/stand/defaults/loader.conf.5 b/stand/defaults/loader.conf.5
index 021f68f2309e..dc1c8f7f44e0 100644
--- a/stand/defaults/loader.conf.5
+++ b/stand/defaults/loader.conf.5
@@ -21,7 +21,7 @@
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
-.Dd June 5, 2025
+.Dd June 12, 2025
.Dt LOADER.CONF 5
.Os
.Sh NAME
@@ -116,6 +116,10 @@ option in this manner,
.Va beastie_disable
must be set to
.Dq Li YES .
+.It Ar print_delay
+Add a delay in microseconds after printing each line.
+Default
+.Dq Li 0 .
.It Ar boot_*
See list in
.Xr loader.efi 8
diff --git a/stand/efi/libefi/efinet.c b/stand/efi/libefi/efinet.c
index 186d816cd323..e872110ef08f 100644
--- a/stand/efi/libefi/efinet.c
+++ b/stand/efi/libefi/efinet.c
@@ -256,6 +256,7 @@ efi_env_net_params(struct iodesc *desc)
rootip.s_addr = rootaddr;
#ifdef EFINET_DEBUG
+ printf("%s: proto=%d\n", __func__, netproto);
printf("%s: ip=%s\n", __func__, inet_ntoa(myip));
printf("%s: mask=%s\n", __func__, intoa(netmask));
printf("%s: gateway=%s\n", __func__, inet_ntoa(gateip));
@@ -427,6 +428,7 @@ efinet_dev_init(void)
dif->dif_private = handles2[i];
}
+ efinet_dev.dv_cleanup = netdev.dv_cleanup;
efinet_dev.dv_open = netdev.dv_open;
efinet_dev.dv_close = netdev.dv_close;
efinet_dev.dv_strategy = netdev.dv_strategy;
diff --git a/stand/efi/loader/arch/amd64/elf64_freebsd.c b/stand/efi/loader/arch/amd64/elf64_freebsd.c
index c4265aca035e..35bd4d6c1419 100644
--- a/stand/efi/loader/arch/amd64/elf64_freebsd.c
+++ b/stand/efi/loader/arch/amd64/elf64_freebsd.c
@@ -209,6 +209,12 @@ elf64_exec(struct preloaded_file *fp)
trampoline, PT4);
printf("Start @ 0x%lx ...\n", ehdr->e_entry);
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
efi_time_fini();
err = bi_load(fp->f_args, &modulep, &kernend, true);
if (err != 0) {
@@ -218,8 +224,6 @@ elf64_exec(struct preloaded_file *fp)
return (err);
}
- dev_cleanup();
-
trampoline(trampstack, copy_staging == COPY_STAGING_ENABLE ?
efi_copy_finish : efi_copy_finish_nop, kernend, modulep,
PT4, ehdr->e_entry);
diff --git a/stand/efi/loader/arch/arm/exec.c b/stand/efi/loader/arch/arm/exec.c
index c2a79523c02a..3963b6c0104b 100644
--- a/stand/efi/loader/arch/arm/exec.c
+++ b/stand/efi/loader/arch/arm/exec.c
@@ -74,16 +74,17 @@ __elfN(arm_exec)(struct preloaded_file *fp)
printf("Kernel entry at %p...\n", entry);
printf("Kernel args: %s\n", fp->f_args);
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
if ((error = bi_load(fp->f_args, &modulep, &kernend, true)) != 0) {
efi_time_init();
return (error);
}
- /* At this point we've called ExitBootServices, so we can't call
- * printf or any other function that uses Boot Services */
-
- dev_cleanup();
-
(*entry)((void *)modulep);
panic("exec returned");
}
diff --git a/stand/efi/loader/arch/arm64/exec.c b/stand/efi/loader/arch/arm64/exec.c
index 91a0503a976f..89e2ad7521a8 100644
--- a/stand/efi/loader/arch/arm64/exec.c
+++ b/stand/efi/loader/arch/arm64/exec.c
@@ -69,6 +69,12 @@ elf64_exec(struct preloaded_file *fp)
ehdr = (Elf_Ehdr *)&(md->md_data);
entry = efi_translate(ehdr->e_entry);
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
efi_time_fini();
err = bi_load(fp->f_args, &modulep, &kernendp, true);
if (err != 0) {
@@ -76,8 +82,6 @@ elf64_exec(struct preloaded_file *fp)
return (err);
}
- dev_cleanup();
-
/* Clean D-cache under kernel area and invalidate whole I-cache */
clean_addr = (vm_offset_t)efi_translate(fp->f_addr);
clean_size = (vm_offset_t)efi_translate(kernendp) - clean_addr;
diff --git a/stand/efi/loader/arch/i386/elf64_freebsd.c b/stand/efi/loader/arch/i386/elf64_freebsd.c
index b02cda2269bc..22cdd685ea9b 100644
--- a/stand/efi/loader/arch/i386/elf64_freebsd.c
+++ b/stand/efi/loader/arch/i386/elf64_freebsd.c
@@ -252,6 +252,13 @@ elf64_exec(struct preloaded_file *fp)
ehdr->e_entry
);
+
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
efi_time_fini();
err = bi_load(fp->f_args, &modulep, &kernend, true);
if (err != 0) {
@@ -259,8 +266,6 @@ elf64_exec(struct preloaded_file *fp)
return (err);
}
- dev_cleanup();
-
trampoline(trampstack, type == AllocateMaxAddress ? efi_copy_finish :
efi_copy_finish_nop, kernend, modulep, PT4, gdtr, ehdr->e_entry);
diff --git a/stand/efi/loader/arch/riscv/exec.c b/stand/efi/loader/arch/riscv/exec.c
index 9da61229ef68..a53fbd9442b0 100644
--- a/stand/efi/loader/arch/riscv/exec.c
+++ b/stand/efi/loader/arch/riscv/exec.c
@@ -86,17 +86,17 @@ __elfN(exec)(struct preloaded_file *fp)
printf("Kernel entry at %p...\n", entry);
printf("Kernel args: %s\n", fp->f_args);
+ /*
+ * we have to cleanup here because net_cleanup() doesn't work after
+ * we call ExitBootServices
+ */
+ dev_cleanup();
+
if ((error = bi_load(fp->f_args, &modulep, &kernend, true)) != 0) {
efi_time_init();
return (error);
}
- /*
- * At this point we've called ExitBootServices, so we can't call
- * printf or any other function that uses Boot Services
- */
- dev_cleanup();
-
(*entry)((void *)modulep);
panic("exec returned");
}
diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c
index 3ef418d20df3..436676368447 100644
--- a/stand/efi/loader/main.c
+++ b/stand/efi/loader/main.c
@@ -1241,6 +1241,9 @@ main(int argc, CHAR16 *argv[])
#endif
cons_probe();
+ /* Set print_delay variable to have hooks in place. */
+ env_setenv("print_delay", EV_VOLATILE, "", setprint_delay, env_nounset);
+
/* Set up currdev variable to have hooks in place. */
env_setenv("currdev", EV_VOLATILE, "", gen_setcurrdev, env_nounset);
diff --git a/stand/libsa/bootp.c b/stand/libsa/bootp.c
index d919bb59e843..ac37553c6d34 100644
--- a/stand/libsa/bootp.c
+++ b/stand/libsa/bootp.c
@@ -42,7 +42,6 @@
#include <string.h>
-#define BOOTP_DEBUGxx
#define SUPPORT_DHCP
#define DHCP_ENV_NOVENDOR 1 /* do not parse vendor options */
@@ -130,10 +129,7 @@ bootp(int sock)
} wbuf;
struct bootp *rbootp;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootp: socket=%d\n", sock);
-#endif
+ DEBUG_PRINTF(1, ("bootp: socket=%d\n", sock));
if (!bot)
bot = getsecs();
@@ -141,10 +137,7 @@ bootp(int sock)
printf("bootp: bad socket. %d\n", sock);
return;
}
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootp: d=%lx\n", (long)d);
-#endif
+ DEBUG_PRINTF(1, ("bootp: socktodesc=%lx\n", (long)d));
bp = &wbuf.wbootp;
bzero(bp, sizeof(*bp));
@@ -225,31 +218,20 @@ bootp(int sock)
netmask = htonl(IN_CLASSB_NET);
else
netmask = htonl(IN_CLASSC_NET);
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("'native netmask' is %s\n", intoa(netmask));
-#endif
+ DEBUG_PRINTF(1, ("'native netmask' is %s\n", intoa(netmask)));
}
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("mask: %s\n", intoa(netmask));
-#endif
+ DEBUG_PRINTF(1,("rootip: %s\n", inet_ntoa(rootip)));
+ DEBUG_PRINTF(1,("mask: %s\n", intoa(netmask)));
/* We need a gateway if root is on a different net */
if (!SAMENET(myip, rootip, netmask)) {
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("need gateway for root ip\n");
-#endif
+ DEBUG_PRINTF(1,("need gateway for root ip\n"));
}
/* Toss gateway if on a different net */
if (!SAMENET(myip, gateip, netmask)) {
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("gateway ip (%s) bad\n", inet_ntoa(gateip));
-#endif
+ DEBUG_PRINTF(1,("gateway ip (%s) bad\n", inet_ntoa(gateip)));
gateip.s_addr = 0;
}
@@ -264,18 +246,11 @@ bootpsend(struct iodesc *d, void *pkt, size_t len)
{
struct bootp *bp;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootpsend: d=%lx called.\n", (long)d);
-#endif
-
+ DEBUG_PRINTF(1,("bootpsend: d=%lx called.\n", (long)d));
bp = pkt;
bp->bp_secs = htons((u_short)(getsecs() - bot));
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootpsend: calling sendudp\n");
-#endif
+ DEBUG_PRINTF(1,("bootpsend: calling sendudp\n"));
return (sendudp(d, pkt, len));
}
@@ -288,34 +263,22 @@ bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft,
struct bootp *bp;
void *ptr;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootp_recvoffer: called\n");
-#endif
+ DEBUG_PRINTF(1,("bootp_recvoffer: called\n"));
ptr = NULL;
n = readudp(d, &ptr, (void **)&bp, tleft);
if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE)
goto bad;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootprecv: checked. bp = %p, n = %zd\n", bp, n);
-#endif
+ DEBUG_PRINTF(1,("bootprecv: checked. bp = %p, n = %zd\n", bp, n));
+
if (bp->bp_xid != htonl(d->xid)) {
-#ifdef BOOTP_DEBUG
- if (debug) {
- printf("bootprecv: expected xid 0x%lx, got 0x%x\n",
- d->xid, ntohl(bp->bp_xid));
- }
-#endif
+ DEBUG_PRINTF(1,("bootprecv: expected xid 0x%lx, got 0x%x\n",
+ d->xid, ntohl(bp->bp_xid)));
goto bad;
}
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootprecv: got one!\n");
-#endif
+ DEBUG_PRINTF(1,("bootprecv: got one!\n"));
/* Suck out vendor info */
if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) {
@@ -359,10 +322,7 @@ vend_rfc1048(u_char *cp, u_int len)
u_char tag;
const char *val;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("vend_rfc1048 bootp info. len=%d\n", len);
-#endif
+ DEBUG_PRINTF(1,("vend_rfc1048 bootp info. len=%d\n", len));
ep = cp + len;
/* Step over magic cookie */
@@ -443,10 +403,8 @@ vend_cmu(u_char *cp)
{
struct cmu_vend *vp;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("vend_cmu bootp info.\n");
-#endif
+ DEBUG_PRINTF(1,("vend_cmu bootp info.\n"));
+
vp = (struct cmu_vend *)cp;
if (vp->v_smask.s_addr != 0) {
diff --git a/stand/libsa/pkgfs.c b/stand/libsa/pkgfs.c
index 64ebdf033f14..32d488de5cfb 100644
--- a/stand/libsa/pkgfs.c
+++ b/stand/libsa/pkgfs.c
@@ -31,12 +31,6 @@
#include <string.h>
#include <zlib.h>
-#ifdef PKGFS_DEBUG
-#define DBG(x) printf x
-#else
-#define DBG(x)
-#endif
-
static int pkg_open(const char *, struct open_file *);
static int pkg_close(struct open_file *);
static int pkg_read(struct open_file *, void *, size_t, size_t *);
@@ -172,6 +166,9 @@ pkgfs_init(const char *pkgname, struct fs_ops *proto)
exclusive_file_system = NULL;
+ DEBUG_PRINTF(0, ("%s(%s: '%s') -> %d (error=%d)\n", __func__,
+ proto->fs_name, pkgname, fd, errno));
+
if (fd == -1)
return (errno);
@@ -239,7 +236,7 @@ pkg_open_follow(const char *fn, struct open_file *f, int lnks)
if (strcmp(fn, tf->tf_hdr.ut_name) == 0) {
f->f_fsdata = tf;
tf->tf_fp = 0; /* Reset the file pointer. */
- DBG(("%s: found %s type %c\n", __func__,
+ DEBUG_PRINTF(1, ("%s: found %s type %c\n", __func__,
fn, tf->tf_hdr.ut_typeflag[0]));
if (tf->tf_hdr.ut_typeflag[0] == '2') {
/* we have a symlink
@@ -275,6 +272,7 @@ pkg_close(struct open_file *f)
/*
* Free up the cache if we read all of the file.
*/
+ DEBUG_PRINTF(1, ("%s(%s)\n", __func__, tf->tf_hdr.ut_name));
if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) {
free(tf->tf_cache);
tf->tf_cachesz = 0;
@@ -297,6 +295,8 @@ pkg_read(struct open_file *f, void *buf, size_t size, size_t *res)
return (EBADF);
}
+ DEBUG_PRINTF(4, ("%s(%s,%zd)\n", __func__, tf->tf_hdr.ut_name, size));
+
if (tf->tf_cachesz == 0)
cache_data(tf, 1);
@@ -334,6 +334,8 @@ pkg_read(struct open_file *f, void *buf, size_t size, size_t *res)
tf->tf_fp = fp;
if (res != NULL)
*res = size;
+ DEBUG_PRINTF(4, ("%s(%s) res=%zd\n", __func__, tf->tf_hdr.ut_name,
+ (ssize_t)(tf->tf_size - tf->tf_fp)));
return ((sz == -1) ? errno : 0);
}
@@ -377,7 +379,7 @@ pkg_seek(struct open_file *f, off_t ofs, int whence)
return (tf->tf_fp);
}
}
- DBG(("%s: negative file seek (%jd)\n", __func__,
+ DEBUG_PRINTF(3, ("%s: negative file seek (%jd)\n", __func__,
(intmax_t)delta));
errno = ESPIPE;
return (-1);
@@ -511,26 +513,28 @@ cache_data(struct tarfile *tf, int force)
size_t sz;
if (tf == NULL) {
- DBG(("%s: no file to cache data for?\n", __func__));
+ DEBUG_PRINTF(5, ("%s: no file to cache data for?\n",
+ __func__));
errno = EINVAL;
return (-1);
}
pkg = tf->tf_pkg;
if (pkg == NULL) {
- DBG(("%s: no package associated with file?\n", __func__));
+ DEBUG_PRINTF(5, ("%s: no package associated with file?\n",
+ __func__));
errno = EINVAL;
return (-1);
}
if (tf->tf_cachesz > 0) {
- DBG(("%s: data already cached\n", __func__));
+ DEBUG_PRINTF(5, ("%s: data already cached\n", __func__));
errno = EINVAL;
return (-1);
}
if (tf->tf_ofs != pkg->pkg_ofs) {
- DBG(("%s: caching after force read of file %s?\n",
+ DEBUG_PRINTF(5, ("%s: caching after force read of file %s?\n",
__func__, tf->tf_hdr.ut_name));
errno = EINVAL;
return (-1);
@@ -548,7 +552,8 @@ cache_data(struct tarfile *tf, int force)
tf->tf_cache = malloc(sz);
if (tf->tf_cache == NULL) {
- DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz));
+ DEBUG_PRINTF(5, ("%s: could not allocate %d bytes\n",
+ __func__, (int)sz));
errno = ENOMEM;
return (-1);
}
@@ -732,7 +737,7 @@ new_package(int fd, struct package **pp)
}
/*
- * Done parsing the ZIP header. Spkgt the inflation engine.
+ * Done parsing the ZIP header. Start the inflation engine.
*/
error = inflateInit2(&pkg->pkg_zs, -15);
if (error != Z_OK)
diff --git a/stand/libsa/stand.h b/stand/libsa/stand.h
index e1188fb73a26..8b7d93074ef2 100644
--- a/stand/libsa/stand.h
+++ b/stand/libsa/stand.h
@@ -558,4 +558,17 @@ void tslog_getbuf(void ** buf, size_t * len);
__END_DECLS
+/* define _DEBUG_LEVEL n or _DEBUG_LEVEL_VAR before include */
+#ifndef DEBUG_PRINTF
+# if defined(_DEBUG_LEVEL) || defined(_DEBUG_LEVEL_VAR)
+# ifndef _DEBUG_LEVEL_VAR
+# define _DEBUG_LEVEL_VAR _debug
+static int _debug = _DEBUG_LEVEL;
+# endif
+# define DEBUG_PRINTF(n, args) if (_DEBUG_LEVEL_VAR >= n) printf args
+# else
+# define DEBUG_PRINTF(n, args)
+# endif
+#endif
+
#endif /* STAND_H */
diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c
index 41ef5a46f30e..971d71d098d3 100644
--- a/stand/libsa/zfs/zfsimpl.c
+++ b/stand/libsa/zfs/zfsimpl.c
@@ -1106,7 +1106,8 @@ vdev_insert(vdev_t *top_vdev, vdev_t *vdev)
}
static int
-vdev_from_nvlist(spa_t *spa, uint64_t top_guid, const nvlist_t *nvlist)
+vdev_from_nvlist(spa_t *spa, uint64_t top_guid, uint64_t txg,
+ const nvlist_t *nvlist)
{
vdev_t *top_vdev, *vdev;
nvlist_t **kids = NULL;
@@ -1120,6 +1121,7 @@ vdev_from_nvlist(spa_t *spa, uint64_t top_guid, const nvlist_t *nvlist)
return (rc);
top_vdev->v_spa = spa;
top_vdev->v_top = top_vdev;
+ top_vdev->v_txg = txg;
vdev_insert(spa->spa_root_vdev, top_vdev);
}
@@ -1163,7 +1165,7 @@ done:
static int
vdev_init_from_label(spa_t *spa, const nvlist_t *nvlist)
{
- uint64_t pool_guid, top_guid;
+ uint64_t pool_guid, top_guid, txg;
nvlist_t *vdevs;
int rc;
@@ -1171,13 +1173,15 @@ vdev_init_from_label(spa_t *spa, const nvlist_t *nvlist)
NULL, &pool_guid, NULL) ||
nvlist_find(nvlist, ZPOOL_CONFIG_TOP_GUID, DATA_TYPE_UINT64,
NULL, &top_guid, NULL) ||
+ nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64,
+ NULL, &txg, NULL) != 0 ||
nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST,
NULL, &vdevs, NULL)) {
printf("ZFS: can't find vdev details\n");
return (ENOENT);
}
- rc = vdev_from_nvlist(spa, top_guid, vdevs);
+ rc = vdev_from_nvlist(spa, top_guid, txg, vdevs);
nvlist_destroy(vdevs);
return (rc);
}
@@ -1267,6 +1271,21 @@ vdev_update_from_nvlist(uint64_t top_guid, const nvlist_t *nvlist)
return (rc);
}
+/*
+ * Shall not be called on root vdev, that is not linked into zfs_vdevs.
+ * See comment in vdev_create().
+ */
+static void
+vdev_free(struct vdev *vdev)
+{
+ struct vdev *kid, *safe;
+
+ STAILQ_FOREACH_SAFE(kid, &vdev->v_children, v_childlink, safe)
+ vdev_free(kid);
+ STAILQ_REMOVE(&zfs_vdevs, vdev, vdev, v_alllink);
+ free(vdev);
+}
+
static int
vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist)
{
@@ -1313,9 +1332,10 @@ vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist)
vdev = vdev_find(guid);
/*
* Top level vdev is missing, create it.
+ * XXXGL: how can this happen?
*/
if (vdev == NULL)
- rc = vdev_from_nvlist(spa, guid, kids[i]);
+ rc = vdev_from_nvlist(spa, guid, 0, kids[i]);
else
rc = vdev_update_from_nvlist(guid, kids[i]);
if (rc != 0)
@@ -1379,7 +1399,7 @@ spa_create(uint64_t guid, const char *name)
free(spa);
return (NULL);
}
- spa->spa_root_vdev->v_name = strdup("root");
+ spa->spa_root_vdev->v_name = spa->spa_name;
STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link);
return (spa);
@@ -2006,8 +2026,7 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv,
vdev_t *vdev;
nvlist_t *nvl;
uint64_t val;
- uint64_t guid, vdev_children;
- uint64_t pool_txg, pool_guid;
+ uint64_t guid, pool_guid, top_guid, txg;
const char *pool_name;
int rc, namelen;
@@ -2063,11 +2082,15 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv,
}
if (nvlist_find(nvl, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64,
- NULL, &pool_txg, NULL) != 0 ||
+ NULL, &txg, NULL) != 0 ||
+ nvlist_find(nvl, ZPOOL_CONFIG_TOP_GUID, DATA_TYPE_UINT64,
+ NULL, &top_guid, NULL) != 0 ||
nvlist_find(nvl, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64,
NULL, &pool_guid, NULL) != 0 ||
nvlist_find(nvl, ZPOOL_CONFIG_POOL_NAME, DATA_TYPE_STRING,
- NULL, &pool_name, &namelen) != 0) {
+ NULL, &pool_name, &namelen) != 0 ||
+ nvlist_find(nvl, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64,
+ NULL, &guid, NULL) != 0) {
/*
* Cache and spare devices end up here - just ignore
* them.
@@ -2083,8 +2106,6 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv,
if (spa == NULL) {
char *name;
- nvlist_find(nvl, ZPOOL_CONFIG_VDEV_CHILDREN,
- DATA_TYPE_UINT64, NULL, &vdev_children, NULL);
name = malloc(namelen + 1);
if (name == NULL) {
nvlist_destroy(nvl);
@@ -2098,10 +2119,22 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv,
nvlist_destroy(nvl);
return (ENOMEM);
}
- spa->spa_root_vdev->v_nchildren = vdev_children;
+ } else {
+ struct vdev *kid;
+
+ STAILQ_FOREACH(kid, &spa->spa_root_vdev->v_children,
+ v_childlink)
+ if (kid->v_guid == top_guid && kid->v_txg < txg) {
+ printf("ZFS: pool %s vdev %s ignoring stale "
+ "label from txg 0x%jx, using 0x%jx@0x%jx\n",
+ spa->spa_name, kid->v_name,
+ kid->v_txg, guid, txg);
+ STAILQ_REMOVE(&spa->spa_root_vdev->v_children,
+ kid, vdev, v_childlink);
+ vdev_free(kid);
+ break;
+ }
}
- if (pool_txg > spa->spa_txg)
- spa->spa_txg = pool_txg;
/*
* Get the vdev tree and create our in-core copy of it.
@@ -2109,11 +2142,6 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv,
* be some kind of alias (overlapping slices, dangerously dedicated
* disks etc).
*/
- if (nvlist_find(nvl, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64,
- NULL, &guid, NULL) != 0) {
- nvlist_destroy(nvl);
- return (EIO);
- }
vdev = vdev_find(guid);
/* Has this vdev already been inited? */
if (vdev && vdev->v_phys_read) {
@@ -3541,8 +3569,10 @@ zfs_spa_init(spa_t *spa)
return (EIO);
}
rc = load_nvlist(spa, config_object, &nvlist);
- if (rc != 0)
+ if (rc != 0) {
+ printf("ZFS: failed to load pool %s nvlist\n", spa->spa_name);
return (rc);
+ }
rc = zap_lookup(spa, &dir, DMU_POOL_ZPOOL_CHECKPOINT,
sizeof(uint64_t), sizeof(checkpoint) / sizeof(uint64_t),
diff --git a/sys/amd64/acpica/acpi_wakeup.c b/sys/amd64/acpica/acpi_wakeup.c
index 51d6d5e36840..99565fbb69ca 100644
--- a/sys/amd64/acpica/acpi_wakeup.c
+++ b/sys/amd64/acpica/acpi_wakeup.c
@@ -54,10 +54,8 @@
#include <x86/apicreg.h>
#include <x86/apicvar.h>
-#ifdef SMP
#include <machine/smp.h>
#include <machine/vmparam.h>
-#endif
#include <contrib/dev/acpica/include/acpi.h>
@@ -73,19 +71,13 @@ extern int acpi_resume_beep;
extern int acpi_reset_video;
extern int acpi_susp_bounce;
-#ifdef SMP
extern struct susppcb **susppcbs;
static cpuset_t suspcpus;
-#else
-static struct susppcb **susppcbs;
-#endif
static void acpi_stop_beep(void *);
-#ifdef SMP
static int acpi_wakeup_ap(struct acpi_softc *, int);
static void acpi_wakeup_cpus(struct acpi_softc *);
-#endif
#define ACPI_WAKEPT_PAGES 7
@@ -103,7 +95,6 @@ acpi_stop_beep(void *arg)
timer_spkr_release();
}
-#ifdef SMP
static int
acpi_wakeup_ap(struct acpi_softc *sc, int cpu)
{
@@ -177,7 +168,6 @@ acpi_wakeup_cpus(struct acpi_softc *sc)
outb(CMOS_DATA, mpbiosreason);
}
}
-#endif
int
acpi_sleep_machdep(struct acpi_softc *sc, int state)
@@ -190,10 +180,8 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
if (sc->acpi_wakeaddr == 0ul)
return (-1); /* couldn't alloc wake memory */
-#ifdef SMP
suspcpus = all_cpus;
CPU_CLR(PCPU_GET(cpuid), &suspcpus);
-#endif
if (acpi_resume_beep != 0)
timer_spkr_acquire();
@@ -208,12 +196,10 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
pcb = &susppcbs[0]->sp_pcb;
if (savectx(pcb)) {
fpususpend(susppcbs[0]->sp_fpususpend);
-#ifdef SMP
if (!CPU_EMPTY(&suspcpus) && suspend_cpus(suspcpus) == 0) {
device_printf(sc->acpi_dev, "Failed to suspend APs\n");
return (0); /* couldn't sleep */
}
-#endif
hw_ibrs_ibpb_active = 0;
hw_ssb_active = 0;
cpu_stdext_feature3 = 0;
@@ -278,16 +264,12 @@ acpi_wakeup_machdep(struct acpi_softc *sc, int state, int sleep_result,
PCPU_SET(switchtime, 0);
PCPU_SET(switchticks, ticks);
lapic_xapic_mode();
-#ifdef SMP
if (!CPU_EMPTY(&suspcpus))
acpi_wakeup_cpus(sc);
-#endif
}
-#ifdef SMP
if (!CPU_EMPTY(&suspcpus))
resume_cpus(suspcpus);
-#endif
/*
* Re-read cpu_stdext_feature3, which was zeroed-out
diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S
index 6e51ebff298a..e98bae9eb6c5 100644
--- a/sys/amd64/amd64/apic_vector.S
+++ b/sys/amd64/amd64/apic_vector.S
@@ -49,12 +49,6 @@
#include <machine/specialreg.h>
#include <x86/apicreg.h>
-#ifdef SMP
-#define LK lock ;
-#else
-#define LK
-#endif
-
.text
SUPERALIGN_TEXT
/* End Of Interrupt to APIC */
@@ -163,7 +157,6 @@ IDTVEC(spuriousint)
jmp doreti
#endif
-#ifdef SMP
/*
* Global address space TLB shootdown.
*/
@@ -270,5 +263,3 @@ IDTVEC(justreturn)
INTR_HANDLER justreturn1
call as_lapic_eoi
jmp doreti
-
-#endif /* SMP */
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
index a053f6c70af1..d7e954f573b0 100644
--- a/sys/amd64/amd64/cpu_switch.S
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -136,7 +136,7 @@ ctx_switch_fpusave_done:
movq %r15,TD_LOCK(%r13) /* Release the old thread */
sw1:
leaq TD_MD_PCB(%r12),%r8
-#if defined(SCHED_ULE) && defined(SMP)
+#if defined(SCHED_ULE)
movq $blocked_lock, %rdx
movq TD_LOCK(%r12),%rcx
cmpq %rcx, %rdx
@@ -492,7 +492,7 @@ ENTRY(resumectx)
END(resumectx)
/* Wait for the new thread to become unblocked */
-#if defined(SCHED_ULE) && defined(SMP)
+#if defined(SCHED_ULE)
sw1wait:
1:
pause
diff --git a/sys/amd64/amd64/efirt_machdep.c b/sys/amd64/amd64/efirt_machdep.c
index 81a28ebe97ee..fe5d60c978dd 100644
--- a/sys/amd64/amd64/efirt_machdep.c
+++ b/sys/amd64/amd64/efirt_machdep.c
@@ -56,6 +56,13 @@
#include <vm/vm_pager.h>
#include <vm/vm_radix.h>
+/* The EFI regions we're allowed to map. */
+#define EFI_ALLOWED_TYPES_MASK ( \
+ 1u << EFI_MD_TYPE_BS_CODE | 1u << EFI_MD_TYPE_BS_DATA | \
+ 1u << EFI_MD_TYPE_RT_CODE | 1u << EFI_MD_TYPE_RT_DATA | \
+ 1u << EFI_MD_TYPE_FIRMWARE \
+)
+
static pml5_entry_t *efi_pml5;
static pml4_entry_t *efi_pml4;
static vm_object_t obj_1t1_pt;
@@ -181,6 +188,7 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz)
vm_offset_t va;
uint64_t idx;
int bits, i, mode;
+ bool map_pz = true;
obj_1t1_pt = vm_pager_allocate(OBJT_PHYS, NULL, ptoa(1 +
NPML4EPG + NPML4EPG * NPDPEPG + NPML4EPG * NPDPEPG * NPDEPG),
@@ -198,9 +206,16 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz)
pmap_pinit_pml4(efi_pmltop_page);
}
+ if ((efi_map_regs & ~EFI_ALLOWED_TYPES_MASK) != 0) {
+ printf("Ignoring the following runtime EFI regions: %#x\n",
+ efi_map_regs & ~EFI_ALLOWED_TYPES_MASK);
+ efi_map_regs &= EFI_ALLOWED_TYPES_MASK;
+ }
+
for (i = 0, p = map; i < ndesc; i++, p = efi_next_descriptor(p,
descsz)) {
- if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
+ if ((p->md_attr & EFI_MD_ATTR_RT) == 0 &&
+ !EFI_MAP_BOOTTYPE_ALLOWED(p->md_type))
continue;
if (p->md_virt != 0 && p->md_virt != p->md_phys) {
if (bootverbose)
@@ -256,6 +271,22 @@ efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz)
}
}
VM_OBJECT_WUNLOCK(obj_1t1_pt);
+ if (p->md_phys == 0)
+ map_pz = false;
+ }
+
+ /*
+ * Some BIOSes tend to access phys 0 during efirt calls,
+ * so map it if we haven't yet.
+ */
+ if (map_pz) {
+ VM_OBJECT_WLOCK(obj_1t1_pt);
+ pte = efi_1t1_pte(0);
+ /* Assume Write-Back */
+ bits = pmap_cache_bits(kernel_pmap, VM_MEMATTR_WRITE_BACK,
+ false) | X86_PG_RW | X86_PG_V;
+ pte_store(pte, bits);
+ VM_OBJECT_WUNLOCK(obj_1t1_pt);
}
return (true);
diff --git a/sys/amd64/amd64/exec_machdep.c b/sys/amd64/amd64/exec_machdep.c
index da68289e2c83..6752b716deb5 100644
--- a/sys/amd64/amd64/exec_machdep.c
+++ b/sys/amd64/amd64/exec_machdep.c
@@ -59,9 +59,7 @@
#include <sys/reg.h>
#include <sys/rwlock.h>
#include <sys/signalvar.h>
-#ifdef SMP
#include <sys/smp.h>
-#endif
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 032a134bbd4b..37c7056f649c 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -38,7 +38,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "opt_atpic.h"
#include "opt_cpu.h"
#include "opt_ddb.h"
@@ -82,9 +81,7 @@
#include <sys/rwlock.h>
#include <sys/sched.h>
#include <sys/signalvar.h>
-#ifdef SMP
#include <sys/smp.h>
-#endif
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
@@ -132,9 +129,7 @@
#include <machine/tss.h>
#include <x86/ucode.h>
#include <x86/ifunc.h>
-#ifdef SMP
#include <machine/smp.h>
-#endif
#ifdef FDT
#include <x86/fdt.h>
#endif
@@ -149,6 +144,10 @@
#include <isa/rtc.h>
#include <x86/init.h>
+#ifndef SMP
+#error amd64 requires options SMP
+#endif
+
/* Sanity check for __curthread() */
CTASSERT(offsetof(struct pcpu, pc_curthread) == 0);
@@ -188,6 +187,12 @@ struct init_ops init_ops = {
*/
vm_paddr_t efi_systbl_phys;
+/*
+ * Bitmap of extra EFI memory region types that should be preserved and mapped
+ * during runtime services calls.
+ */
+uint32_t efi_map_regs;
+
/* Intel ICH registers */
#define ICH_PMBASE 0x400
#define ICH_SMI_EN ICH_PMBASE + 0x30
@@ -645,7 +650,7 @@ add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap,
* NB: physmap_idx points to the next free slot.
*/
insert_idx = physmap_idx;
- for (i = 0; i <= physmap_idx; i += 2) {
+ for (i = 0; i < physmap_idx; i += 2) {
if (base < physmap[i + 1]) {
if (base + length <= physmap[i]) {
insert_idx = i;
@@ -659,7 +664,7 @@ add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap,
}
/* See if we can prepend to the next entry. */
- if (insert_idx <= physmap_idx && base + length == physmap[insert_idx]) {
+ if (insert_idx < physmap_idx && base + length == physmap[insert_idx]) {
physmap[insert_idx] = base;
return (1);
}
@@ -670,8 +675,6 @@ add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap,
return (1);
}
- physmap_idx += 2;
- *physmap_idxp = physmap_idx;
if (physmap_idx == PHYS_AVAIL_ENTRIES) {
printf(
"Too many segments in the physical address map, giving up\n");
@@ -682,11 +685,14 @@ add_physmap_entry(uint64_t base, uint64_t length, vm_paddr_t *physmap,
* Move the last 'N' entries down to make room for the new
* entry if needed.
*/
- for (i = (physmap_idx - 2); i > insert_idx; i -= 2) {
+ for (i = physmap_idx; i > insert_idx; i -= 2) {
physmap[i] = physmap[i - 2];
physmap[i + 1] = physmap[i - 1];
}
+ physmap_idx += 2;
+ *physmap_idxp = physmap_idx;
+
/* Insert the new entry. */
physmap[insert_idx] = base;
physmap[insert_idx + 1] = base + length;
@@ -757,6 +763,7 @@ add_efi_map_entries(struct efi_map_header *efihdr, vm_paddr_t *physmap,
printf("%23s %12s %12s %8s %4s\n",
"Type", "Physical", "Virtual", "#Pages", "Attr");
+ TUNABLE_INT_FETCH("machdep.efirt.regs", &efi_map_regs);
for (i = 0, p = map; i < ndesc; i++,
p = efi_next_descriptor(p, efihdr->descriptor_size)) {
if (boothowto & RB_VERBOSE) {
@@ -794,10 +801,13 @@ add_efi_map_entries(struct efi_map_header *efihdr, vm_paddr_t *physmap,
}
switch (p->md_type) {
- case EFI_MD_TYPE_CODE:
- case EFI_MD_TYPE_DATA:
case EFI_MD_TYPE_BS_CODE:
case EFI_MD_TYPE_BS_DATA:
+ if (EFI_MAP_BOOTTYPE_ALLOWED(p->md_type))
+ continue;
+ /* FALLTHROUGH */
+ case EFI_MD_TYPE_CODE:
+ case EFI_MD_TYPE_DATA:
case EFI_MD_TYPE_FREE:
/*
* We're allowed to use any entry with these types.
diff --git a/sys/amd64/amd64/mem.c b/sys/amd64/amd64/mem.c
index 413b7c74890e..851f2df0e6e1 100644
--- a/sys/amd64/amd64/mem.c
+++ b/sys/amd64/amd64/mem.c
@@ -105,8 +105,8 @@ memrw(struct cdev *dev, struct uio *uio, int flags)
* PAGE_SIZE, the uiomove() call does not
* access past the end of the direct map.
*/
- if (v >= DMAP_MIN_ADDRESS &&
- v < DMAP_MIN_ADDRESS + dmaplimit) {
+ if (v >= kva_layout.dmap_low &&
+ v < kva_layout.dmap_high) {
error = uiomove((void *)v, c, uio);
break;
}
diff --git a/sys/amd64/amd64/minidump_machdep.c b/sys/amd64/amd64/minidump_machdep.c
index 6d0917e16099..43bf81a991bf 100644
--- a/sys/amd64/amd64/minidump_machdep.c
+++ b/sys/amd64/amd64/minidump_machdep.c
@@ -186,7 +186,7 @@ cpu_minidumpsys(struct dumperinfo *di, const struct minidumpstate *state)
* tables, so care must be taken to read each entry only once.
*/
pmapsize = 0;
- for (va = VM_MIN_KERNEL_ADDRESS; va < kva_end; ) {
+ for (va = kva_layout.km_low; va < kva_end; ) {
/*
* We always write a page, even if it is zero. Each
* page written corresponds to 1GB of space
@@ -279,9 +279,9 @@ cpu_minidumpsys(struct dumperinfo *di, const struct minidumpstate *state)
mdhdr.msgbufsize = mbp->msg_size;
mdhdr.bitmapsize = round_page(BITSET_SIZE(vm_page_dump_pages));
mdhdr.pmapsize = pmapsize;
- mdhdr.kernbase = VM_MIN_KERNEL_ADDRESS;
- mdhdr.dmapbase = DMAP_MIN_ADDRESS;
- mdhdr.dmapend = DMAP_MAX_ADDRESS;
+ mdhdr.kernbase = kva_layout.km_low;
+ mdhdr.dmapbase = kva_layout.dmap_low;
+ mdhdr.dmapend = kva_layout.dmap_high;
mdhdr.dumpavailsize = round_page(sizeof(dump_avail));
dump_init_header(di, &kdh, KERNELDUMPMAGIC, KERNELDUMP_AMD64_VERSION,
@@ -323,7 +323,7 @@ cpu_minidumpsys(struct dumperinfo *di, const struct minidumpstate *state)
/* Dump kernel page directory pages */
bzero(fakepd, sizeof(fakepd));
- for (va = VM_MIN_KERNEL_ADDRESS; va < kva_end; va += NBPDP) {
+ for (va = kva_layout.km_low; va < kva_end; va += NBPDP) {
ii = pmap_pml4e_index(va);
pml4 = (uint64_t *)PHYS_TO_DMAP(KPML4phys) + ii;
pdp = (uint64_t *)PHYS_TO_DMAP(*pml4 & PG_FRAME);
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 2ab8c3b17e22..d1d80afccdc7 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -162,9 +162,7 @@
#include <machine/msan.h>
#include <machine/pcb.h>
#include <machine/specialreg.h>
-#ifdef SMP
#include <machine/smp.h>
-#endif
#include <machine/sysarch.h>
#include <machine/tss.h>
@@ -415,7 +413,7 @@ SYSCTL_INT(_machdep, OID_AUTO, nkpt, CTLFLAG_RD, &nkpt, 0,
static int ndmpdp;
vm_paddr_t dmaplimit;
-vm_offset_t kernel_vm_end = VM_MIN_KERNEL_ADDRESS;
+vm_offset_t kernel_vm_end = VM_MIN_KERNEL_ADDRESS_LA48;
pt_entry_t pg_nx;
static SYSCTL_NODE(_vm, OID_AUTO, pmap, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
@@ -475,11 +473,56 @@ _Static_assert(DMPML4I + NDMPML4E <= KMSANSHADPML4I, "direct map overflow");
static pml4_entry_t *kernel_pml4;
static u_int64_t DMPDphys; /* phys addr of direct mapped level 2 */
static u_int64_t DMPDPphys; /* phys addr of direct mapped level 3 */
+static u_int64_t DMPML4phys; /* ... level 4, for la57 */
static int ndmpdpphys; /* number of DMPDPphys pages */
vm_paddr_t kernphys; /* phys addr of start of bootstrap data */
vm_paddr_t KERNend; /* and the end */
+struct kva_layout_s kva_layout = {
+ .kva_min = KV4ADDR(PML4PML4I, 0, 0, 0),
+ .kva_max = KV4ADDR(NPML4EPG - 1, NPDPEPG - 1,
+ NPDEPG - 1, NPTEPG - 1),
+ .dmap_low = KV4ADDR(DMPML4I, 0, 0, 0),
+ .dmap_high = KV4ADDR(DMPML4I + NDMPML4E, 0, 0, 0),
+ .lm_low = KV4ADDR(LMSPML4I, 0, 0, 0),
+ .lm_high = KV4ADDR(LMEPML4I + 1, 0, 0, 0),
+ .km_low = KV4ADDR(KPML4BASE, 0, 0, 0),
+ .km_high = KV4ADDR(KPML4BASE + NKPML4E - 1, NPDPEPG - 1,
+ NPDEPG - 1, NPTEPG - 1),
+ .rec_pt = KV4ADDR(PML4PML4I, 0, 0, 0),
+ .kasan_shadow_low = KV4ADDR(KASANPML4I, 0, 0, 0),
+ .kasan_shadow_high = KV4ADDR(KASANPML4I + NKASANPML4E, 0, 0, 0),
+ .kmsan_shadow_low = KV4ADDR(KMSANSHADPML4I, 0, 0, 0),
+ .kmsan_shadow_high = KV4ADDR(KMSANSHADPML4I + NKMSANSHADPML4E,
+ 0, 0, 0),
+ .kmsan_origin_low = KV4ADDR(KMSANORIGPML4I, 0, 0, 0),
+ .kmsan_origin_high = KV4ADDR(KMSANORIGPML4I + NKMSANORIGPML4E,
+ 0, 0, 0),
+};
+
+struct kva_layout_s kva_layout_la57 = {
+ .kva_min = KV5ADDR(NPML5EPG / 2, 0, 0, 0, 0), /* == rec_pt */
+ .kva_max = KV5ADDR(NPML5EPG - 1, NPML4EPG - 1, NPDPEPG - 1,
+ NPDEPG - 1, NPTEPG - 1),
+ .dmap_low = KV5ADDR(DMPML5I, 0, 0, 0, 0),
+ .dmap_high = KV5ADDR(DMPML5I + NDMPML5E, 0, 0, 0, 0),
+ .lm_low = KV5ADDR(LMSPML5I, 0, 0, 0, 0),
+ .lm_high = KV5ADDR(LMEPML5I + 1, 0, 0, 0, 0),
+ .km_low = KV4ADDR(KPML4BASE, 0, 0, 0),
+ .km_high = KV4ADDR(KPML4BASE + NKPML4E - 1, NPDPEPG - 1,
+ NPDEPG - 1, NPTEPG - 1),
+ .rec_pt = KV5ADDR(PML5PML5I, 0, 0, 0, 0),
+ .kasan_shadow_low = KV4ADDR(KASANPML4I, 0, 0, 0),
+ .kasan_shadow_high = KV4ADDR(KASANPML4I + NKASANPML4E, 0, 0, 0),
+ .kmsan_shadow_low = KV4ADDR(KMSANSHADPML4I, 0, 0, 0),
+ .kmsan_shadow_high = KV4ADDR(KMSANSHADPML4I + NKMSANSHADPML4E,
+ 0, 0, 0),
+ .kmsan_origin_low = KV4ADDR(KMSANORIGPML4I, 0, 0, 0),
+ .kmsan_origin_high = KV4ADDR(KMSANORIGPML4I + NKMSANORIGPML4E,
+ 0, 0, 0),
+};
+
/*
* pmap_mapdev support pre initialization (i.e. console)
*/
@@ -549,8 +592,8 @@ static int pmap_flags = PMAP_PDE_SUPERPAGE; /* flags for x86 pmaps */
static vmem_t *large_vmem;
static u_int lm_ents;
-#define PMAP_ADDRESS_IN_LARGEMAP(va) ((va) >= LARGEMAP_MIN_ADDRESS && \
- (va) < LARGEMAP_MIN_ADDRESS + NBPML4 * (u_long)lm_ents)
+#define PMAP_ADDRESS_IN_LARGEMAP(va) ((va) >= kva_layout.lm_low && \
+ (va) < kva_layout.lm_high)
int pmap_pcid_enabled = 1;
SYSCTL_INT(_vm_pmap, OID_AUTO, pcid_enabled, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
@@ -1301,8 +1344,10 @@ static int pmap_change_props_locked(vm_offset_t va, vm_size_t size,
static bool pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va);
static bool pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde,
vm_offset_t va, struct rwlock **lockp);
+static bool pmap_demote_pde_mpte(pmap_t pmap, pd_entry_t *pde,
+ vm_offset_t va, struct rwlock **lockp, vm_page_t mpte);
static bool pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe,
- vm_offset_t va);
+ vm_offset_t va, vm_page_t m);
static int pmap_enter_2mpage(pmap_t pmap, vm_offset_t va, vm_page_t m,
vm_prot_t prot, struct rwlock **lockp);
static int pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde,
@@ -1334,7 +1379,7 @@ static pdp_entry_t *pmap_pti_pdpe(vm_offset_t va);
static pd_entry_t *pmap_pti_pde(vm_offset_t va);
static void pmap_pti_wire_pte(void *pte);
static int pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva,
- struct spglist *free, struct rwlock **lockp);
+ bool demote_kpde, struct spglist *free, struct rwlock **lockp);
static int pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t sva,
pd_entry_t ptepde, struct spglist *free, struct rwlock **lockp);
static vm_page_t pmap_remove_pt_page(pmap_t pmap, vm_offset_t va);
@@ -1720,7 +1765,7 @@ create_pagetables(vm_paddr_t *firstaddr)
{
pd_entry_t *pd_p;
pdp_entry_t *pdp_p;
- pml4_entry_t *p4_p;
+ pml4_entry_t *p4_p, *p4d_p;
pml5_entry_t *p5_p;
uint64_t DMPDkernphys;
vm_paddr_t pax;
@@ -1730,7 +1775,7 @@ create_pagetables(vm_paddr_t *firstaddr)
vm_offset_t kasankernbase;
int kasankpdpi, kasankpdi, nkasanpte;
#endif
- int i, j, ndm1g, nkpdpe, nkdmpde;
+ int i, j, ndm1g, nkpdpe, nkdmpde, ndmpml4phys;
TSENTER();
/* Allocate page table pages for the direct map */
@@ -1738,15 +1783,30 @@ create_pagetables(vm_paddr_t *firstaddr)
if (ndmpdp < 4) /* Minimum 4GB of dirmap */
ndmpdp = 4;
ndmpdpphys = howmany(ndmpdp, NPDPEPG);
- if (ndmpdpphys > NDMPML4E) {
- /*
- * Each NDMPML4E allows 512 GB, so limit to that,
- * and then readjust ndmpdp and ndmpdpphys.
- */
- printf("NDMPML4E limits system to %d GB\n", NDMPML4E * 512);
- Maxmem = atop(NDMPML4E * NBPML4);
- ndmpdpphys = NDMPML4E;
- ndmpdp = NDMPML4E * NPDEPG;
+ if (la57) {
+ ndmpml4phys = howmany(ndmpdpphys, NPML4EPG);
+ if (ndmpml4phys > NDMPML5E) {
+ printf("NDMPML5E limits system to %ld GB\n",
+ (u_long)NDMPML5E * NBPML5 / 1024 / 1024 / 1024);
+ Maxmem = atop(NDMPML5E * NBPML5);
+ ndmpml4phys = NDMPML5E;
+ ndmpdpphys = ndmpml4phys * NPML4EPG;
+ ndmpdp = ndmpdpphys * NPDEPG;
+ }
+ DMPML4phys = allocpages(firstaddr, ndmpml4phys);
+ } else {
+ if (ndmpdpphys > NDMPML4E) {
+ /*
+ * Each NDMPML4E allows 512 GB, so limit to
+ * that, and then readjust ndmpdp and
+ * ndmpdpphys.
+ */
+ printf("NDMPML4E limits system to %d GB\n",
+ NDMPML4E * 512);
+ Maxmem = atop(NDMPML4E * NBPML4);
+ ndmpdpphys = NDMPML4E;
+ ndmpdp = NDMPML4E * NPDEPG;
+ }
}
DMPDPphys = allocpages(firstaddr, ndmpdpphys);
ndm1g = 0;
@@ -1771,7 +1831,13 @@ create_pagetables(vm_paddr_t *firstaddr)
dmaplimit = (vm_paddr_t)ndmpdp << PDPSHIFT;
/* Allocate pages. */
+ if (la57) {
+ KPML5phys = allocpages(firstaddr, 1);
+ p5_p = (pml5_entry_t *)KPML5phys;
+ }
KPML4phys = allocpages(firstaddr, 1);
+ p4_p = (pml4_entry_t *)KPML4phys;
+
KPDPphys = allocpages(firstaddr, NKPML4E);
#ifdef KASAN
KASANPDPphys = allocpages(firstaddr, NKASANPML4E);
@@ -1891,6 +1957,16 @@ create_pagetables(vm_paddr_t *firstaddr)
}
/*
+ * Connect the Direct Map slots up to the PML4.
+ * pml5 entries for DMAP are handled below in global pml5 loop.
+ */
+ p4d_p = la57 ? (pml4_entry_t *)DMPML4phys : &p4_p[DMPML4I];
+ for (i = 0; i < ndmpdpphys; i++) {
+ p4d_p[i] = (DMPDPphys + ptoa(i)) | X86_PG_RW | X86_PG_V |
+ pg_nx;
+ }
+
+ /*
* Instead of using a 1G page for the memory containing the kernel,
* use 2M pages with read-only and no-execute permissions. (If using 1G
* pages, this will partially overwrite the PDPEs above.)
@@ -1909,11 +1985,6 @@ create_pagetables(vm_paddr_t *firstaddr)
}
}
- /* And recursively map PML4 to itself in order to get PTmap */
- p4_p = (pml4_entry_t *)KPML4phys;
- p4_p[PML4PML4I] = KPML4phys;
- p4_p[PML4PML4I] |= X86_PG_RW | X86_PG_V | pg_nx;
-
#ifdef KASAN
/* Connect the KASAN shadow map slots up to the PML4. */
for (i = 0; i < NKASANPML4E; i++) {
@@ -1936,25 +2007,15 @@ create_pagetables(vm_paddr_t *firstaddr)
}
#endif
- /* Connect the Direct Map slots up to the PML4. */
- for (i = 0; i < ndmpdpphys; i++) {
- p4_p[DMPML4I + i] = DMPDPphys + ptoa(i);
- p4_p[DMPML4I + i] |= X86_PG_RW | X86_PG_V | pg_nx;
- }
-
/* Connect the KVA slots up to the PML4 */
for (i = 0; i < NKPML4E; i++) {
p4_p[KPML4BASE + i] = KPDPphys + ptoa(i);
p4_p[KPML4BASE + i] |= X86_PG_RW | X86_PG_V;
}
- kernel_pml4 = (pml4_entry_t *)PHYS_TO_DMAP(KPML4phys);
-
if (la57) {
/* XXXKIB bootstrap KPML5phys page is lost */
- KPML5phys = allocpages(firstaddr, 1);
- for (i = 0, p5_p = (pml5_entry_t *)KPML5phys; i < NPML5EPG;
- i++) {
+ for (i = 0; i < NPML5EPG; i++) {
if (i == PML5PML5I) {
/*
* Recursively map PML5 to itself in
@@ -1962,6 +2023,10 @@ create_pagetables(vm_paddr_t *firstaddr)
*/
p5_p[i] = KPML5phys | X86_PG_RW | X86_PG_A |
X86_PG_M | X86_PG_V | pg_nx;
+ } else if (i >= DMPML5I && i < DMPML5I + ndmpml4phys) {
+ /* Connect DMAP pml4 pages to PML5. */
+ p5_p[i] = (DMPML4phys + ptoa(i - DMPML5I)) |
+ X86_PG_RW | X86_PG_V | pg_nx;
} else if (i == pmap_pml5e_index(UPT_MAX_ADDRESS)) {
p5_p[i] = KPML4phys | X86_PG_RW | X86_PG_A |
X86_PG_M | X86_PG_V;
@@ -1969,6 +2034,10 @@ create_pagetables(vm_paddr_t *firstaddr)
p5_p[i] = 0;
}
}
+ } else {
+ /* Recursively map PML4 to itself in order to get PTmap */
+ p4_p[PML4PML4I] = KPML4phys;
+ p4_p[PML4PML4I] |= X86_PG_RW | X86_PG_V | pg_nx;
}
TSEXIT();
}
@@ -2022,7 +2091,7 @@ pmap_bootstrap(vm_paddr_t *firstaddr)
*/
virtual_avail = (vm_offset_t)KERNSTART + round_2mpage(KERNend -
(vm_paddr_t)kernphys);
- virtual_end = VM_MAX_KERNEL_ADDRESS;
+ virtual_end = kva_layout.km_high;
/*
* Enable PG_G global pages, then switch to the kernel page
@@ -2044,9 +2113,13 @@ pmap_bootstrap(vm_paddr_t *firstaddr)
* Initialize the kernel pmap (which is statically allocated).
* Count bootstrap data as being resident in case any of this data is
* later unmapped (using pmap_remove()) and freed.
+ *
+ * DMAP_TO_PHYS()/PHYS_TO_DMAP() are functional only after
+ * kva_layout is fixed.
*/
PMAP_LOCK_INIT(kernel_pmap);
if (la57) {
+ kva_layout = kva_layout_la57;
vtoptem = ((1ul << (NPTEPGSHIFT + NPDEPGSHIFT + NPDPEPGSHIFT +
NPML4EPGSHIFT + NPML5EPGSHIFT)) - 1) << 3;
PTmap = (vm_offset_t)P5Tmap;
@@ -2057,6 +2130,7 @@ pmap_bootstrap(vm_paddr_t *firstaddr)
kernel_pmap->pm_cr3 = KPML5phys;
pmap_pt_page_count_adj(kernel_pmap, 1); /* top-level page */
} else {
+ kernel_pml4 = (pml4_entry_t *)PHYS_TO_DMAP(KPML4phys);
kernel_pmap->pm_pmltop = kernel_pml4;
kernel_pmap->pm_cr3 = KPML4phys;
}
@@ -2418,6 +2492,8 @@ pmap_init(void)
{
struct pmap_preinit_mapping *ppim;
vm_page_t m, mpte;
+ pml4_entry_t *pml4e;
+ unsigned long lm_max;
int error, i, ret, skz63;
/* L1TF, reserve page @0 unconditionally */
@@ -2543,10 +2619,15 @@ pmap_init(void)
lm_ents = 8;
TUNABLE_INT_FETCH("vm.pmap.large_map_pml4_entries", &lm_ents);
- if (lm_ents > LMEPML4I - LMSPML4I + 1)
- lm_ents = LMEPML4I - LMSPML4I + 1;
+ lm_max = (kva_layout.lm_high - kva_layout.lm_low) / NBPML4;
+ if (lm_ents > lm_max) {
+ printf(
+ "pmap: shrinking large map from requested %d slots to %ld slots\n",
+ lm_ents, lm_max);
+ lm_ents = lm_max;
+ }
#ifdef KMSAN
- if (lm_ents > KMSANORIGPML4I - LMSPML4I) {
+ if (!la57 && lm_ents > KMSANORIGPML4I - LMSPML4I) {
printf(
"pmap: shrinking large map for KMSAN (%d slots to %ld slots)\n",
lm_ents, KMSANORIGPML4I - LMSPML4I);
@@ -2557,18 +2638,27 @@ pmap_init(void)
printf("pmap: large map %u PML4 slots (%lu GB)\n",
lm_ents, (u_long)lm_ents * (NBPML4 / 1024 / 1024 / 1024));
if (lm_ents != 0) {
- large_vmem = vmem_create("large", LARGEMAP_MIN_ADDRESS,
+ large_vmem = vmem_create("large", kva_layout.lm_low,
(vmem_size_t)lm_ents * NBPML4, PAGE_SIZE, 0, M_WAITOK);
if (large_vmem == NULL) {
printf("pmap: cannot create large map\n");
lm_ents = 0;
}
+ if (la57) {
+ for (i = 0; i < howmany((vm_offset_t)NBPML4 *
+ lm_ents, NBPML5); i++) {
+ m = pmap_large_map_getptp_unlocked();
+ kernel_pmap->pm_pmltop[LMSPML5I + i] = X86_PG_V |
+ X86_PG_RW | X86_PG_A | X86_PG_M |
+ pg_nx | VM_PAGE_TO_PHYS(m);
+ }
+ }
for (i = 0; i < lm_ents; i++) {
m = pmap_large_map_getptp_unlocked();
- /* XXXKIB la57 */
- kernel_pml4[LMSPML4I + i] = X86_PG_V |
- X86_PG_RW | X86_PG_A | X86_PG_M | pg_nx |
- VM_PAGE_TO_PHYS(m);
+ pml4e = pmap_pml4e(kernel_pmap, kva_layout.lm_low +
+ (u_long)i * NBPML4);
+ *pml4e = X86_PG_V | X86_PG_RW | X86_PG_A | X86_PG_M |
+ pg_nx | VM_PAGE_TO_PHYS(m);
}
}
}
@@ -2973,7 +3063,6 @@ pmap_update_pde_invalidate(pmap_t pmap, vm_offset_t va, pd_entry_t newpde)
* XXX TODO
*/
-#ifdef SMP
/*
* Interrupt the cpus that are executing in the guest context.
* This will force the vcpu to exit and the cached EPT mappings
@@ -3431,168 +3520,6 @@ pmap_update_pde(pmap_t pmap, vm_offset_t va, pd_entry_t *pde, pd_entry_t newpde)
}
sched_unpin();
}
-#else /* !SMP */
-/*
- * Normal, non-SMP, invalidation functions.
- */
-void
-pmap_invalidate_page(pmap_t pmap, vm_offset_t va)
-{
- struct invpcid_descr d;
- struct pmap_pcid *pcidp;
- uint64_t kcr3, ucr3;
- uint32_t pcid;
-
- if (pmap->pm_type == PT_RVI || pmap->pm_type == PT_EPT) {
- pmap->pm_eptgen++;
- return;
- }
- KASSERT(pmap->pm_type == PT_X86,
- ("pmap_invalidate_range: unknown type %d", pmap->pm_type));
-
- if (pmap == kernel_pmap || pmap == PCPU_GET(curpmap)) {
- invlpg(va);
- if (pmap == PCPU_GET(curpmap) && pmap_pcid_enabled &&
- pmap->pm_ucr3 != PMAP_NO_CR3) {
- critical_enter();
- pcid = pmap_get_pcid(pmap);
- if (invpcid_works) {
- d.pcid = pcid | PMAP_PCID_USER_PT;
- d.pad = 0;
- d.addr = va;
- invpcid(&d, INVPCID_ADDR);
- } else {
- kcr3 = pmap->pm_cr3 | pcid | CR3_PCID_SAVE;
- ucr3 = pmap->pm_ucr3 | pcid |
- PMAP_PCID_USER_PT | CR3_PCID_SAVE;
- pmap_pti_pcid_invlpg(ucr3, kcr3, va);
- }
- critical_exit();
- }
- } else if (pmap_pcid_enabled) {
- pcidp = zpcpu_get(pmap->pm_pcidp);
- pcidp->pm_gen = 0;
- }
-}
-
-void
-pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
-{
- struct invpcid_descr d;
- struct pmap_pcid *pcidp;
- vm_offset_t addr;
- uint64_t kcr3, ucr3;
- uint32_t pcid;
-
- if (pmap->pm_type == PT_RVI || pmap->pm_type == PT_EPT) {
- pmap->pm_eptgen++;
- return;
- }
- KASSERT(pmap->pm_type == PT_X86,
- ("pmap_invalidate_range: unknown type %d", pmap->pm_type));
-
- if (pmap == kernel_pmap || pmap == PCPU_GET(curpmap)) {
- for (addr = sva; addr < eva; addr += PAGE_SIZE)
- invlpg(addr);
- if (pmap == PCPU_GET(curpmap) && pmap_pcid_enabled &&
- pmap->pm_ucr3 != PMAP_NO_CR3) {
- critical_enter();
- pcid = pmap_get_pcid(pmap);
- if (invpcid_works) {
- d.pcid = pcid | PMAP_PCID_USER_PT;
- d.pad = 0;
- d.addr = sva;
- for (; d.addr < eva; d.addr += PAGE_SIZE)
- invpcid(&d, INVPCID_ADDR);
- } else {
- kcr3 = pmap->pm_cr3 | pcid | CR3_PCID_SAVE;
- ucr3 = pmap->pm_ucr3 | pcid |
- PMAP_PCID_USER_PT | CR3_PCID_SAVE;
- pmap_pti_pcid_invlrng(ucr3, kcr3, sva, eva);
- }
- critical_exit();
- }
- } else if (pmap_pcid_enabled) {
- pcidp = zpcpu_get(pmap->pm_pcidp);
- pcidp->pm_gen = 0;
- }
-}
-
-void
-pmap_invalidate_all(pmap_t pmap)
-{
- struct invpcid_descr d;
- struct pmap_pcid *pcidp;
- uint64_t kcr3, ucr3;
- uint32_t pcid;
-
- if (pmap->pm_type == PT_RVI || pmap->pm_type == PT_EPT) {
- pmap->pm_eptgen++;
- return;
- }
- KASSERT(pmap->pm_type == PT_X86,
- ("pmap_invalidate_all: unknown type %d", pmap->pm_type));
-
- if (pmap == kernel_pmap) {
- if (pmap_pcid_enabled && invpcid_works) {
- bzero(&d, sizeof(d));
- invpcid(&d, INVPCID_CTXGLOB);
- } else {
- invltlb_glob();
- }
- } else if (pmap == PCPU_GET(curpmap)) {
- if (pmap_pcid_enabled) {
- critical_enter();
- pcid = pmap_get_pcid(pmap);
- if (invpcid_works) {
- d.pcid = pcid;
- d.pad = 0;
- d.addr = 0;
- invpcid(&d, INVPCID_CTX);
- if (pmap->pm_ucr3 != PMAP_NO_CR3) {
- d.pcid |= PMAP_PCID_USER_PT;
- invpcid(&d, INVPCID_CTX);
- }
- } else {
- kcr3 = pmap->pm_cr3 | pcid;
- if (pmap->pm_ucr3 != PMAP_NO_CR3) {
- ucr3 = pmap->pm_ucr3 | pcid |
- PMAP_PCID_USER_PT;
- pmap_pti_pcid_invalidate(ucr3, kcr3);
- } else
- load_cr3(kcr3);
- }
- critical_exit();
- } else {
- invltlb();
- }
- } else if (pmap_pcid_enabled) {
- pcidp = zpcpu_get(pmap->pm_pcidp);
- pcidp->pm_gen = 0;
- }
-}
-
-void
-pmap_invalidate_cache(void)
-{
-
- wbinvd();
-}
-
-static void
-pmap_update_pde(pmap_t pmap, vm_offset_t va, pd_entry_t *pde, pd_entry_t newpde)
-{
- struct pmap_pcid *pcidp;
-
- pmap_update_pde_store(pmap, pde, newpde);
- if (pmap == kernel_pmap || pmap == PCPU_GET(curpmap))
- pmap_update_pde_invalidate(pmap, va, newpde);
- else {
- pcidp = zpcpu_get(pmap->pm_pcidp);
- pcidp->pm_gen = 0;
- }
-}
-#endif /* !SMP */
static void
pmap_invalidate_pde_page(pmap_t pmap, vm_offset_t va, pd_entry_t pde)
@@ -3897,7 +3824,7 @@ pmap_kextract(vm_offset_t va)
pd_entry_t pde;
vm_paddr_t pa;
- if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) {
+ if (va >= kva_layout.dmap_low && va < kva_layout.dmap_high) {
pa = DMAP_TO_PHYS(va);
} else if (PMAP_ADDRESS_IN_LARGEMAP(va)) {
pa = pmap_large_map_kextract(va);
@@ -4038,7 +3965,7 @@ pmap_qremove(vm_offset_t sva, int count)
* enough to one of those pmap_enter() calls for it to
* be caught up in a promotion.
*/
- KASSERT(va >= VM_MIN_KERNEL_ADDRESS, ("usermode va %lx", va));
+ KASSERT(va >= kva_layout.km_low, ("usermode va %lx", va));
KASSERT((*vtopde(va) & X86_PG_PS) == 0,
("pmap_qremove on promoted va %#lx", va));
@@ -4326,21 +4253,13 @@ void
pmap_pinit_pml5(vm_page_t pml5pg)
{
pml5_entry_t *pm_pml5;
+ int i;
pm_pml5 = (pml5_entry_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pml5pg));
-
- /*
- * Add pml5 entry at top of KVA pointing to existing pml4 table,
- * entering all existing kernel mappings into level 5 table.
- */
- pm_pml5[pmap_pml5e_index(UPT_MAX_ADDRESS)] = KPML4phys | X86_PG_V |
- X86_PG_RW | X86_PG_A | X86_PG_M;
-
- /*
- * Install self-referential address mapping entry.
- */
- pm_pml5[PML5PML5I] = VM_PAGE_TO_PHYS(pml5pg) |
- X86_PG_RW | X86_PG_V | X86_PG_M | X86_PG_A;
+ for (i = 0; i < NPML5EPG / 2; i++)
+ pm_pml5[i] = 0;
+ for (; i < NPML5EPG; i++)
+ pm_pml5[i] = kernel_pmap->pm_pmltop[i];
}
static void
@@ -4897,8 +4816,8 @@ pmap_release(pmap_t pmap)
m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pmap->pm_pmltop));
if (pmap_is_la57(pmap)) {
- pmap->pm_pmltop[pmap_pml5e_index(UPT_MAX_ADDRESS)] = 0;
- pmap->pm_pmltop[PML5PML5I] = 0;
+ for (i = NPML5EPG / 2; i < NPML5EPG; i++)
+ pmap->pm_pmltop[i] = 0;
} else {
for (i = 0; i < NKPML4E; i++) /* KVA */
pmap->pm_pmltop[KPML4BASE + i] = 0;
@@ -4940,7 +4859,7 @@ pmap_release(pmap_t pmap)
static int
kvm_size(SYSCTL_HANDLER_ARGS)
{
- unsigned long ksize = VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS;
+ unsigned long ksize = kva_layout.km_high - kva_layout.km_low;
return sysctl_handle_long(oidp, &ksize, 0, req);
}
@@ -4951,7 +4870,7 @@ SYSCTL_PROC(_vm, OID_AUTO, kvm_size, CTLTYPE_LONG | CTLFLAG_RD | CTLFLAG_MPSAFE,
static int
kvm_free(SYSCTL_HANDLER_ARGS)
{
- unsigned long kfree = VM_MAX_KERNEL_ADDRESS - kernel_vm_end;
+ unsigned long kfree = kva_layout.km_high - kernel_vm_end;
return sysctl_handle_long(oidp, &kfree, 0, req);
}
@@ -5029,7 +4948,7 @@ pmap_page_array_startup(long pages)
vm_page_array_size = pages;
- start = VM_MIN_KERNEL_ADDRESS;
+ start = kva_layout.km_low;
end = start + pages * sizeof(struct vm_page);
for (va = start; va < end; va += NBPDR) {
pfn = first_page + (va - start) / sizeof(struct vm_page);
@@ -5999,7 +5918,7 @@ pmap_demote_pde_abort(pmap_t pmap, vm_offset_t va, pd_entry_t *pde,
SLIST_INIT(&free);
sva = trunc_2mpage(va);
- pmap_remove_pde(pmap, pde, sva, &free, lockp);
+ pmap_remove_pde(pmap, pde, sva, true, &free, lockp);
if ((oldpde & pmap_global_bit(pmap)) == 0)
pmap_invalidate_pde_page(pmap, sva, oldpde);
vm_page_free_pages_toq(&free, true);
@@ -6011,11 +5930,17 @@ static bool
pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va,
struct rwlock **lockp)
{
+ return (pmap_demote_pde_mpte(pmap, pde, va, lockp, NULL));
+}
+
+static bool
+pmap_demote_pde_mpte(pmap_t pmap, pd_entry_t *pde, vm_offset_t va,
+ struct rwlock **lockp, vm_page_t mpte)
+{
pd_entry_t newpde, oldpde;
pt_entry_t *firstpte, newpte;
pt_entry_t PG_A, PG_G, PG_M, PG_PKU_MASK, PG_RW, PG_V;
vm_paddr_t mptepa;
- vm_page_t mpte;
int PG_PTE_CACHE;
bool in_kernel;
@@ -6028,61 +5953,65 @@ pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va,
PG_PKU_MASK = pmap_pku_mask_bit(pmap);
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
- in_kernel = va >= VM_MAXUSER_ADDRESS;
oldpde = *pde;
KASSERT((oldpde & (PG_PS | PG_V)) == (PG_PS | PG_V),
("pmap_demote_pde: oldpde is missing PG_PS and/or PG_V"));
-
- /*
- * Invalidate the 2MB page mapping and return "failure" if the
- * mapping was never accessed.
- */
- if ((oldpde & PG_A) == 0) {
- KASSERT((oldpde & PG_W) == 0,
- ("pmap_demote_pde: a wired mapping is missing PG_A"));
- pmap_demote_pde_abort(pmap, va, pde, oldpde, lockp);
- return (false);
- }
-
- mpte = pmap_remove_pt_page(pmap, va);
+ KASSERT((oldpde & PG_MANAGED) == 0 || lockp != NULL,
+ ("pmap_demote_pde: lockp for a managed mapping is NULL"));
+ in_kernel = va >= VM_MAXUSER_ADDRESS;
if (mpte == NULL) {
- KASSERT((oldpde & PG_W) == 0,
- ("pmap_demote_pde: page table page for a wired mapping"
- " is missing"));
-
/*
- * If the page table page is missing and the mapping
- * is for a kernel address, the mapping must belong to
- * the direct map. Page table pages are preallocated
- * for every other part of the kernel address space,
- * so the direct map region is the only part of the
- * kernel address space that must be handled here.
+ * Invalidate the 2MB page mapping and return "failure" if the
+ * mapping was never accessed.
*/
- KASSERT(!in_kernel || (va >= DMAP_MIN_ADDRESS &&
- va < DMAP_MAX_ADDRESS),
- ("pmap_demote_pde: No saved mpte for va %#lx", va));
-
- /*
- * If the 2MB page mapping belongs to the direct map
- * region of the kernel's address space, then the page
- * allocation request specifies the highest possible
- * priority (VM_ALLOC_INTERRUPT). Otherwise, the
- * priority is normal.
- */
- mpte = pmap_alloc_pt_page(pmap, pmap_pde_pindex(va),
- (in_kernel ? VM_ALLOC_INTERRUPT : 0) | VM_ALLOC_WIRED);
-
- /*
- * If the allocation of the new page table page fails,
- * invalidate the 2MB page mapping and return "failure".
- */
- if (mpte == NULL) {
+ if ((oldpde & PG_A) == 0) {
+ KASSERT((oldpde & PG_W) == 0,
+ ("pmap_demote_pde: a wired mapping is missing PG_A"));
pmap_demote_pde_abort(pmap, va, pde, oldpde, lockp);
return (false);
}
- if (!in_kernel)
- mpte->ref_count = NPTEPG;
+ mpte = pmap_remove_pt_page(pmap, va);
+ if (mpte == NULL) {
+ KASSERT((oldpde & PG_W) == 0,
+ ("pmap_demote_pde: page table page for a wired mapping is missing"));
+
+ /*
+ * If the page table page is missing and the mapping
+ * is for a kernel address, the mapping must belong to
+ * the direct map. Page table pages are preallocated
+ * for every other part of the kernel address space,
+ * so the direct map region is the only part of the
+ * kernel address space that must be handled here.
+ */
+ KASSERT(!in_kernel || (va >= kva_layout.dmap_low &&
+ va < kva_layout.dmap_high),
+ ("pmap_demote_pde: No saved mpte for va %#lx", va));
+
+ /*
+ * If the 2MB page mapping belongs to the direct map
+ * region of the kernel's address space, then the page
+ * allocation request specifies the highest possible
+ * priority (VM_ALLOC_INTERRUPT). Otherwise, the
+ * priority is normal.
+ */
+ mpte = pmap_alloc_pt_page(pmap, pmap_pde_pindex(va),
+ (in_kernel ? VM_ALLOC_INTERRUPT : 0) |
+ VM_ALLOC_WIRED);
+
+ /*
+ * If the allocation of the new page table page fails,
+ * invalidate the 2MB page mapping and return "failure".
+ */
+ if (mpte == NULL) {
+ pmap_demote_pde_abort(pmap, va, pde, oldpde,
+ lockp);
+ return (false);
+ }
+
+ if (!in_kernel)
+ mpte->ref_count = NPTEPG;
+ }
}
mptepa = VM_PAGE_TO_PHYS(mpte);
firstpte = (pt_entry_t *)PHYS_TO_DMAP(mptepa);
@@ -6162,8 +6091,7 @@ pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
KASSERT(pmap == kernel_pmap, ("pmap %p is not kernel_pmap", pmap));
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
mpte = pmap_remove_pt_page(pmap, va);
- if (mpte == NULL)
- panic("pmap_remove_kernel_pde: Missing pt page.");
+ KASSERT(mpte != NULL, ("pmap_remove_kernel_pde: missing pt page"));
mptepa = VM_PAGE_TO_PHYS(mpte);
newpde = mptepa | X86_PG_M | X86_PG_A | X86_PG_RW | X86_PG_V;
@@ -6193,7 +6121,7 @@ pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
* pmap_remove_pde: do the things to unmap a superpage in a process
*/
static int
-pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva,
+pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, bool demote_kpde,
struct spglist *free, struct rwlock **lockp)
{
struct md_page *pvh;
@@ -6233,9 +6161,7 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva,
pmap_delayed_invl_page(m);
}
}
- if (pmap == kernel_pmap) {
- pmap_remove_kernel_pde(pmap, pdq, sva);
- } else {
+ if (pmap != kernel_pmap) {
mpte = pmap_remove_pt_page(pmap, sva);
if (mpte != NULL) {
KASSERT(vm_page_any_valid(mpte),
@@ -6246,6 +6172,14 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva,
mpte->ref_count = 0;
pmap_add_delayed_free_list(mpte, free, false);
}
+ } else if (demote_kpde) {
+ pmap_remove_kernel_pde(pmap, pdq, sva);
+ } else {
+ mpte = vm_radix_lookup(&pmap->pm_root, pmap_pde_pindex(sva));
+ if (vm_page_any_valid(mpte)) {
+ mpte->valid = 0;
+ pmap_zero_page(mpte);
+ }
}
return (pmap_unuse_pt(pmap, sva, *pmap_pdpe(pmap, sva), free));
}
@@ -6476,7 +6410,8 @@ pmap_remove1(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, bool map_delete)
*/
if ((ptpaddr & PG_G) == 0)
anyvalid = 1;
- pmap_remove_pde(pmap, pde, sva, &free, &lock);
+ pmap_remove_pde(pmap, pde, sva, true, &free,
+ &lock);
continue;
} else if (!pmap_demote_pde_locked(pmap, pde, sva,
&lock)) {
@@ -7166,7 +7101,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
PG_RW = pmap_rw_bit(pmap);
va = trunc_page(va);
- KASSERT(va <= VM_MAX_KERNEL_ADDRESS, ("pmap_enter: toobig"));
+ KASSERT(va <= kva_layout.km_high, ("pmap_enter: toobig"));
KASSERT(va < UPT_MIN_ADDRESS || va >= UPT_MAX_ADDRESS,
("pmap_enter: invalid to pmap_enter page table pages (va: 0x%lx)",
va));
@@ -7495,6 +7430,9 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags,
PG_RW = pmap_rw_bit(pmap);
KASSERT((newpde & (pmap_modified_bit(pmap) | PG_RW)) != PG_RW,
("pmap_enter_pde: newpde is missing PG_M"));
+ KASSERT((flags & (PMAP_ENTER_NOREPLACE | PMAP_ENTER_NORECLAIM)) !=
+ PMAP_ENTER_NORECLAIM,
+ ("pmap_enter_pde: flags is missing PMAP_ENTER_NOREPLACE"));
PG_V = pmap_valid_bit(pmap);
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
@@ -7552,13 +7490,35 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags,
/*
* The reference to the PD page that was acquired by
* pmap_alloc_pde() ensures that it won't be freed.
- * However, if the PDE resulted from a promotion, then
+ * However, if the PDE resulted from a promotion, and
+ * the mapping is not from kernel_pmap, then
* a reserved PT page could be freed.
*/
- (void)pmap_remove_pde(pmap, pde, va, &free, lockp);
+ (void)pmap_remove_pde(pmap, pde, va, false, &free,
+ lockp);
if ((oldpde & PG_G) == 0)
pmap_invalidate_pde_page(pmap, va, oldpde);
} else {
+ if (va >= VM_MAXUSER_ADDRESS) {
+ /*
+ * Try to save the ptp in the trie
+ * before any changes to mappings are
+ * made. Abort on failure.
+ */
+ mt = PHYS_TO_VM_PAGE(oldpde & PG_FRAME);
+ if (pmap_insert_pt_page(pmap, mt, false,
+ false)) {
+ CTR1(KTR_PMAP,
+ "pmap_enter_pde: cannot ins kern ptp va %#lx",
+ va);
+ return (KERN_RESOURCE_SHORTAGE);
+ }
+ /*
+ * Both pmap_remove_pde() and
+ * pmap_remove_ptes() will zero-fill
+ * the kernel page table page.
+ */
+ }
pmap_delayed_invl_start();
if (pmap_remove_ptes(pmap, va, va + NBPDR, pde, &free,
lockp))
@@ -7572,14 +7532,6 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags,
} else {
KASSERT(SLIST_EMPTY(&free),
("pmap_enter_pde: freed kernel page table page"));
-
- /*
- * Both pmap_remove_pde() and pmap_remove_ptes() will
- * leave the kernel page table page zero filled.
- */
- mt = PHYS_TO_VM_PAGE(*pde & PG_FRAME);
- if (pmap_insert_pt_page(pmap, mt, false, false))
- panic("pmap_enter_pde: trie insert failed");
}
}
@@ -7609,6 +7561,14 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags,
if (!pmap_pv_insert_pde(pmap, va, newpde, flags, lockp)) {
if (pdpg != NULL)
pmap_abort_ptp(pmap, va, pdpg);
+ else {
+ KASSERT(va >= VM_MAXUSER_ADDRESS &&
+ (*pde & (PG_PS | PG_V)) == PG_V,
+ ("pmap_enter_pde: invalid kernel PDE"));
+ mt = pmap_remove_pt_page(pmap, va);
+ KASSERT(mt != NULL,
+ ("pmap_enter_pde: missing kernel PTP"));
+ }
if (uwptpg != NULL) {
mt = pmap_remove_pt_page(pmap, va);
KASSERT(mt == uwptpg,
@@ -9518,7 +9478,7 @@ pmap_unmapdev(void *p, vm_size_t size)
va = (vm_offset_t)p;
/* If we gave a direct map region in pmap_mapdev, do nothing */
- if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS)
+ if (va >= kva_layout.dmap_low && va < kva_layout.dmap_high)
return;
offset = va & PAGE_MASK;
size = round_page(offset + size);
@@ -9547,7 +9507,7 @@ pmap_unmapdev(void *p, vm_size_t size)
* Tries to demote a 1GB page mapping.
*/
static bool
-pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va)
+pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va, vm_page_t m)
{
pdp_entry_t newpdpe, oldpdpe;
pd_entry_t *firstpde, newpde, *pde;
@@ -9564,12 +9524,19 @@ pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va)
oldpdpe = *pdpe;
KASSERT((oldpdpe & (PG_PS | PG_V)) == (PG_PS | PG_V),
("pmap_demote_pdpe: oldpdpe is missing PG_PS and/or PG_V"));
- pdpg = pmap_alloc_pt_page(pmap, va >> PDPSHIFT,
- VM_ALLOC_WIRED | VM_ALLOC_INTERRUPT);
- if (pdpg == NULL) {
- CTR2(KTR_PMAP, "pmap_demote_pdpe: failure for va %#lx"
- " in pmap %p", va, pmap);
- return (false);
+ if (m == NULL) {
+ pdpg = pmap_alloc_pt_page(pmap, va >> PDPSHIFT,
+ VM_ALLOC_WIRED);
+ if (pdpg == NULL) {
+ CTR2(KTR_PMAP,
+ "pmap_demote_pdpe: failure for va %#lx in pmap %p",
+ va, pmap);
+ return (false);
+ }
+ } else {
+ pdpg = m;
+ pdpg->pindex = va >> PDPSHIFT;
+ pmap_pt_page_count_adj(pmap, 1);
}
pdpgpa = VM_PAGE_TO_PHYS(pdpg);
firstpde = (pd_entry_t *)PHYS_TO_DMAP(pdpgpa);
@@ -9610,6 +9577,8 @@ pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va)
void
pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma)
{
+ if (m->md.pat_mode == ma)
+ return;
m->md.pat_mode = ma;
@@ -9629,6 +9598,9 @@ pmap_page_set_memattr_noflush(vm_page_t m, vm_memattr_t ma)
{
int error;
+ if (m->md.pat_mode == ma)
+ return;
+
m->md.pat_mode = ma;
if ((m->flags & PG_FICTITIOUS) != 0)
@@ -9685,7 +9657,7 @@ pmap_change_prot(vm_offset_t va, vm_size_t size, vm_prot_t prot)
int error;
/* Only supported within the kernel map. */
- if (va < VM_MIN_KERNEL_ADDRESS)
+ if (va < kva_layout.km_low)
return (EINVAL);
PMAP_LOCK(kernel_pmap);
@@ -9716,7 +9688,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
* Only supported on kernel virtual addresses, including the direct
* map but excluding the recursive map.
*/
- if (base < DMAP_MIN_ADDRESS)
+ if (base < kva_layout.dmap_low)
return (EINVAL);
/*
@@ -9739,7 +9711,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
pte_bits |= X86_PG_RW;
}
if ((prot & VM_PROT_EXECUTE) == 0 ||
- va < VM_MIN_KERNEL_ADDRESS) {
+ va < kva_layout.km_low) {
pde_bits |= pg_nx;
pte_bits |= pg_nx;
}
@@ -9779,7 +9751,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
tmpva += NBPDP;
continue;
}
- if (!pmap_demote_pdpe(kernel_pmap, pdpe, tmpva))
+ if (!pmap_demote_pdpe(kernel_pmap, pdpe, tmpva, NULL))
return (ENOMEM);
}
pde = pmap_pdpe_to_pde(pdpe, tmpva);
@@ -9835,7 +9807,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
pmap_pte_props(pdpe, pde_bits, pde_mask);
changed = true;
}
- if (tmpva >= VM_MIN_KERNEL_ADDRESS &&
+ if (tmpva >= kva_layout.km_low &&
(*pdpe & PG_PS_FRAME) < dmaplimit) {
if (pa_start == pa_end) {
/* Start physical address run. */
@@ -9865,7 +9837,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
pmap_pte_props(pde, pde_bits, pde_mask);
changed = true;
}
- if (tmpva >= VM_MIN_KERNEL_ADDRESS &&
+ if (tmpva >= kva_layout.km_low &&
(*pde & PG_PS_FRAME) < dmaplimit) {
if (pa_start == pa_end) {
/* Start physical address run. */
@@ -9893,7 +9865,7 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
pmap_pte_props(pte, pte_bits, pte_mask);
changed = true;
}
- if (tmpva >= VM_MIN_KERNEL_ADDRESS &&
+ if (tmpva >= kva_layout.km_low &&
(*pte & PG_FRAME) < dmaplimit) {
if (pa_start == pa_end) {
/* Start physical address run. */
@@ -9937,11 +9909,13 @@ pmap_change_props_locked(vm_offset_t va, vm_size_t size, vm_prot_t prot,
}
/*
- * Demotes any mapping within the direct map region that covers more than the
- * specified range of physical addresses. This range's size must be a power
- * of two and its starting address must be a multiple of its size. Since the
- * demotion does not change any attributes of the mapping, a TLB invalidation
- * is not mandatory. The caller may, however, request a TLB invalidation.
+ * Demotes any mapping within the direct map region that covers more
+ * than the specified range of physical addresses. This range's size
+ * must be a power of two and its starting address must be a multiple
+ * of its size, which means that any pdp from the mapping is fully
+ * covered by the range if len > NBPDP. Since the demotion does not
+ * change any attributes of the mapping, a TLB invalidation is not
+ * mandatory. The caller may, however, request a TLB invalidation.
*/
void
pmap_demote_DMAP(vm_paddr_t base, vm_size_t len, bool invalidate)
@@ -9949,38 +9923,67 @@ pmap_demote_DMAP(vm_paddr_t base, vm_size_t len, bool invalidate)
pdp_entry_t *pdpe;
pd_entry_t *pde;
vm_offset_t va;
- bool changed;
+ vm_page_t m, mpte;
+ bool changed, rv __diagused;
if (len == 0)
return;
KASSERT(powerof2(len), ("pmap_demote_DMAP: len is not a power of 2"));
KASSERT((base & (len - 1)) == 0,
("pmap_demote_DMAP: base is not a multiple of len"));
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "pmap_demote_DMAP");
+
if (len < NBPDP && base < dmaplimit) {
va = PHYS_TO_DMAP(base);
changed = false;
+
+ /*
+ * Assume that it is fine to sleep there.
+ * The only existing caller of pmap_demote_DMAP() is the
+ * x86_mr_split_dmap() function.
+ */
+ m = vm_page_alloc_noobj(VM_ALLOC_WIRED | VM_ALLOC_WAITOK);
+ if (len < NBPDR) {
+ mpte = vm_page_alloc_noobj(VM_ALLOC_WIRED |
+ VM_ALLOC_WAITOK);
+ } else
+ mpte = NULL;
+
PMAP_LOCK(kernel_pmap);
pdpe = pmap_pdpe(kernel_pmap, va);
if ((*pdpe & X86_PG_V) == 0)
panic("pmap_demote_DMAP: invalid PDPE");
if ((*pdpe & PG_PS) != 0) {
- if (!pmap_demote_pdpe(kernel_pmap, pdpe, va))
- panic("pmap_demote_DMAP: PDPE failed");
+ rv = pmap_demote_pdpe(kernel_pmap, pdpe, va, m);
+ KASSERT(rv, ("pmap_demote_DMAP: PDPE failed"));
changed = true;
+ m = NULL;
}
if (len < NBPDR) {
pde = pmap_pdpe_to_pde(pdpe, va);
if ((*pde & X86_PG_V) == 0)
panic("pmap_demote_DMAP: invalid PDE");
if ((*pde & PG_PS) != 0) {
- if (!pmap_demote_pde(kernel_pmap, pde, va))
- panic("pmap_demote_DMAP: PDE failed");
+ mpte->pindex = pmap_pde_pindex(va);
+ pmap_pt_page_count_adj(kernel_pmap, 1);
+ rv = pmap_demote_pde_mpte(kernel_pmap, pde, va,
+ NULL, mpte);
+ KASSERT(rv, ("pmap_demote_DMAP: PDE failed"));
changed = true;
+ mpte = NULL;
}
}
if (changed && invalidate)
pmap_invalidate_page(kernel_pmap, va);
PMAP_UNLOCK(kernel_pmap);
+ if (m != NULL) {
+ vm_page_unwire_noq(m);
+ vm_page_free(m);
+ }
+ if (mpte != NULL) {
+ vm_page_unwire_noq(mpte);
+ vm_page_free(mpte);
+ }
}
}
@@ -10210,17 +10213,9 @@ pmap_activate_sw(struct thread *td)
return;
}
cpuid = PCPU_GET(cpuid);
-#ifdef SMP
CPU_SET_ATOMIC(cpuid, &pmap->pm_active);
-#else
- CPU_SET(cpuid, &pmap->pm_active);
-#endif
pmap_activate_sw_mode(td, pmap, cpuid);
-#ifdef SMP
CPU_CLR_ATOMIC(cpuid, &oldpmap->pm_active);
-#else
- CPU_CLR(cpuid, &oldpmap->pm_active);
-#endif
}
void
@@ -10261,11 +10256,7 @@ pmap_activate_boot(pmap_t pmap)
MPASS(pmap != kernel_pmap);
cpuid = PCPU_GET(cpuid);
-#ifdef SMP
CPU_SET_ATOMIC(cpuid, &pmap->pm_active);
-#else
- CPU_SET(cpuid, &pmap->pm_active);
-#endif
PCPU_SET(curpmap, pmap);
if (pti) {
kcr3 = pmap->pm_cr3;
@@ -10629,19 +10620,28 @@ pmap_large_map_getptp(void)
static pdp_entry_t *
pmap_large_map_pdpe(vm_offset_t va)
{
+ pml4_entry_t *pml4;
vm_pindex_t pml4_idx;
vm_paddr_t mphys;
- pml4_idx = pmap_pml4e_index(va);
- KASSERT(LMSPML4I <= pml4_idx && pml4_idx < LMSPML4I + lm_ents,
- ("pmap_large_map_pdpe: va %#jx out of range idx %#jx LMSPML4I "
- "%#jx lm_ents %d",
- (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
- KASSERT((kernel_pml4[pml4_idx] & X86_PG_V) != 0,
- ("pmap_large_map_pdpe: invalid pml4 for va %#jx idx %#jx "
- "LMSPML4I %#jx lm_ents %d",
- (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
- mphys = kernel_pml4[pml4_idx] & PG_FRAME;
+ KASSERT(va >= kva_layout.lm_low && va < kva_layout.lm_low +
+ (vm_offset_t)NBPML4 * lm_ents, ("va %#lx not in large map", va));
+ if (la57) {
+ pml4 = pmap_pml4e(kernel_pmap, va);
+ mphys = *pml4 & PG_FRAME;
+ } else {
+ pml4_idx = pmap_pml4e_index(va);
+
+ KASSERT(LMSPML4I <= pml4_idx && pml4_idx < LMSPML4I + lm_ents,
+ ("pmap_large_map_pdpe: va %#jx out of range idx %#jx "
+ "LMSPML4I %#jx lm_ents %d",
+ (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
+ KASSERT((kernel_pml4[pml4_idx] & X86_PG_V) != 0,
+ ("pmap_large_map_pdpe: invalid pml4 for va %#jx idx %#jx "
+ "LMSPML4I %#jx lm_ents %d",
+ (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
+ mphys = kernel_pml4[pml4_idx] & PG_FRAME;
+ }
return ((pdp_entry_t *)PHYS_TO_DMAP(mphys) + pmap_pdpe_index(va));
}
@@ -10834,8 +10834,8 @@ pmap_large_unmap(void *svaa, vm_size_t len)
struct spglist spgf;
sva = (vm_offset_t)svaa;
- if (len == 0 || sva + len < sva || (sva >= DMAP_MIN_ADDRESS &&
- sva + len <= DMAP_MIN_ADDRESS + dmaplimit))
+ if (len == 0 || sva + len < sva || (sva >= kva_layout.dmap_low &&
+ sva + len < kva_layout.dmap_high))
return;
SLIST_INIT(&spgf);
@@ -11081,11 +11081,10 @@ pmap_large_map_wb(void *svap, vm_size_t len)
sva = (vm_offset_t)svap;
eva = sva + len;
pmap_large_map_wb_fence();
- if (sva >= DMAP_MIN_ADDRESS && eva <= DMAP_MIN_ADDRESS + dmaplimit) {
+ if (sva >= kva_layout.dmap_low && eva < kva_layout.dmap_high) {
pmap_large_map_flush_range(sva, len);
} else {
- KASSERT(sva >= LARGEMAP_MIN_ADDRESS &&
- eva <= LARGEMAP_MIN_ADDRESS + lm_ents * NBPML4,
+ KASSERT(sva >= kva_layout.lm_low && eva < kva_layout.lm_high,
("pmap_large_map_wb: not largemap %#lx %#lx", sva, len));
pmap_large_map_wb_large(sva, eva);
}
@@ -11126,8 +11125,8 @@ pmap_pti_init(void)
VM_OBJECT_WLOCK(pti_obj);
pml4_pg = pmap_pti_alloc_page();
pti_pml4 = (pml4_entry_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pml4_pg));
- for (va = VM_MIN_KERNEL_ADDRESS; va <= VM_MAX_KERNEL_ADDRESS &&
- va >= VM_MIN_KERNEL_ADDRESS && va > NBPML4; va += NBPML4) {
+ for (va = kva_layout.km_low; va <= kva_layout.km_high &&
+ va >= kva_layout.km_low && va > NBPML4; va += NBPML4) {
pdpe = pmap_pti_pdpe(va);
pmap_pti_wire_pte(pdpe);
}
@@ -11901,9 +11900,7 @@ sysctl_kmaps_dump(struct sbuf *sb, struct pmap_kernel_map_range *range,
mode, range->pdpes, range->pdes, range->ptes);
/* Reset to sentinel value. */
- range->sva = la57 ? KV5ADDR(NPML5EPG - 1, NPML4EPG - 1, NPDPEPG - 1,
- NPDEPG - 1, NPTEPG - 1) : KV4ADDR(NPML4EPG - 1, NPDPEPG - 1,
- NPDEPG - 1, NPTEPG - 1);
+ range->sva = kva_layout.kva_max;
}
/*
@@ -11944,12 +11941,18 @@ sysctl_kmaps_reinit(struct pmap_kernel_map_range *range, vm_offset_t va,
*/
static void
sysctl_kmaps_check(struct sbuf *sb, struct pmap_kernel_map_range *range,
- vm_offset_t va, pml4_entry_t pml4e, pdp_entry_t pdpe, pd_entry_t pde,
- pt_entry_t pte)
+ vm_offset_t va, pml5_entry_t pml5e, pml4_entry_t pml4e, pdp_entry_t pdpe,
+ pd_entry_t pde, pt_entry_t pte)
{
pt_entry_t attrs;
- attrs = pml4e & (X86_PG_RW | X86_PG_U | pg_nx);
+ if (la57) {
+ attrs = pml5e & (X86_PG_RW | X86_PG_U | pg_nx);
+ attrs |= pml4e & pg_nx;
+ attrs &= pg_nx | (pml4e & (X86_PG_RW | X86_PG_U));
+ } else {
+ attrs = pml4e & (X86_PG_RW | X86_PG_U | pg_nx);
+ }
attrs |= pdpe & pg_nx;
attrs &= pg_nx | (pdpe & (X86_PG_RW | X86_PG_U));
@@ -11982,13 +11985,15 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
{
struct pmap_kernel_map_range range;
struct sbuf sbuf, *sb;
+ pml5_entry_t pml5e;
pml4_entry_t pml4e;
pdp_entry_t *pdp, pdpe;
pd_entry_t *pd, pde;
pt_entry_t *pt, pte;
vm_offset_t sva;
vm_paddr_t pa;
- int error, i, j, k, l;
+ int error, j, k, l;
+ bool first;
error = sysctl_wire_old_buffer(req, 0);
if (error != 0)
@@ -11997,9 +12002,8 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
sbuf_new_for_sysctl(sb, NULL, PAGE_SIZE, req);
/* Sentinel value. */
- range.sva = la57 ? KV5ADDR(NPML5EPG - 1, NPML4EPG - 1, NPDPEPG - 1,
- NPDEPG - 1, NPTEPG - 1) : KV4ADDR(NPML4EPG - 1, NPDPEPG - 1,
- NPDEPG - 1, NPTEPG - 1);
+ range.sva = kva_layout.kva_max;
+ pml5e = 0; /* no UB for la48 */
/*
* Iterate over the kernel page tables without holding the kernel pmap
@@ -12008,41 +12012,50 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
* Within the large map, ensure that PDP and PD page addresses are
* valid before descending.
*/
- for (sva = 0, i = pmap_pml4e_index(sva); i < NPML4EPG; i++) {
- switch (i) {
- case PML4PML4I:
+ for (first = true, sva = 0; sva != 0 || first; first = false) {
+ if (sva == kva_layout.rec_pt)
sbuf_printf(sb, "\nRecursive map:\n");
- break;
- case DMPML4I:
+ else if (sva == kva_layout.dmap_low)
sbuf_printf(sb, "\nDirect map:\n");
- break;
#ifdef KASAN
- case KASANPML4I:
+ else if (sva == kva_layout.kasan_shadow_low)
sbuf_printf(sb, "\nKASAN shadow map:\n");
- break;
#endif
#ifdef KMSAN
- case KMSANSHADPML4I:
+ else if (sva == kva_layout.kmsan_shadow_low)
sbuf_printf(sb, "\nKMSAN shadow map:\n");
- break;
- case KMSANORIGPML4I:
+ else if (sva == kva_layout.kmsan_origin_low)
sbuf_printf(sb, "\nKMSAN origin map:\n");
- break;
#endif
- case KPML4BASE:
+ else if (sva == kva_layout.km_low)
sbuf_printf(sb, "\nKernel map:\n");
- break;
- case LMSPML4I:
+ else if (sva == kva_layout.lm_low)
sbuf_printf(sb, "\nLarge map:\n");
- break;
- }
/* Convert to canonical form. */
- if (sva == 1ul << 47)
- sva |= -1ul << 48;
+ if (la57) {
+ if (sva == 1ul << 56) {
+ sva |= -1ul << 57;
+ continue;
+ }
+ } else {
+ if (sva == 1ul << 47) {
+ sva |= -1ul << 48;
+ continue;
+ }
+ }
restart:
- pml4e = kernel_pml4[i];
+ if (la57) {
+ pml5e = *pmap_pml5e(kernel_pmap, sva);
+ if ((pml5e & X86_PG_V) == 0) {
+ sva = rounddown2(sva, NBPML5);
+ sysctl_kmaps_dump(sb, &range, sva);
+ sva += NBPML5;
+ continue;
+ }
+ }
+ pml4e = *pmap_pml4e(kernel_pmap, sva);
if ((pml4e & X86_PG_V) == 0) {
sva = rounddown2(sva, NBPML4);
sysctl_kmaps_dump(sb, &range, sva);
@@ -12063,8 +12076,8 @@ restart:
pa = pdpe & PG_FRAME;
if ((pdpe & PG_PS) != 0) {
sva = rounddown2(sva, NBPDP);
- sysctl_kmaps_check(sb, &range, sva, pml4e, pdpe,
- 0, 0);
+ sysctl_kmaps_check(sb, &range, sva, pml5e,
+ pml4e, pdpe, 0, 0);
range.pdpes++;
sva += NBPDP;
continue;
@@ -12076,6 +12089,7 @@ restart:
* freed. Validate the next-level address
* before descending.
*/
+ sva += NBPDP;
goto restart;
}
pd = (pd_entry_t *)PHYS_TO_DMAP(pa);
@@ -12092,7 +12106,7 @@ restart:
if ((pde & PG_PS) != 0) {
sva = rounddown2(sva, NBPDR);
sysctl_kmaps_check(sb, &range, sva,
- pml4e, pdpe, pde, 0);
+ pml5e, pml4e, pdpe, pde, 0);
range.pdes++;
sva += NBPDR;
continue;
@@ -12104,6 +12118,7 @@ restart:
* may be freed. Validate the
* next-level address before descending.
*/
+ sva += NBPDR;
goto restart;
}
pt = (pt_entry_t *)PHYS_TO_DMAP(pa);
@@ -12117,7 +12132,7 @@ restart:
continue;
}
sysctl_kmaps_check(sb, &range, sva,
- pml4e, pdpe, pde, pte);
+ pml5e, pml4e, pdpe, pde, pte);
range.ptes++;
}
}
diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S
index c95696bbe7ef..870cd255abb7 100644
--- a/sys/amd64/amd64/support.S
+++ b/sys/amd64/amd64/support.S
@@ -934,10 +934,7 @@ ENTRY(casueword32_nosmap)
ja fusufault
movl %esi,%eax /* old */
-#ifdef SMP
- lock
-#endif
- cmpxchgl %ecx,(%rdi) /* new = %ecx */
+ lock cmpxchgl %ecx,(%rdi) /* new = %ecx */
setne %cl
/*
@@ -971,10 +968,7 @@ ENTRY(casueword32_smap)
movl %esi,%eax /* old */
stac
-#ifdef SMP
- lock
-#endif
- cmpxchgl %ecx,(%rdi) /* new = %ecx */
+ lock cmpxchgl %ecx,(%rdi) /* new = %ecx */
clac
setne %cl
@@ -1014,10 +1008,7 @@ ENTRY(casueword_nosmap)
ja fusufault
movq %rsi,%rax /* old */
-#ifdef SMP
- lock
-#endif
- cmpxchgq %rcx,(%rdi) /* new = %rcx */
+ lock cmpxchgq %rcx,(%rdi) /* new = %rcx */
setne %cl
/*
@@ -1045,10 +1036,7 @@ ENTRY(casueword_smap)
movq %rsi,%rax /* old */
stac
-#ifdef SMP
- lock
-#endif
- cmpxchgq %rcx,(%rdi) /* new = %rcx */
+ lock cmpxchgq %rcx,(%rdi) /* new = %rcx */
clac
setne %cl
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index 09ac0a67dbef..f3469ed5e2bc 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -37,7 +37,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
/*
* AMD64 Trap and System call handling
*/
@@ -87,9 +86,7 @@ PMC_SOFT_DEFINE( , , page_fault, write);
#include <x86/mca.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
-#ifdef SMP
#include <machine/smp.h>
-#endif
#include <machine/stack.h>
#include <machine/trap.h>
#include <machine/tss.h>
@@ -769,7 +766,7 @@ trap_pfault(struct trapframe *frame, bool usermode, int *signo, int *ucode)
return (-1);
}
}
- if (eva >= VM_MIN_KERNEL_ADDRESS) {
+ if (eva >= kva_layout.km_low) {
/*
* Don't allow user-mode faults in kernel address space.
*/
@@ -900,11 +897,9 @@ trap_diag(struct trapframe *frame, vm_offset_t eva)
printf("\n\nFatal trap %d: %s while in %s mode\n", type,
type < nitems(trap_msg) ? trap_msg[type] : UNKNOWN,
TRAPF_USERMODE(frame) ? "user" : "kernel");
-#ifdef SMP
- /* two separate prints in case of a trap on an unmapped page */
- printf("cpuid = %d; ", PCPU_GET(cpuid));
- printf("apic id = %02x\n", PCPU_GET(apic_id));
-#endif
+ /* Print these separately in case pcpu accesses trap. */
+ printf("cpuid = %d; apic id = %02x\n", PCPU_GET(cpuid),
+ PCPU_GET(apic_id));
if (type == T_PAGEFLT) {
printf("fault virtual address = 0x%lx\n", eva);
printf("fault code = %s %s %s%s%s, %s\n",
@@ -1025,11 +1020,9 @@ dblfault_handler(struct trapframe *frame)
frame->tf_cs, frame->tf_ss, frame->tf_ds, frame->tf_es,
frame->tf_fs, frame->tf_gs,
rdmsr(MSR_FSBASE), rdmsr(MSR_GSBASE), rdmsr(MSR_KGSBASE));
-#ifdef SMP
- /* two separate prints in case of a trap on an unmapped page */
- printf("cpuid = %d; ", PCPU_GET(cpuid));
- printf("apic id = %02x\n", PCPU_GET(apic_id));
-#endif
+ /* Print these separately in case pcpu accesses trap. */
+ printf("cpuid = %d; apic id = %02x\n", PCPU_GET(cpuid),
+ PCPU_GET(apic_id));
panic("double fault");
}
diff --git a/sys/amd64/conf/MINIMALUP b/sys/amd64/conf/MINIMALUP
deleted file mode 100644
index 0dbddbe5b341..000000000000
--- a/sys/amd64/conf/MINIMALUP
+++ /dev/null
@@ -1,4 +0,0 @@
-include MINIMAL
-ident MINIMALUP
-nooptions SMP
-nooptions NUMA
diff --git a/sys/amd64/include/efi.h b/sys/amd64/include/efi.h
index b47c4aa27ac7..439f2f0b317d 100644
--- a/sys/amd64/include/efi.h
+++ b/sys/amd64/include/efi.h
@@ -53,6 +53,10 @@
#define EFI_TIME_OWNED() mtx_assert(&atrtc_time_lock, MA_OWNED)
#define EFI_RT_HANDLE_FAULTS_DEFAULT 1
+
+#define EFI_MAP_BOOTTYPE_ALLOWED(type) (((efi_map_regs >> (type)) & 1) != 0)
+
+extern uint32_t efi_map_regs;
#endif
struct efirt_callinfo {
diff --git a/sys/amd64/include/param.h b/sys/amd64/include/param.h
index 8db314fa034d..5a9c3162e14c 100644
--- a/sys/amd64/include/param.h
+++ b/sys/amd64/include/param.h
@@ -146,11 +146,10 @@
#define amd64_btop(x) ((unsigned long)(x) >> PAGE_SHIFT)
#define amd64_ptob(x) ((unsigned long)(x) << PAGE_SHIFT)
-#define INKERNEL(va) (((va) >= DMAP_MIN_ADDRESS && (va) < DMAP_MAX_ADDRESS) \
- || ((va) >= VM_MIN_KERNEL_ADDRESS && (va) < VM_MAX_KERNEL_ADDRESS))
+#define INKERNEL(va) \
+ (((va) >= kva_layout.dmap_low && (va) < kva_layout.dmap_high) || \
+ ((va) >= kva_layout.km_low && (va) < kva_layout.km_high))
-#ifdef SMP
#define SC_TABLESIZE 1024 /* Must be power of 2. */
-#endif
#endif /* !_AMD64_INCLUDE_PARAM_H_ */
diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h
index 7d3e91bcd9b9..e2f97442c10f 100644
--- a/sys/amd64/include/pmap.h
+++ b/sys/amd64/include/pmap.h
@@ -169,11 +169,12 @@
* the recursive page table map.
*/
#define NDMPML4E 8
+#define NDMPML5E 32
/*
- * These values control the layout of virtual memory. The starting address
- * of the direct map, which is controlled by DMPML4I, must be a multiple of
- * its size. (See the PHYS_TO_DMAP() and DMAP_TO_PHYS() macros.)
+ * These values control the layout of virtual memory. The starting
+ * address of the direct map is controlled by DMPML4I on LA48 and
+ * DMPML5I on LA57.
*
* Note: KPML4I is the index of the (single) level 4 page that maps
* the KVA that holds KERNBASE, while KPML4BASE is the index of the
@@ -191,6 +192,7 @@
#define KPML4BASE (NPML4EPG-NKPML4E) /* KVM at highest addresses */
#define DMPML4I rounddown(KPML4BASE-NDMPML4E, NDMPML4E) /* Below KVM */
+#define DMPML5I (NPML5EPG / 2 + 1)
#define KPML4I (NPML4EPG-1)
#define KPDPI (NPDPEPG-2) /* kernbase at -2GB */
@@ -200,9 +202,14 @@
#define KMSANSHADPML4I (KPML4BASE - NKMSANSHADPML4E)
#define KMSANORIGPML4I (DMPML4I - NKMSANORIGPML4E)
-/* Large map: index of the first and max last pml4 entry */
+/*
+ * Large map: index of the first and max last pml4/la48 and pml5/la57
+ * entry.
+ */
#define LMSPML4I (PML4PML4I + 1)
#define LMEPML4I (KASANPML4I - 1)
+#define LMSPML5I (DMPML5I + NDMPML5E)
+#define LMEPML5I (LMSPML5I + 32 - 1) /* 32 slots for large map */
/*
* XXX doesn't really belong here I guess...
@@ -548,6 +555,25 @@ pmap_pml5e_index(vm_offset_t va)
return ((va >> PML5SHIFT) & ((1ul << NPML5EPGSHIFT) - 1));
}
+struct kva_layout_s {
+ vm_offset_t kva_min;
+ vm_offset_t kva_max;
+ vm_offset_t dmap_low; /* DMAP_MIN_ADDRESS */
+ vm_offset_t dmap_high; /* DMAP_MAX_ADDRESS */
+ vm_offset_t lm_low; /* LARGEMAP_MIN_ADDRESS */
+ vm_offset_t lm_high; /* LARGEMAP_MAX_ADDRESS */
+ vm_offset_t km_low; /* VM_MIN_KERNEL_ADDRESS */
+ vm_offset_t km_high; /* VM_MAX_KERNEL_ADDRESS */
+ vm_offset_t rec_pt;
+ vm_offset_t kasan_shadow_low; /* KASAN_MIN_ADDRESS */
+ vm_offset_t kasan_shadow_high; /* KASAN_MAX_ADDRESS */
+ vm_offset_t kmsan_shadow_low; /* KMSAN_SHAD_MIN_ADDRESS */
+ vm_offset_t kmsan_shadow_high; /* KMSAN_SHAD_MAX_ADDRESS */
+ vm_offset_t kmsan_origin_low; /* KMSAN_ORIG_MIN_ADDRESS */
+ vm_offset_t kmsan_origin_high; /* KMSAN_ORIG_MAX_ADDRESS */
+};
+extern struct kva_layout_s kva_layout;
+
#endif /* !LOCORE */
#endif /* !_MACHINE_PMAP_H_ */
diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h
index 26eb227211da..bff92570ff82 100644
--- a/sys/amd64/include/smp.h
+++ b/sys/amd64/include/smp.h
@@ -13,8 +13,6 @@
#ifdef _KERNEL
-#ifdef SMP
-
#ifndef LOCORE
#include <x86/x86_smp.h>
@@ -39,7 +37,6 @@ void invlop_handler(void);
int start_all_aps(void);
#endif /* !LOCORE */
-#endif /* SMP */
#endif /* _KERNEL */
#endif /* _MACHINE_SMP_H_ */
diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h
index 0cd9bb4fa7a4..d2ac3c6648b2 100644
--- a/sys/amd64/include/vmparam.h
+++ b/sys/amd64/include/vmparam.h
@@ -163,6 +163,7 @@
* Virtual addresses of things. Derived from the page directory and
* page table indexes from pmap.h for precision.
*
+ * LA48:
* 0x0000000000000000 - 0x00007fffffffffff user map
* 0x0000800000000000 - 0xffff7fffffffffff does not exist (hole)
* 0xffff800000000000 - 0xffff804020100fff recursive page table (512GB slot)
@@ -175,32 +176,38 @@
* 0xfffffc0000000000 - 0xfffffdffffffffff 2TB KMSAN shadow map, optional
* 0xfffffe0000000000 - 0xffffffffffffffff 2TB kernel map
*
+ * LA57:
+ * 0x0000000000000000 - 0x00ffffffffffffff user map
+ * 0x0100000000000000 - 0xf0ffffffffffffff does not exist (hole)
+ * 0xff00000000000000 - 0xff00ffffffffffff recursive page table (2048TB slot)
+ * 0xff01000000000000 - 0xff20ffffffffffff direct map (32 x 2048TB slots)
+ * 0xff21000000000000 - 0xff40ffffffffffff large map
+ * 0xff41000000000000 - 0xffff7fffffffffff unused
+ * 0xffff800000000000 - 0xfffff5ffffffffff unused (start of kernel pml4 entry)
+ * 0xfffff60000000000 - 0xfffff7ffffffffff 2TB KMSAN origin map, optional
+ * 0xfffff78000000000 - 0xfffff7bfffffffff 512GB KASAN shadow map, optional
+ * 0xfffff80000000000 - 0xfffffbffffffffff 4TB unused
+ * 0xfffffc0000000000 - 0xfffffdffffffffff 2TB KMSAN shadow map, optional
+ * 0xfffffe0000000000 - 0xffffffffffffffff 2TB kernel map
+ *
* Within the kernel map:
*
* 0xfffffe0000000000 vm_page_array
* 0xffffffff80000000 KERNBASE
*/
-#define VM_MIN_KERNEL_ADDRESS KV4ADDR(KPML4BASE, 0, 0, 0)
-#define VM_MAX_KERNEL_ADDRESS KV4ADDR(KPML4BASE + NKPML4E - 1, \
- NPDPEPG-1, NPDEPG-1, NPTEPG-1)
-
-#define DMAP_MIN_ADDRESS KV4ADDR(DMPML4I, 0, 0, 0)
-#define DMAP_MAX_ADDRESS KV4ADDR(DMPML4I + NDMPML4E, 0, 0, 0)
-
-#define KASAN_MIN_ADDRESS KV4ADDR(KASANPML4I, 0, 0, 0)
-#define KASAN_MAX_ADDRESS KV4ADDR(KASANPML4I + NKASANPML4E, 0, 0, 0)
+#define VM_MIN_KERNEL_ADDRESS_LA48 KV4ADDR(KPML4BASE, 0, 0, 0)
+#define VM_MIN_KERNEL_ADDRESS kva_layout.km_low
+#define VM_MAX_KERNEL_ADDRESS kva_layout.km_high
-#define KMSAN_SHAD_MIN_ADDRESS KV4ADDR(KMSANSHADPML4I, 0, 0, 0)
-#define KMSAN_SHAD_MAX_ADDRESS KV4ADDR(KMSANSHADPML4I + NKMSANSHADPML4E, \
- 0, 0, 0)
+#define KASAN_MIN_ADDRESS (kva_layout.kasan_shadow_low)
+#define KASAN_MAX_ADDRESS (kva_layout.kasan_shadow_high)
-#define KMSAN_ORIG_MIN_ADDRESS KV4ADDR(KMSANORIGPML4I, 0, 0, 0)
-#define KMSAN_ORIG_MAX_ADDRESS KV4ADDR(KMSANORIGPML4I + NKMSANORIGPML4E, \
- 0, 0, 0)
+#define KMSAN_SHAD_MIN_ADDRESS (kva_layout.kmsan_shadow_low)
+#define KMSAN_SHAD_MAX_ADDRESS (kva_layout.kmsan_shadow_high)
-#define LARGEMAP_MIN_ADDRESS KV4ADDR(LMSPML4I, 0, 0, 0)
-#define LARGEMAP_MAX_ADDRESS KV4ADDR(LMEPML4I + 1, 0, 0, 0)
+#define KMSAN_ORIG_MIN_ADDRESS (kva_layout.kmsan_origin_low)
+#define KMSAN_ORIG_MAX_ADDRESS (kva_layout.kmsan_origin_high)
/*
* Formally kernel mapping starts at KERNBASE, but kernel linker
@@ -239,21 +246,21 @@
* vt fb startup needs to be reworked.
*/
#define PHYS_IN_DMAP(pa) (dmaplimit == 0 || (pa) < dmaplimit)
-#define VIRT_IN_DMAP(va) ((va) >= DMAP_MIN_ADDRESS && \
- (va) < (DMAP_MIN_ADDRESS + dmaplimit))
+#define VIRT_IN_DMAP(va) \
+ ((va) >= kva_layout.dmap_low && (va) < kva_layout.dmap_low + dmaplimit)
#define PMAP_HAS_DMAP 1
-#define PHYS_TO_DMAP(x) ({ \
+#define PHYS_TO_DMAP(x) __extension__ ({ \
KASSERT(PHYS_IN_DMAP(x), \
("physical address %#jx not covered by the DMAP", \
(uintmax_t)x)); \
- (x) | DMAP_MIN_ADDRESS; })
+ (x) + kva_layout.dmap_low; })
-#define DMAP_TO_PHYS(x) ({ \
+#define DMAP_TO_PHYS(x) __extension__ ({ \
KASSERT(VIRT_IN_DMAP(x), \
("virtual address %#jx not covered by the DMAP", \
(uintmax_t)x)); \
- (x) & ~DMAP_MIN_ADDRESS; })
+ (x) - kva_layout.dmap_low; })
/*
* amd64 maps the page array into KVA so that it can be more easily
@@ -274,7 +281,7 @@
*/
#ifndef VM_KMEM_SIZE_MAX
#define VM_KMEM_SIZE_MAX ((VM_MAX_KERNEL_ADDRESS - \
- VM_MIN_KERNEL_ADDRESS + 1) * 3 / 5)
+ kva_layout.km_low + 1) * 3 / 5)
#endif
/* initial pagein size of beginning of executable file */
diff --git a/sys/amd64/linux/linux_proto.h b/sys/amd64/linux/linux_proto.h
index 15e1dfc1a444..f1d9c96a78d7 100644
--- a/sys/amd64/linux/linux_proto.h
+++ b/sys/amd64/linux/linux_proto.h
@@ -914,10 +914,13 @@ struct linux_inotify_init_args {
syscallarg_t dummy;
};
struct linux_inotify_add_watch_args {
- syscallarg_t dummy;
+ char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)];
+ char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)];
+ char mask_l_[PADL_(uint32_t)]; uint32_t mask; char mask_r_[PADR_(uint32_t)];
};
struct linux_inotify_rm_watch_args {
- syscallarg_t dummy;
+ char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)];
+ char wd_l_[PADL_(uint32_t)]; uint32_t wd; char wd_r_[PADR_(uint32_t)];
};
struct linux_migrate_pages_args {
syscallarg_t dummy;
diff --git a/sys/amd64/linux/linux_sysent.c b/sys/amd64/linux/linux_sysent.c
index 8413d2723551..62b50cf68a32 100644
--- a/sys/amd64/linux/linux_sysent.c
+++ b/sys/amd64/linux/linux_sysent.c
@@ -268,8 +268,8 @@ struct sysent linux_sysent[] = {
{ .sy_narg = AS(linux_ioprio_set_args), .sy_call = (sy_call_t *)linux_ioprio_set, .sy_auevent = AUE_SETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 251 = linux_ioprio_set */
{ .sy_narg = AS(linux_ioprio_get_args), .sy_call = (sy_call_t *)linux_ioprio_get, .sy_auevent = AUE_GETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 252 = linux_ioprio_get */
{ .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_init, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 253 = linux_inotify_init */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_add_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 254 = linux_inotify_add_watch */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_rm_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 255 = linux_inotify_rm_watch */
+ { .sy_narg = AS(linux_inotify_add_watch_args), .sy_call = (sy_call_t *)linux_inotify_add_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 254 = linux_inotify_add_watch */
+ { .sy_narg = AS(linux_inotify_rm_watch_args), .sy_call = (sy_call_t *)linux_inotify_rm_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 255 = linux_inotify_rm_watch */
{ .sy_narg = 0, .sy_call = (sy_call_t *)linux_migrate_pages, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 256 = linux_migrate_pages */
{ .sy_narg = AS(linux_openat_args), .sy_call = (sy_call_t *)linux_openat, .sy_auevent = AUE_OPEN_RWTC, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 257 = linux_openat */
{ .sy_narg = AS(linux_mkdirat_args), .sy_call = (sy_call_t *)linux_mkdirat, .sy_auevent = AUE_MKDIRAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 258 = linux_mkdirat */
diff --git a/sys/amd64/linux/linux_systrace_args.c b/sys/amd64/linux/linux_systrace_args.c
index 20322f7a8660..1dc4de019080 100644
--- a/sys/amd64/linux/linux_systrace_args.c
+++ b/sys/amd64/linux/linux_systrace_args.c
@@ -1918,12 +1918,19 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
}
/* linux_inotify_add_watch */
case 254: {
- *n_args = 0;
+ struct linux_inotify_add_watch_args *p = params;
+ iarg[a++] = p->fd; /* l_int */
+ uarg[a++] = (intptr_t)p->pathname; /* const char * */
+ uarg[a++] = p->mask; /* uint32_t */
+ *n_args = 3;
break;
}
/* linux_inotify_rm_watch */
case 255: {
- *n_args = 0;
+ struct linux_inotify_rm_watch_args *p = params;
+ iarg[a++] = p->fd; /* l_int */
+ uarg[a++] = p->wd; /* uint32_t */
+ *n_args = 2;
break;
}
/* linux_migrate_pages */
@@ -5860,9 +5867,32 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_inotify_add_watch */
case 254:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
break;
/* linux_inotify_rm_watch */
case 255:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
break;
/* linux_migrate_pages */
case 256:
@@ -8353,8 +8383,14 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
case 253:
/* linux_inotify_add_watch */
case 254:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_inotify_rm_watch */
case 255:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_migrate_pages */
case 256:
/* linux_openat */
diff --git a/sys/amd64/linux/syscalls.master b/sys/amd64/linux/syscalls.master
index fd08c9b0279d..5e1394751ef6 100644
--- a/sys/amd64/linux/syscalls.master
+++ b/sys/amd64/linux/syscalls.master
@@ -1476,10 +1476,17 @@
int linux_inotify_init(void);
}
254 AUE_NULL STD {
- int linux_inotify_add_watch(void);
+ int linux_inotify_add_watch(
+ l_int fd,
+ const char *pathname,
+ uint32_t mask
+ );
}
255 AUE_NULL STD {
- int linux_inotify_rm_watch(void);
+ int linux_inotify_rm_watch(
+ l_int fd,
+ uint32_t wd
+ );
}
256 AUE_NULL STD {
int linux_migrate_pages(void);
diff --git a/sys/amd64/linux32/linux32_proto.h b/sys/amd64/linux32/linux32_proto.h
index ab0edd99df42..57a303271f1c 100644
--- a/sys/amd64/linux32/linux32_proto.h
+++ b/sys/amd64/linux32/linux32_proto.h
@@ -983,10 +983,13 @@ struct linux_inotify_init_args {
syscallarg_t dummy;
};
struct linux_inotify_add_watch_args {
- syscallarg_t dummy;
+ char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)];
+ char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)];
+ char mask_l_[PADL_(uint32_t)]; uint32_t mask; char mask_r_[PADR_(uint32_t)];
};
struct linux_inotify_rm_watch_args {
- syscallarg_t dummy;
+ char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)];
+ char wd_l_[PADL_(uint32_t)]; uint32_t wd; char wd_r_[PADR_(uint32_t)];
};
struct linux_migrate_pages_args {
syscallarg_t dummy;
@@ -1184,7 +1187,7 @@ struct linux_pipe2_args {
char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
};
struct linux_inotify_init1_args {
- syscallarg_t dummy;
+ char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
};
struct linux_preadv_args {
char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)];
diff --git a/sys/amd64/linux32/linux32_sysent.c b/sys/amd64/linux32/linux32_sysent.c
index add9844254ce..1bc8841badf3 100644
--- a/sys/amd64/linux32/linux32_sysent.c
+++ b/sys/amd64/linux32/linux32_sysent.c
@@ -307,8 +307,8 @@ struct sysent linux32_sysent[] = {
{ .sy_narg = AS(linux_ioprio_set_args), .sy_call = (sy_call_t *)linux_ioprio_set, .sy_auevent = AUE_SETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 289 = linux_ioprio_set */
{ .sy_narg = AS(linux_ioprio_get_args), .sy_call = (sy_call_t *)linux_ioprio_get, .sy_auevent = AUE_GETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 290 = linux_ioprio_get */
{ .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_init, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 291 = linux_inotify_init */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_add_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 292 = linux_inotify_add_watch */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_rm_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 293 = linux_inotify_rm_watch */
+ { .sy_narg = AS(linux_inotify_add_watch_args), .sy_call = (sy_call_t *)linux_inotify_add_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 292 = linux_inotify_add_watch */
+ { .sy_narg = AS(linux_inotify_rm_watch_args), .sy_call = (sy_call_t *)linux_inotify_rm_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 293 = linux_inotify_rm_watch */
{ .sy_narg = 0, .sy_call = (sy_call_t *)linux_migrate_pages, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 294 = linux_migrate_pages */
{ .sy_narg = AS(linux_openat_args), .sy_call = (sy_call_t *)linux_openat, .sy_auevent = AUE_OPEN_RWTC, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 295 = linux_openat */
{ .sy_narg = AS(linux_mkdirat_args), .sy_call = (sy_call_t *)linux_mkdirat, .sy_auevent = AUE_MKDIRAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 296 = linux_mkdirat */
@@ -347,7 +347,7 @@ struct sysent linux32_sysent[] = {
{ .sy_narg = AS(linux_epoll_create1_args), .sy_call = (sy_call_t *)linux_epoll_create1, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 329 = linux_epoll_create1 */
{ .sy_narg = AS(linux_dup3_args), .sy_call = (sy_call_t *)linux_dup3, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 330 = linux_dup3 */
{ .sy_narg = AS(linux_pipe2_args), .sy_call = (sy_call_t *)linux_pipe2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 331 = linux_pipe2 */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_init1, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 332 = linux_inotify_init1 */
+ { .sy_narg = AS(linux_inotify_init1_args), .sy_call = (sy_call_t *)linux_inotify_init1, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 332 = linux_inotify_init1 */
{ .sy_narg = AS(linux_preadv_args), .sy_call = (sy_call_t *)linux_preadv, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 333 = linux_preadv */
{ .sy_narg = AS(linux_pwritev_args), .sy_call = (sy_call_t *)linux_pwritev, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 334 = linux_pwritev */
{ .sy_narg = AS(linux_rt_tgsigqueueinfo_args), .sy_call = (sy_call_t *)linux_rt_tgsigqueueinfo, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 335 = linux_rt_tgsigqueueinfo */
diff --git a/sys/amd64/linux32/linux32_systrace_args.c b/sys/amd64/linux32/linux32_systrace_args.c
index 7793124e6935..cbd1641c2a34 100644
--- a/sys/amd64/linux32/linux32_systrace_args.c
+++ b/sys/amd64/linux32/linux32_systrace_args.c
@@ -2036,12 +2036,19 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
}
/* linux_inotify_add_watch */
case 292: {
- *n_args = 0;
+ struct linux_inotify_add_watch_args *p = params;
+ iarg[a++] = p->fd; /* l_int */
+ uarg[a++] = (intptr_t)p->pathname; /* const char * */
+ uarg[a++] = p->mask; /* uint32_t */
+ *n_args = 3;
break;
}
/* linux_inotify_rm_watch */
case 293: {
- *n_args = 0;
+ struct linux_inotify_rm_watch_args *p = params;
+ iarg[a++] = p->fd; /* l_int */
+ uarg[a++] = p->wd; /* uint32_t */
+ *n_args = 2;
break;
}
/* linux_migrate_pages */
@@ -2379,7 +2386,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
}
/* linux_inotify_init1 */
case 332: {
- *n_args = 0;
+ struct linux_inotify_init1_args *p = params;
+ iarg[a++] = p->flags; /* l_int */
+ *n_args = 1;
break;
}
/* linux_preadv */
@@ -6536,9 +6545,32 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_inotify_add_watch */
case 292:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
break;
/* linux_inotify_rm_watch */
case 293:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
break;
/* linux_migrate_pages */
case 294:
@@ -7116,6 +7148,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_inotify_init1 */
case 332:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ default:
+ break;
+ };
break;
/* linux_preadv */
case 333:
@@ -9809,8 +9848,14 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
case 291:
/* linux_inotify_add_watch */
case 292:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_inotify_rm_watch */
case 293:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_migrate_pages */
case 294:
/* linux_openat */
@@ -9982,6 +10027,9 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_inotify_init1 */
case 332:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_preadv */
case 333:
if (ndx == 0 || ndx == 1)
diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master
index 92d5f09c423f..7bd522a598e8 100644
--- a/sys/amd64/linux32/syscalls.master
+++ b/sys/amd64/linux32/syscalls.master
@@ -1589,10 +1589,17 @@
int linux_inotify_init(void);
}
292 AUE_NULL STD {
- int linux_inotify_add_watch(void);
+ int linux_inotify_add_watch(
+ l_int fd,
+ const char *pathname,
+ uint32_t mask
+ );
}
293 AUE_NULL STD {
- int linux_inotify_rm_watch(void);
+ int linux_inotify_rm_watch(
+ l_int fd,
+ uint32_t wd
+ );
}
; Linux 2.6.16:
294 AUE_NULL STD {
@@ -1860,7 +1867,9 @@
);
}
332 AUE_NULL STD {
- int linux_inotify_init1(void);
+ int linux_inotify_init1(
+ l_int flags
+ );
}
; Linux 2.6.30:
333 AUE_NULL STD {
diff --git a/sys/amd64/pt/pt.c b/sys/amd64/pt/pt.c
new file mode 100644
index 000000000000..c7b75767680a
--- /dev/null
+++ b/sys/amd64/pt/pt.c
@@ -0,0 +1,978 @@
+/*
+ * Copyright (c) 2025 Bojan Novković <bnovkov@freebsd.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * hwt(4) Intel Processor Trace (PT) backend
+ *
+ * Driver Design Overview
+ *
+ * - Since PT is configured on a per-core basis, the driver uses
+ * 'smp_rendezvous' to start and disable tracing on each target core.
+ * - PT-specific resources are stored in a 'struct pt_ctx' context structure for
+ * each traced CPU core or thread. Upon initialization, a ToPA configuration
+ * is generated for each 'pt_ctx' structure using the HWT tracing buffers.
+ * The HWT tracing buffer is split into 4K ToPA entries. Currently, each
+ * 4K ToPA entry is configured to trigger an interrupt after it is filled.
+ * - The PT driver uses the XSAVE/XRSTOR PT extensions to load and save all
+ * relevant PT registers. Every time a traced thread is switched
+ * out or in, its state will be saved to or loaded from its corresponding
+ * 'pt_ctx' context.
+ * - When tracing starts, the PT hardware will start writing data into the
+ * tracing buffer. When a TOPA_INT entry is filled, it will trigger an
+ * interrupt before continuing. The interrupt handler will then fetch the
+ * last valid tracing buffer offset and enqueue a HWT_RECORD_BUFFER record.
+ * The driver is currently configured to use the NMI interrupt line.
+ * - The userspace PT backend waits for incoming HWT_RECORD_BUFFER records
+ * and uses the offsets to decode data from the tracing buffer.
+ *
+ * Future improvements and limitations
+ *
+ * - We currently configure the PT hardware to trigger an interrupt whenever
+ * a 4K ToPA entry is filled. While this is fine when tracing smaller
+ * functions or infrequent code paths, this will generate too much interrupt
+ * traffic when tracing hotter functions. A proper solution for this issue
+ * should estimate the amount of data generated by the current configuration
+ * and use it to determine interrupt frequency.
+ *
+ * - Support for more tracing options and PT features.
+ *
+ */
+
+#include <sys/systm.h>
+#include <sys/hwt.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sdt.h>
+#include <sys/smp.h>
+#include <sys/taskqueue.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+#include <machine/atomic.h>
+#include <machine/cpufunc.h>
+#include <machine/fpu.h>
+#include <machine/smp.h>
+#include <machine/specialreg.h>
+
+#include <x86/apicvar.h>
+#include <x86/x86_var.h>
+
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_vm.h>
+#include <dev/hwt/hwt_backend.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_cpu.h>
+#include <dev/hwt/hwt_record.h>
+#include <dev/hwt/hwt_thread.h>
+
+#include <amd64/pt/pt.h>
+
+#ifdef PT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+#define PT_SUPPORTED_FLAGS \
+ (RTIT_CTL_MTCEN | RTIT_CTL_CR3FILTER | RTIT_CTL_DIS_TNT | \
+ RTIT_CTL_USER | RTIT_CTL_OS | RTIT_CTL_BRANCHEN)
+#define PT_XSAVE_MASK (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE)
+#define PT_XSTATE_BV (PT_XSAVE_MASK | XFEATURE_ENABLED_PT)
+#define PT_MAX_IP_RANGES 2
+
+#define PT_TOPA_MASK_PTRS 0x7f
+#define PT_TOPA_PAGE_MASK 0xffffff80
+#define PT_TOPA_PAGE_SHIFT 7
+
+#define CPUID_PT_LEAF 0x14
+
+MALLOC_DEFINE(M_PT, "pt", "Intel Processor Trace");
+
+SDT_PROVIDER_DEFINE(pt);
+SDT_PROBE_DEFINE(pt, , , topa__intr);
+
+TASKQUEUE_FAST_DEFINE_THREAD(pt);
+
+static void pt_send_buffer_record(void *arg, int pending __unused);
+static int pt_topa_intr(struct trapframe *tf);
+
+/*
+ * Intel Processor Trace XSAVE-managed state.
+ */
+struct pt_ext_area {
+ uint64_t rtit_ctl;
+ uint64_t rtit_output_base;
+ uint64_t rtit_output_mask_ptrs;
+ uint64_t rtit_status;
+ uint64_t rtit_cr3_match;
+ uint64_t rtit_addr0_a;
+ uint64_t rtit_addr0_b;
+ uint64_t rtit_addr1_a;
+ uint64_t rtit_addr1_b;
+};
+
+struct pt_buffer {
+ uint64_t *topa_hw; /* ToPA table entries. */
+ size_t size;
+ struct mtx lock; /* Lock for fields below. */
+ vm_offset_t offset;
+ uint64_t wrap_count;
+ int curpage;
+};
+
+struct pt_ctx {
+ int id;
+ struct pt_buffer buf; /* ToPA buffer metadata */
+ struct task task; /* ToPA buffer notification task */
+ struct hwt_context *hwt_ctx;
+ uint8_t *save_area; /* PT XSAVE area */
+};
+/* PT tracing contexts used for CPU mode. */
+static struct pt_ctx *pt_pcpu_ctx;
+
+enum pt_cpu_state {
+ PT_DISABLED = 0,
+ PT_STOPPED,
+ PT_ACTIVE
+};
+
+static struct pt_cpu {
+ struct pt_ctx *ctx; /* active PT tracing context */
+ enum pt_cpu_state state; /* used as part of trace stop protocol */
+} *pt_pcpu;
+
+/*
+ * PT-related CPUID bits.
+ */
+static struct pt_cpu_info {
+ uint32_t l0_eax;
+ uint32_t l0_ebx;
+ uint32_t l0_ecx;
+ uint32_t l1_eax;
+ uint32_t l1_ebx;
+ size_t xsave_area_size;
+ size_t xstate_hdr_offset;
+ size_t pt_xsave_offset;
+} pt_info __read_mostly;
+
+static bool initialized = false;
+static int cpu_mode_ctr = 0;
+
+static __inline enum pt_cpu_state
+pt_cpu_get_state(int cpu_id)
+{
+ return (atomic_load_int(&pt_pcpu[cpu_id].state));
+}
+
+static __inline void
+pt_cpu_set_state(int cpu_id, enum pt_cpu_state state)
+{
+ atomic_store_int(&pt_pcpu[cpu_id].state, state);
+}
+
+static __inline struct xstate_hdr *
+pt_ctx_get_xstate_hdr(struct pt_ctx *ctx)
+{
+ return ((struct xstate_hdr *)(ctx->save_area +
+ pt_info.xstate_hdr_offset));
+}
+
+
+static __inline struct pt_ext_area *
+pt_ctx_get_ext_area(struct pt_ctx *ctx)
+{
+ return ((struct pt_ext_area *)(ctx->save_area +
+ pt_info.pt_xsave_offset));
+}
+
+/*
+ * Updates current trace buffer offset from the
+ * ToPA MSRs. Records if the trace buffer wrapped.
+ */
+static __inline void
+pt_update_buffer(struct pt_buffer *buf)
+{
+ uint64_t reg;
+ int curpage;
+
+ /* Update buffer offset. */
+ reg = rdmsr(MSR_IA32_RTIT_OUTPUT_MASK_PTRS);
+ curpage = (reg & PT_TOPA_PAGE_MASK) >> PT_TOPA_PAGE_SHIFT;
+ mtx_lock_spin(&buf->lock);
+ /* Check if the output wrapped. */
+ if (buf->curpage > curpage)
+ buf->wrap_count++;
+ buf->curpage = curpage;
+ buf->offset = reg >> 32;
+ mtx_unlock_spin(&buf->lock);
+
+ dprintf("%s: wrap_cnt: %lu, curpage: %d, offset: %zu\n", __func__,
+ buf->wrap_count, buf->curpage, buf->offset);
+}
+
+static __inline void
+pt_fill_buffer_record(int id, struct pt_buffer *buf,
+ struct hwt_record_entry *rec)
+{
+ rec->record_type = HWT_RECORD_BUFFER;
+ rec->buf_id = id;
+ rec->curpage = buf->curpage;
+ rec->offset = buf->offset + (buf->wrap_count * buf->size);
+}
+
+/*
+ * Enables or disables tracing on curcpu
+ * using the XSAVE/XRSTOR PT extensions.
+ */
+static void
+pt_cpu_toggle_local(uint8_t *save_area, bool enable)
+{
+ u_long xcr0, cr0;
+ u_long xss;
+
+ cr0 = rcr0();
+ if (cr0 & CR0_TS)
+ clts();
+ xcr0 = rxcr(XCR0);
+ if ((xcr0 & PT_XSAVE_MASK) != PT_XSAVE_MASK)
+ load_xcr(XCR0, xcr0 | PT_XSAVE_MASK);
+ xss = rdmsr(MSR_IA32_XSS);
+ wrmsr(MSR_IA32_XSS, xss | XFEATURE_ENABLED_PT);
+
+ if (!enable) {
+ KASSERT((rdmsr(MSR_IA32_RTIT_CTL) & RTIT_CTL_TRACEEN) != 0,
+ ("%s: PT is disabled", __func__));
+ xsaves(save_area, XFEATURE_ENABLED_PT);
+ } else {
+ KASSERT((rdmsr(MSR_IA32_RTIT_CTL) & RTIT_CTL_TRACEEN) == 0,
+ ("%s: PT is enabled", __func__));
+ xrstors(save_area, XFEATURE_ENABLED_PT);
+ }
+ wrmsr(MSR_IA32_XSS, xss);
+ if ((xcr0 & PT_XSAVE_MASK) != PT_XSAVE_MASK)
+ load_xcr(XCR0, xcr0);
+ if (cr0 & CR0_TS)
+ load_cr0(cr0);
+}
+
+/*
+ * Starts PT tracing on 'curcpu'.
+ */
+static void
+pt_cpu_start(void *dummy)
+{
+ struct pt_cpu *cpu;
+
+ cpu = &pt_pcpu[curcpu];
+ MPASS(cpu->ctx != NULL);
+
+ dprintf("%s: curcpu %d\n", __func__, curcpu);
+ load_cr4(rcr4() | CR4_XSAVE);
+ wrmsr(MSR_IA32_RTIT_STATUS, 0);
+ pt_cpu_set_state(curcpu, PT_ACTIVE);
+ pt_cpu_toggle_local(cpu->ctx->save_area, true);
+}
+
+/*
+ * Stops PT tracing on 'curcpu'.
+ * Updates trace buffer offset to ensure
+ * any data generated between the last interrupt
+ * and the trace stop gets picked up by userspace.
+ */
+static void
+pt_cpu_stop(void *dummy)
+{
+ struct pt_cpu *cpu;
+ struct pt_ctx *ctx;
+
+ /* Shutdown may occur before PT gets properly configured. */
+ if (pt_cpu_get_state(curcpu) == PT_DISABLED)
+ return;
+
+ cpu = &pt_pcpu[curcpu];
+ ctx = cpu->ctx;
+ MPASS(ctx != NULL);
+ dprintf("%s: curcpu %d\n", __func__, curcpu);
+
+ pt_cpu_set_state(curcpu, PT_STOPPED);
+ pt_cpu_toggle_local(cpu->ctx->save_area, false);
+ pt_update_buffer(&ctx->buf);
+}
+
+/*
+ * Prepares the Table of Physical Addresses (ToPA) metadata for 'pt_ctx'.
+ * The HWT trace buffer is split into 4K ToPA table entries and used
+ * as a circular buffer, meaning that the last ToPA entry points to
+ * the first ToPA entry. Each entry is configured to raise an
+ * interrupt after being filled.
+ */
+static int
+pt_topa_prepare(struct pt_ctx *ctx, struct hwt_vm *vm)
+{
+ struct pt_buffer *buf;
+ size_t topa_size;
+ int i;
+
+ topa_size = TOPA_SIZE_4K;
+ buf = &ctx->buf;
+
+ KASSERT(buf->topa_hw == NULL,
+ ("%s: ToPA info already exists", __func__));
+ buf->topa_hw = mallocarray(vm->npages + 1, sizeof(uint64_t), M_PT,
+ M_ZERO | M_WAITOK);
+ dprintf("%s: ToPA virt addr %p\n", __func__, buf->topa_hw);
+ buf->size = vm->npages * PAGE_SIZE;
+ for (i = 0; i < vm->npages; i++) {
+ buf->topa_hw[i] = VM_PAGE_TO_PHYS(vm->pages[i]) | topa_size;
+ /*
+ * XXX: TOPA_INT should ideally be set according to
+ * expected amount of incoming trace data. Too few TOPA_INT
+ * entries will not trigger interrupts often enough when tracing
+ * smaller functions.
+ */
+ buf->topa_hw[i] |= TOPA_INT;
+ }
+ buf->topa_hw[vm->npages] = (uint64_t)vtophys(buf->topa_hw) | TOPA_END;
+
+ return (0);
+}
+
+/*
+ * Configures IP filtering for trace generation.
+ * A maximum of 2 ranges can be specified due to
+ * limitations imposed by the XSAVE/XRSTOR PT extensions.
+ */
+static int
+pt_configure_ranges(struct pt_ctx *ctx, struct pt_cpu_config *cfg)
+{
+ struct pt_ext_area *pt_ext;
+ int nranges_supp, n, error = 0;
+
+ pt_ext = pt_ctx_get_ext_area(ctx);
+ if (pt_info.l0_ebx & CPUPT_IPF) {
+ nranges_supp = (pt_info.l1_eax & CPUPT_NADDR_M) >>
+ CPUPT_NADDR_S;
+
+ if (nranges_supp > PT_IP_FILTER_MAX_RANGES)
+ nranges_supp = PT_IP_FILTER_MAX_RANGES;
+ n = cfg->nranges;
+ if (n > nranges_supp) {
+ printf("%s: %d IP filtering ranges requested, CPU "
+ "supports %d, truncating\n",
+ __func__, n, nranges_supp);
+ n = nranges_supp;
+ }
+
+ switch (n) {
+ case 2:
+ pt_ext->rtit_ctl |= (1UL << RTIT_CTL_ADDR_CFG_S(1));
+ pt_ext->rtit_addr1_a = cfg->ip_ranges[1].start;
+ pt_ext->rtit_addr1_b = cfg->ip_ranges[1].end;
+ case 1:
+ pt_ext->rtit_ctl |= (1UL << RTIT_CTL_ADDR_CFG_S(0));
+ pt_ext->rtit_addr0_a = cfg->ip_ranges[0].start;
+ pt_ext->rtit_addr0_b = cfg->ip_ranges[0].end;
+ break;
+ default:
+ error = (EINVAL);
+ break;
+ };
+ } else
+ error = (ENXIO);
+
+ return (error);
+}
+
+static int
+pt_init_ctx(struct pt_ctx *pt_ctx, struct hwt_vm *vm, int ctx_id)
+{
+
+ dprintf("%s: ctx id %d\n", __func__, ctx_id);
+
+ KASSERT(pt_ctx->buf.topa_hw == NULL,
+ ("%s: active ToPA buffer in context %p\n", __func__, pt_ctx));
+
+ memset(pt_ctx, 0, sizeof(struct pt_ctx));
+ mtx_init(&pt_ctx->buf.lock, "pttopa", NULL, MTX_SPIN);
+ pt_ctx->save_area = malloc_aligned(pt_info.xsave_area_size, 64,
+ M_PT, M_NOWAIT | M_ZERO);
+ if (pt_ctx->save_area == NULL)
+ return (ENOMEM);
+ dprintf("%s: preparing ToPA buffer\n", __func__);
+ if (pt_topa_prepare(pt_ctx, vm) != 0) {
+ dprintf("%s: failed to prepare ToPA buffer\n", __func__);
+ free(pt_ctx->save_area, M_PT);
+ return (ENOMEM);
+ }
+
+ pt_ctx->id = ctx_id;
+ TASK_INIT(&pt_ctx->task, 0, pt_send_buffer_record, pt_ctx);
+
+ return (0);
+}
+
+static void
+pt_deinit_ctx(struct pt_ctx *pt_ctx)
+{
+
+ if (pt_ctx->buf.topa_hw != NULL)
+ free(pt_ctx->buf.topa_hw, M_PT);
+ if (pt_ctx->save_area != NULL)
+ free(pt_ctx->save_area, M_PT);
+ memset(pt_ctx, 0, sizeof(*pt_ctx));
+ pt_ctx->buf.topa_hw = NULL;
+}
+
+/*
+ * HWT backend configuration method.
+ *
+ * Checks and translates the user-defined configuration to a
+ * set of PT tracing features. Uses the feature set to initialize
+ * the tracing context for the target CPU or thread.
+ */
+static int
+pt_backend_configure(struct hwt_context *ctx, int cpu_id, int thread_id)
+{
+ struct hwt_cpu *hwt_cpu;
+ struct hwt_thread *thr;
+ struct pt_ctx *pt_ctx;
+ struct pt_cpu_config *cfg;
+ struct pt_ext_area *pt_ext;
+ struct xstate_hdr *hdr;
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ cfg = (struct pt_cpu_config *)ctx->config;
+ pt_ctx = NULL;
+
+ /* Clear any flags we don't support yet. */
+ cfg->rtit_ctl &= PT_SUPPORTED_FLAGS;
+ if (cfg->rtit_ctl & RTIT_CTL_MTCEN) {
+ if ((pt_info.l0_ebx & CPUPT_MTC) == 0) {
+ printf("%s: CPU does not support generating MTC "
+ "packets\n", __func__);
+ return (ENXIO);
+ }
+ }
+
+ if (cfg->rtit_ctl & RTIT_CTL_CR3FILTER) {
+ if ((pt_info.l0_ebx & CPUPT_CR3) == 0) {
+ printf("%s: CPU does not support CR3 filtering\n",
+ __func__);
+ return (ENXIO);
+ }
+ }
+
+ if (cfg->rtit_ctl & RTIT_CTL_DIS_TNT) {
+ if ((pt_info.l0_ebx & CPUPT_DIS_TNT) == 0) {
+ printf("%s: CPU does not support TNT\n", __func__);
+ return (ENXIO);
+ }
+ }
+ /* TODO: support for more config bits. */
+
+ if (ctx->mode == HWT_MODE_CPU) {
+ TAILQ_FOREACH(hwt_cpu, &ctx->cpus, next) {
+ if (hwt_cpu->cpu_id != cpu_id)
+ continue;
+ pt_ctx = &pt_pcpu_ctx[cpu_id];
+ break;
+ }
+ } else {
+ TAILQ_FOREACH(thr, &ctx->threads, next) {
+ if (thr->thread_id != thread_id)
+ continue;
+ KASSERT(thr->private != NULL,
+ ("%s: hwt thread private"
+ " not set, thr %p",
+ __func__, thr));
+ pt_ctx = (struct pt_ctx *)thr->private;
+ break;
+ }
+ }
+ if (pt_ctx == NULL)
+ return (ENOENT);
+
+ dprintf("%s: preparing MSRs\n", __func__);
+ pt_ext = pt_ctx_get_ext_area(pt_ctx);
+ hdr = pt_ctx_get_xstate_hdr(pt_ctx);
+
+ pt_ext->rtit_ctl |= cfg->rtit_ctl;
+ if (cfg->nranges != 0) {
+ dprintf("%s: preparing IPF ranges\n", __func__);
+ if ((error = pt_configure_ranges(pt_ctx, cfg)) != 0)
+ return (error);
+ }
+ pt_ctx->hwt_ctx = ctx;
+ pt_ext->rtit_ctl |= RTIT_CTL_TOPA;
+ pt_ext->rtit_output_base = (uint64_t)vtophys(pt_ctx->buf.topa_hw);
+ pt_ext->rtit_output_mask_ptrs = PT_TOPA_MASK_PTRS;
+ hdr->xstate_bv = XFEATURE_ENABLED_PT;
+ hdr->xstate_xcomp_bv = XFEATURE_ENABLED_PT |
+ XSTATE_XCOMP_BV_COMPACT;
+ pt_ext->rtit_ctl |= RTIT_CTL_TRACEEN;
+ pt_pcpu[cpu_id].ctx = pt_ctx;
+ pt_cpu_set_state(cpu_id, PT_STOPPED);
+
+ return (0);
+}
+
+/*
+ * hwt backend trace start operation. CPU affine.
+ */
+static void
+pt_backend_enable(struct hwt_context *ctx, int cpu_id)
+{
+ if (ctx->mode == HWT_MODE_CPU)
+ return;
+
+ KASSERT(curcpu == cpu_id,
+ ("%s: attempting to start PT on another cpu", __func__));
+ pt_cpu_start(NULL);
+ CPU_SET(cpu_id, &ctx->cpu_map);
+}
+
+/*
+ * hwt backend trace stop operation. CPU affine.
+ */
+static void
+pt_backend_disable(struct hwt_context *ctx, int cpu_id)
+{
+ struct pt_cpu *cpu;
+
+ if (ctx->mode == HWT_MODE_CPU)
+ return;
+
+ KASSERT(curcpu == cpu_id,
+ ("%s: attempting to disable PT on another cpu", __func__));
+ pt_cpu_stop(NULL);
+ CPU_CLR(cpu_id, &ctx->cpu_map);
+ cpu = &pt_pcpu[cpu_id];
+ cpu->ctx = NULL;
+}
+
+/*
+ * hwt backend trace start operation for remote CPUs.
+ */
+static int
+pt_backend_enable_smp(struct hwt_context *ctx)
+{
+
+ dprintf("%s\n", __func__);
+ if (ctx->mode == HWT_MODE_CPU &&
+ atomic_swap_32(&cpu_mode_ctr, 1) != 0)
+ return (-1);
+
+ KASSERT(ctx->mode == HWT_MODE_CPU,
+ ("%s: should only be used for CPU mode", __func__));
+ smp_rendezvous_cpus(ctx->cpu_map, NULL, pt_cpu_start, NULL, NULL);
+
+ return (0);
+}
+
+/*
+ * hwt backend trace stop operation for remote CPUs.
+ */
+static int
+pt_backend_disable_smp(struct hwt_context *ctx)
+{
+
+ dprintf("%s\n", __func__);
+ if (ctx->mode == HWT_MODE_CPU &&
+ atomic_swap_32(&cpu_mode_ctr, 0) == 0)
+ return (-1);
+
+ if (CPU_EMPTY(&ctx->cpu_map)) {
+ dprintf("%s: empty cpu map\n", __func__);
+ return (-1);
+ }
+ smp_rendezvous_cpus(ctx->cpu_map, NULL, pt_cpu_stop, NULL, NULL);
+
+ return (0);
+}
+
+/*
+ * HWT backend initialization method.
+ *
+ * Installs the ToPA interrupt handler and initializes
+ * the tracing contexts used for HWT_MODE_CPU.
+ */
+static int
+pt_backend_init(struct hwt_context *ctx)
+{
+ struct hwt_cpu *hwt_cpu;
+ int error;
+
+ dprintf("%s\n", __func__);
+ if (ctx->mode == HWT_MODE_CPU) {
+ TAILQ_FOREACH(hwt_cpu, &ctx->cpus, next) {
+ error = pt_init_ctx(&pt_pcpu_ctx[hwt_cpu->cpu_id],
+ hwt_cpu->vm, hwt_cpu->cpu_id);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * HWT backend teardown method.
+ *
+ * Removes the ToPA interrupt handler, stops tracing on all active CPUs,
+ * and releases all previously allocated ToPA metadata.
+ */
+static int
+pt_backend_deinit(struct hwt_context *ctx)
+{
+ struct pt_ctx *pt_ctx;
+ struct hwt_thread *thr;
+ int cpu_id;
+
+ dprintf("%s\n", __func__);
+
+ pt_backend_disable_smp(ctx);
+ if (ctx->mode == HWT_MODE_THREAD) {
+ TAILQ_FOREACH(thr, &ctx->threads, next) {
+ KASSERT(thr->private != NULL,
+ ("%s: thr->private not set", __func__));
+ pt_ctx = (struct pt_ctx *)thr->private;
+ pt_deinit_ctx(pt_ctx);
+ }
+ } else {
+ CPU_FOREACH(cpu_id) {
+ if (!CPU_ISSET(cpu_id, &ctx->cpu_map))
+ continue;
+ if (pt_pcpu[cpu_id].ctx != NULL) {
+ KASSERT(pt_pcpu[cpu_id].ctx ==
+ &pt_pcpu_ctx[cpu_id],
+ ("%s: CPU mode tracing with non-cpu mode PT"
+ "context active",
+ __func__));
+ pt_pcpu[cpu_id].ctx = NULL;
+ }
+ pt_ctx = &pt_pcpu_ctx[cpu_id];
+ pt_deinit_ctx(pt_ctx);
+ memset(&pt_pcpu[cpu_id], 0, sizeof(struct pt_cpu));
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Fetches current offset into the tracing buffer.
+ */
+static int
+pt_backend_read(struct hwt_vm *vm, int *curpage, vm_offset_t *curpage_offset,
+ uint64_t *data)
+{
+ struct pt_buffer *buf;
+
+ if (vm->ctx->mode == HWT_MODE_THREAD)
+ buf = &((struct pt_ctx *)vm->thr->private)->buf;
+ else
+ buf = &pt_pcpu[vm->cpu->cpu_id].ctx->buf;
+ mtx_lock_spin(&buf->lock);
+ *curpage = buf->curpage;
+ *curpage_offset = buf->offset + (buf->wrap_count * vm->ctx->bufsize);
+ mtx_unlock_spin(&buf->lock);
+
+ return (0);
+}
+
+/*
+ * HWT thread creation hook.
+ * Allocates and associates a 'struct pt_ctx' for a given hwt thread.
+ */
+static int
+pt_backend_alloc_thread(struct hwt_thread *thr)
+{
+ struct pt_ctx *pt_ctx;
+ int error;
+
+ /* Omit M_WAITOK since this might get invoked a non-sleepable context */
+ pt_ctx = malloc(sizeof(*pt_ctx), M_PT, M_NOWAIT | M_ZERO);
+ if (pt_ctx == NULL)
+ return (ENOMEM);
+
+ error = pt_init_ctx(pt_ctx, thr->vm, thr->thread_id);
+ if (error)
+ return (error);
+
+ thr->private = pt_ctx;
+ return (0);
+}
+/*
+ * HWT thread teardown hook.
+ */
+static void
+pt_backend_free_thread(struct hwt_thread *thr)
+{
+ struct pt_ctx *ctx;
+
+ ctx = (struct pt_ctx *)thr->private;
+
+ pt_deinit_ctx(ctx);
+ free(ctx, M_PT);
+}
+
+static void
+pt_backend_dump(int cpu_id)
+{
+}
+
+static struct hwt_backend_ops pt_ops = {
+ .hwt_backend_init = pt_backend_init,
+ .hwt_backend_deinit = pt_backend_deinit,
+
+ .hwt_backend_configure = pt_backend_configure,
+
+ .hwt_backend_enable = pt_backend_enable,
+ .hwt_backend_disable = pt_backend_disable,
+
+#ifdef SMP
+ .hwt_backend_enable_smp = pt_backend_enable_smp,
+ .hwt_backend_disable_smp = pt_backend_disable_smp,
+#endif
+
+ .hwt_backend_read = pt_backend_read,
+ .hwt_backend_dump = pt_backend_dump,
+
+ .hwt_backend_thread_alloc = pt_backend_alloc_thread,
+ .hwt_backend_thread_free = pt_backend_free_thread,
+};
+
+static struct hwt_backend backend = {
+ .ops = &pt_ops,
+ .name = "pt",
+ .kva_req = 1,
+};
+
+/*
+ * Reads the latest valid trace buffer offset and enqueues
+ * a HWT_RECORD_BUFFER record.
+ * Used as a taskqueue routine from the ToPA interrupt handler.
+ */
+static void
+pt_send_buffer_record(void *arg, int pending __unused)
+{
+ struct hwt_record_entry record;
+ struct pt_ctx *ctx = (struct pt_ctx *)arg;
+
+ /* Prepare buffer record. */
+ mtx_lock_spin(&ctx->buf.lock);
+ pt_fill_buffer_record(ctx->id, &ctx->buf, &record);
+ mtx_unlock_spin(&ctx->buf.lock);
+ hwt_record_ctx(ctx->hwt_ctx, &record, M_ZERO | M_NOWAIT);
+}
+static void
+pt_topa_status_clear(void)
+{
+ uint64_t reg;
+
+ reg = rdmsr(MSR_IA_GLOBAL_STATUS_RESET);
+ reg &= ~GLOBAL_STATUS_FLAG_TRACETOPAPMI;
+ reg |= GLOBAL_STATUS_FLAG_TRACETOPAPMI;
+ wrmsr(MSR_IA_GLOBAL_STATUS_RESET, reg);
+}
+
+/*
+ * ToPA PMI handler.
+ *
+ * Invoked every time a ToPA entry marked with TOPA_INT is filled.
+ * Uses taskqueue to enqueue a buffer record for userspace.
+ * Re-enables the PC interrupt line as long as tracing is active.
+ */
+static int
+pt_topa_intr(struct trapframe *tf)
+{
+ struct pt_buffer *buf;
+ struct pt_ctx *ctx;
+ uint64_t reg;
+
+ SDT_PROBE0(pt, , , topa__intr);
+
+ if (pt_cpu_get_state(curcpu) != PT_ACTIVE) {
+ return (0);
+ }
+ reg = rdmsr(MSR_IA_GLOBAL_STATUS);
+ if ((reg & GLOBAL_STATUS_FLAG_TRACETOPAPMI) == 0) {
+ /* ACK spurious or leftover interrupt. */
+ pt_topa_status_clear();
+ return (1);
+ }
+
+ ctx = pt_pcpu[curcpu].ctx;
+ buf = &ctx->buf;
+ KASSERT(buf->topa_hw != NULL,
+ ("%s: ToPA PMI interrupt with invalid buffer", __func__));
+
+ pt_cpu_toggle_local(ctx->save_area, false);
+ pt_update_buffer(buf);
+ pt_topa_status_clear();
+ taskqueue_enqueue_flags(taskqueue_pt, &ctx->task,
+ TASKQUEUE_FAIL_IF_PENDING);
+
+ if (pt_cpu_get_state(curcpu) == PT_ACTIVE) {
+ pt_cpu_toggle_local(ctx->save_area, true);
+ lapic_reenable_pcint();
+ }
+ return (1);
+}
+
+/*
+ * Module initialization.
+ *
+ * Saves all PT-related cpuid info, registers itself as a HWT backend,
+ * and allocates metadata required to keep track of tracing operations
+ * on each CPU.
+ */
+static int
+pt_init(void)
+{
+ u_int cp[4];
+ int error;
+
+ dprintf("pt: Enumerating part 1\n");
+ cpuid_count(CPUID_PT_LEAF, 0, cp);
+ dprintf("pt: Maximum valid sub-leaf Index: %x\n", cp[0]);
+ dprintf("pt: ebx %x\n", cp[1]);
+ dprintf("pt: ecx %x\n", cp[2]);
+
+ pt_info.l0_eax = cp[0];
+ pt_info.l0_ebx = cp[1];
+ pt_info.l0_ecx = cp[2];
+
+ dprintf("pt: Enumerating part 2\n");
+ cpuid_count(CPUID_PT_LEAF, 1, cp);
+ dprintf("pt: eax %x\n", cp[0]);
+ dprintf("pt: ebx %x\n", cp[1]);
+
+ pt_info.l1_eax = cp[0];
+ pt_info.l1_ebx = cp[1];
+
+ error = hwt_backend_register(&backend);
+ if (error != 0) {
+ printf("pt: unable to register hwt backend, error %d\n", error);
+ return (error);
+ }
+ pt_pcpu = mallocarray(mp_ncpus, sizeof(struct pt_cpu), M_PT,
+ M_ZERO | M_WAITOK);
+ pt_pcpu_ctx = mallocarray(mp_ncpus, sizeof(struct pt_ctx), M_PT,
+ M_ZERO | M_WAITOK);
+
+ nmi_register_handler(pt_topa_intr);
+ if (!lapic_enable_pcint()) {
+ nmi_remove_handler(pt_topa_intr);
+ hwt_backend_unregister(&backend);
+ free(pt_pcpu, M_PT);
+ free(pt_pcpu_ctx, M_PT);
+ pt_pcpu = NULL;
+ pt_pcpu_ctx = NULL;
+ printf("pt: failed to setup interrupt line\n");
+ return (error);
+ }
+ initialized = true;
+
+ return (0);
+}
+
+/*
+ * Checks whether the CPU support Intel PT and
+ * initializes XSAVE area info.
+ *
+ * The driver relies on XSAVE/XRSTOR PT extensions,
+ * Table of Physical Addresses (ToPA) support, and
+ * support for multiple ToPA entries.
+ */
+static bool
+pt_supported(void)
+{
+ u_int cp[4];
+
+ if ((cpu_stdext_feature & CPUID_STDEXT_PROCTRACE) == 0) {
+ printf("pt: CPU does not support Intel Processor Trace\n");
+ return (false);
+ }
+ if ((cpu_feature2 & CPUID2_XSAVE) == 0) {
+ printf("pt: XSAVE is not supported\n");
+ return (false);
+ }
+ if (!xsave_extfeature_supported(XFEATURE_ENABLED_PT, true)) {
+ printf("pt: CPU does not support managing PT state using XSAVE\n");
+ return (false);
+ }
+ if (!xsave_extension_supported(CPUID_EXTSTATE_XSAVEC)) {
+ printf("pt: XSAVE compaction is not supported\n");
+ return (false);
+ }
+ if (!xsave_extension_supported(CPUID_EXTSTATE_XSAVES)) {
+ printf("pt: CPU does not support XSAVES/XRSTORS\n");
+ return (false);
+ }
+
+ /* Require ToPA support. */
+ cpuid_count(CPUID_PT_LEAF, 0, cp);
+ if ((cp[2] & CPUPT_TOPA) == 0) {
+ printf("pt: ToPA is not supported\n");
+ return (false);
+ }
+ if ((cp[2] & CPUPT_TOPA_MULTI) == 0) {
+ printf("pt: multiple ToPA outputs are not supported\n");
+ return (false);
+ }
+
+ pt_info.xstate_hdr_offset = xsave_area_hdr_offset();
+ pt_info.xsave_area_size = xsave_area_size(PT_XSTATE_BV, true, true);
+ pt_info.pt_xsave_offset = xsave_area_offset(PT_XSTATE_BV,
+ XFEATURE_ENABLED_PT, true, true);
+
+ return (true);
+}
+
+static void
+pt_deinit(void)
+{
+ if (!initialized)
+ return;
+ nmi_remove_handler(pt_topa_intr);
+ lapic_disable_pcint();
+ hwt_backend_unregister(&backend);
+ free(pt_pcpu, M_PT);
+ free(pt_pcpu_ctx, M_PT);
+ pt_pcpu = NULL;
+ initialized = false;
+}
+
+static int
+pt_modevent(module_t mod, int type, void *data)
+{
+ switch (type) {
+ case MOD_LOAD:
+ if (!pt_supported() || pt_init() != 0) {
+ return (ENXIO);
+ }
+ break;
+ case MOD_UNLOAD:
+ pt_deinit();
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static moduledata_t pt_mod = { "intel_pt", pt_modevent, NULL };
+
+DECLARE_MODULE(intel_pt, pt_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_DEPEND(intel_pt, hwt, 1, 1, 1);
+MODULE_VERSION(intel_pt, 1);
diff --git a/sys/amd64/pt/pt.h b/sys/amd64/pt/pt.h
new file mode 100644
index 000000000000..2423afdf22e9
--- /dev/null
+++ b/sys/amd64/pt/pt.h
@@ -0,0 +1,49 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Bojan Novković <bnovkov@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _AMD64_PT_PT_H_
+#define _AMD64_PT_PT_H_
+
+#include <sys/types.h>
+
+#include <x86/include/specialreg.h>
+
+#define PT_IP_FILTER_MAX_RANGES (2) /* Intel SDM Vol. 3C, 33-29 */
+
+struct pt_cpu_config {
+ uint64_t rtit_ctl;
+ register_t cr3_filter;
+ int nranges;
+ struct ipf_range {
+ vm_offset_t start;
+ vm_offset_t end;
+ } ip_ranges[PT_IP_FILTER_MAX_RANGES];
+ uint32_t mtc_freq;
+ uint32_t cyc_thresh;
+ uint32_t psb_freq;
+};
+#endif /* !_AMD64_PT_PT_H_ */
diff --git a/sys/amd64/vmm/intel/vmx_support.S b/sys/amd64/vmm/intel/vmx_support.S
index f393f160b101..130130b64541 100644
--- a/sys/amd64/vmm/intel/vmx_support.S
+++ b/sys/amd64/vmm/intel/vmx_support.S
@@ -32,12 +32,6 @@
#include "vmx_assym.h"
-#ifdef SMP
-#define LK lock ;
-#else
-#define LK
-#endif
-
/* Be friendly to DTrace FBT's prologue/epilogue pattern matching */
#define VENTER push %rbp ; mov %rsp,%rbp
#define VLEAVE pop %rbp
diff --git a/sys/arm/allwinner/aw_gpio.c b/sys/arm/allwinner/aw_gpio.c
index 18b47bab12d9..2061e38a155f 100644
--- a/sys/arm/allwinner/aw_gpio.c
+++ b/sys/arm/allwinner/aw_gpio.c
@@ -1154,10 +1154,6 @@ aw_gpio_attach(device_t dev)
aw_gpio_register_isrcs(sc);
intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev)));
- sc->sc_busdev = gpiobus_attach_bus(dev);
- if (sc->sc_busdev == NULL)
- goto fail;
-
/*
* Register as a pinctrl device
*/
@@ -1166,6 +1162,10 @@ aw_gpio_attach(device_t dev)
fdt_pinctrl_register(dev, "allwinner,pins");
fdt_pinctrl_configure_tree(dev);
+ sc->sc_busdev = gpiobus_attach_bus(dev);
+ if (sc->sc_busdev == NULL)
+ goto fail;
+
config_intrhook_oneshot(aw_gpio_enable_bank_supply, sc);
return (0);
diff --git a/sys/arm/allwinner/aw_mmc.c b/sys/arm/allwinner/aw_mmc.c
index 6bebf5e5fb5e..a8add957dc74 100644
--- a/sys/arm/allwinner/aw_mmc.c
+++ b/sys/arm/allwinner/aw_mmc.c
@@ -84,21 +84,26 @@
struct aw_mmc_conf {
uint32_t dma_xferlen;
+ uint32_t dma_desc_shift;
bool mask_data0;
bool can_calibrate;
bool new_timing;
+ bool zero_is_skip;
};
static const struct aw_mmc_conf a10_mmc_conf = {
.dma_xferlen = 0x2000,
+ .dma_desc_shift = 0,
};
static const struct aw_mmc_conf a13_mmc_conf = {
.dma_xferlen = 0x10000,
+ .dma_desc_shift = 0,
};
static const struct aw_mmc_conf a64_mmc_conf = {
.dma_xferlen = 0x10000,
+ .dma_desc_shift = 0,
.mask_data0 = true,
.can_calibrate = true,
.new_timing = true,
@@ -106,13 +111,24 @@ static const struct aw_mmc_conf a64_mmc_conf = {
static const struct aw_mmc_conf a64_emmc_conf = {
.dma_xferlen = 0x2000,
+ .dma_desc_shift = 0,
.can_calibrate = true,
};
+static const struct aw_mmc_conf d1_mmc_conf = {
+ .dma_xferlen = 0x1000,
+ .dma_desc_shift = 2,
+ .mask_data0 = true,
+ .can_calibrate = true,
+ .new_timing = true,
+ .zero_is_skip = true,
+};
+
static struct ofw_compat_data compat_data[] = {
{"allwinner,sun4i-a10-mmc", (uintptr_t)&a10_mmc_conf},
{"allwinner,sun5i-a13-mmc", (uintptr_t)&a13_mmc_conf},
{"allwinner,sun7i-a20-mmc", (uintptr_t)&a13_mmc_conf},
+ {"allwinner,sun20i-d1-mmc", (uintptr_t)&d1_mmc_conf},
{"allwinner,sun50i-a64-mmc", (uintptr_t)&a64_mmc_conf},
{"allwinner,sun50i-a64-emmc", (uintptr_t)&a64_emmc_conf},
{NULL, 0}
@@ -607,16 +623,18 @@ aw_dma_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
dma_desc = sc->aw_dma_desc;
for (i = 0; i < nsegs; i++) {
- if (segs[i].ds_len == sc->aw_mmc_conf->dma_xferlen)
+ if ((segs[i].ds_len == sc->aw_mmc_conf->dma_xferlen) &&
+ !sc->aw_mmc_conf->zero_is_skip)
dma_desc[i].buf_size = 0; /* Size of 0 indicate max len */
else
dma_desc[i].buf_size = segs[i].ds_len;
- dma_desc[i].buf_addr = segs[i].ds_addr;
+ dma_desc[i].buf_addr = segs[i].ds_addr >>
+ sc->aw_mmc_conf->dma_desc_shift;
dma_desc[i].config = AW_MMC_DMA_CONFIG_CH |
- AW_MMC_DMA_CONFIG_OWN | AW_MMC_DMA_CONFIG_DIC;
-
- dma_desc[i].next = sc->aw_dma_desc_phys +
- ((i + 1) * sizeof(struct aw_mmc_dma_desc));
+ AW_MMC_DMA_CONFIG_OWN | AW_MMC_DMA_CONFIG_DIC;
+ dma_desc[i].next = (sc->aw_dma_desc_phys +
+ (i + 1) * sizeof(struct aw_mmc_dma_desc)) >>
+ sc->aw_mmc_conf->dma_desc_shift;
}
dma_desc[0].config |= AW_MMC_DMA_CONFIG_FD;
@@ -678,7 +696,8 @@ aw_mmc_prepare_dma(struct aw_mmc_softc *sc)
AW_MMC_WRITE_4(sc, AW_MMC_IDIE, val);
/* Set DMA descritptor list address */
- AW_MMC_WRITE_4(sc, AW_MMC_DLBA, sc->aw_dma_desc_phys);
+ AW_MMC_WRITE_4(sc, AW_MMC_DLBA, sc->aw_dma_desc_phys >>
+ sc->aw_mmc_conf->dma_desc_shift);
/* FIFO trigger level */
AW_MMC_WRITE_4(sc, AW_MMC_FWLR, AW_MMC_DMA_FTRGLEVEL);
diff --git a/sys/arm/allwinner/aw_rtc.c b/sys/arm/allwinner/aw_rtc.c
index 9938601f17ce..4af57ab879e8 100644
--- a/sys/arm/allwinner/aw_rtc.c
+++ b/sys/arm/allwinner/aw_rtc.c
@@ -134,6 +134,7 @@ static struct ofw_compat_data compat_data[] = {
{ "allwinner,sun7i-a20-rtc", (uintptr_t) &a20_conf },
{ "allwinner,sun6i-a31-rtc", (uintptr_t) &a31_conf },
{ "allwinner,sun8i-h3-rtc", (uintptr_t) &h3_conf },
+ { "allwinner,sun20i-d1-rtc", (uintptr_t) &h3_conf },
{ "allwinner,sun50i-h5-rtc", (uintptr_t) &h3_conf },
{ "allwinner,sun50i-h6-rtc", (uintptr_t) &h3_conf },
{ NULL, 0 }
@@ -147,11 +148,13 @@ struct aw_rtc_softc {
static struct clk_fixed_def aw_rtc_osc32k = {
.clkdef.id = 0,
+ .clkdef.name = "osc32k",
.freq = 32768,
};
static struct clk_fixed_def aw_rtc_iosc = {
.clkdef.id = 2,
+ .clkdef.name = "iosc",
};
static void aw_rtc_install_clocks(struct aw_rtc_softc *sc, device_t dev);
@@ -250,23 +253,33 @@ aw_rtc_install_clocks(struct aw_rtc_softc *sc, device_t dev) {
int nclocks;
node = ofw_bus_get_node(dev);
- nclocks = ofw_bus_string_list_to_array(node, "clock-output-names", &clknames);
- /* No clocks to export */
- if (nclocks <= 0)
- return;
- if (nclocks != 3) {
- device_printf(dev, "Having only %d clocks instead of 3, aborting\n", nclocks);
+ /* Nothing to do. */
+ if (!OF_hasprop(node, "clocks"))
return;
+
+ /*
+ * If the device tree gives us specific output names for the clocks,
+ * use them.
+ */
+ nclocks = ofw_bus_string_list_to_array(node, "clock-output-names", &clknames);
+ if (nclocks > 0) {
+ if (nclocks != 3) {
+ device_printf(dev,
+ "Found %d clocks names instead of 3, aborting\n",
+ nclocks);
+ return;
+ }
+
+ aw_rtc_osc32k.clkdef.name = clknames[0];
+ aw_rtc_iosc.clkdef.name = clknames[2];
}
clkdom = clkdom_create(dev);
- aw_rtc_osc32k.clkdef.name = clknames[0];
if (clknode_fixed_register(clkdom, &aw_rtc_osc32k) != 0)
device_printf(dev, "Cannot register osc32k clock\n");
- aw_rtc_iosc.clkdef.name = clknames[2];
aw_rtc_iosc.freq = sc->conf->iosc_freq;
if (clknode_fixed_register(clkdom, &aw_rtc_iosc) != 0)
device_printf(dev, "Cannot register iosc clock\n");
diff --git a/sys/arm/arm/pmap-v6.c b/sys/arm/arm/pmap-v6.c
index 92eb0589f80b..78883296c5b7 100644
--- a/sys/arm/arm/pmap-v6.c
+++ b/sys/arm/arm/pmap-v6.c
@@ -5767,7 +5767,7 @@ pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma)
CTR5(KTR_PMAP, "%s: page %p - 0x%08X oma: %d, ma: %d", __func__, m,
VM_PAGE_TO_PHYS(m), oma, ma);
- if ((m->flags & PG_FICTITIOUS) != 0)
+ if (ma == oma || (m->flags & PG_FICTITIOUS) != 0)
return;
#if 0
/*
@@ -5784,22 +5784,20 @@ pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma)
* If page is not mapped by sf buffer, map the page
* transient and do invalidation.
*/
- if (ma != oma) {
- pa = VM_PAGE_TO_PHYS(m);
- sched_pin();
- pc = get_pcpu();
- cmap2_pte2p = pc->pc_cmap2_pte2p;
- mtx_lock(&pc->pc_cmap_lock);
- if (pte2_load(cmap2_pte2p) != 0)
- panic("%s: CMAP2 busy", __func__);
- pte2_store(cmap2_pte2p, PTE2_KERN_NG(pa, PTE2_AP_KRW,
- vm_memattr_to_pte2(ma)));
- dcache_wbinv_poc((vm_offset_t)pc->pc_cmap2_addr, pa, PAGE_SIZE);
- pte2_clear(cmap2_pte2p);
- tlb_flush((vm_offset_t)pc->pc_cmap2_addr);
- sched_unpin();
- mtx_unlock(&pc->pc_cmap_lock);
- }
+ pa = VM_PAGE_TO_PHYS(m);
+ sched_pin();
+ pc = get_pcpu();
+ cmap2_pte2p = pc->pc_cmap2_pte2p;
+ mtx_lock(&pc->pc_cmap_lock);
+ if (pte2_load(cmap2_pte2p) != 0)
+ panic("%s: CMAP2 busy", __func__);
+ pte2_store(cmap2_pte2p, PTE2_KERN_NG(pa, PTE2_AP_KRW,
+ vm_memattr_to_pte2(ma)));
+ dcache_wbinv_poc((vm_offset_t)pc->pc_cmap2_addr, pa, PAGE_SIZE);
+ pte2_clear(cmap2_pte2p);
+ tlb_flush((vm_offset_t)pc->pc_cmap2_addr);
+ sched_unpin();
+ mtx_unlock(&pc->pc_cmap_lock);
}
/*
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_gpio.c b/sys/arm/broadcom/bcm2835/bcm2835_gpio.c
index e4fc57b79ba5..48d1d2af5abc 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_gpio.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_gpio.c
@@ -837,12 +837,12 @@ bcm_gpio_attach(device_t dev)
}
sc->sc_gpio_npins = i;
bcm_gpio_sysctl_init(sc);
- sc->sc_busdev = gpiobus_attach_bus(dev);
- if (sc->sc_busdev == NULL)
- goto fail;
fdt_pinctrl_register(dev, "brcm,pins");
fdt_pinctrl_configure_tree(dev);
+ sc->sc_busdev = gpiobus_attach_bus(dev);
+ if (sc->sc_busdev == NULL)
+ goto fail;
return (0);
diff --git a/sys/arm/mv/mvebu_gpio.c b/sys/arm/mv/mvebu_gpio.c
index 681cf20f7f9f..7acdfff539dc 100644
--- a/sys/arm/mv/mvebu_gpio.c
+++ b/sys/arm/mv/mvebu_gpio.c
@@ -810,7 +810,6 @@ mvebu_gpio_attach(device_t dev)
return (ENXIO);
}
- bus_attach_children(dev);
return (0);
}
diff --git a/sys/arm/nvidia/as3722_gpio.c b/sys/arm/nvidia/as3722_gpio.c
index 073d057884c9..f7b3d4d43bab 100644
--- a/sys/arm/nvidia/as3722_gpio.c
+++ b/sys/arm/nvidia/as3722_gpio.c
@@ -544,7 +544,7 @@ as3722_gpio_attach(struct as3722_softc *sc, phandle_t node)
sc->gpio_pins = malloc(sizeof(struct as3722_gpio_pin *) *
sc->gpio_npins, M_AS3722_GPIO, M_WAITOK | M_ZERO);
- sc->gpio_busdev = gpiobus_attach_bus(sc->dev);
+ sc->gpio_busdev = gpiobus_add_bus(sc->dev);
if (sc->gpio_busdev == NULL)
return (ENXIO);
for (i = 0; i < sc->gpio_npins; i++) {
diff --git a/sys/arm/nvidia/tegra_gpio.c b/sys/arm/nvidia/tegra_gpio.c
index 16e1ef94d6a9..e37fd69a121e 100644
--- a/sys/arm/nvidia/tegra_gpio.c
+++ b/sys/arm/nvidia/tegra_gpio.c
@@ -824,7 +824,6 @@ tegra_gpio_attach(device_t dev)
return (ENXIO);
}
- bus_attach_children(dev);
return (0);
}
diff --git a/sys/arm64/apple/apple_pinctrl.c b/sys/arm64/apple/apple_pinctrl.c
index ec2dd5907024..ebaaccea1d99 100644
--- a/sys/arm64/apple/apple_pinctrl.c
+++ b/sys/arm64/apple/apple_pinctrl.c
@@ -161,22 +161,22 @@ apple_pinctrl_attach(device_t dev)
goto error;
}
+ fdt_pinctrl_register(dev, "pinmux");
+ fdt_pinctrl_configure_tree(dev);
+
+ if (OF_hasprop(node, "interrupt-controller")) {
+ sc->sc_irqs = mallocarray(sc->sc_ngpios,
+ sizeof(*sc->sc_irqs), M_DEVBUF, M_ZERO | M_WAITOK);
+ intr_pic_register(dev,
+ OF_xref_from_node(ofw_bus_get_node(dev)));
+ }
+
sc->sc_busdev = gpiobus_attach_bus(dev);
if (sc->sc_busdev == NULL) {
device_printf(dev, "failed to attach gpiobus\n");
goto error;
}
- fdt_pinctrl_register(dev, "pinmux");
- fdt_pinctrl_configure_tree(dev);
-
- if (!OF_hasprop(node, "interrupt-controller"))
- return (0);
-
- sc->sc_irqs = mallocarray(sc->sc_ngpios,
- sizeof(*sc->sc_irqs), M_DEVBUF, M_ZERO | M_WAITOK);
- intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev)));
-
return (0);
error:
mtx_destroy(&sc->sc_mtx);
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index d2e56a270f54..459cc8ebe505 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -497,7 +497,8 @@ static bool pmap_pv_insert_l3c(pmap_t pmap, vm_offset_t va, vm_page_t m,
struct rwlock **lockp);
static void pmap_remove_kernel_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t va);
static int pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva,
- pd_entry_t l1e, struct spglist *free, struct rwlock **lockp);
+ pd_entry_t l1e, bool demote_kl2e, struct spglist *free,
+ struct rwlock **lockp);
static int pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t sva,
pd_entry_t l2e, struct spglist *free, struct rwlock **lockp);
static bool pmap_remove_l3c(pmap_t pmap, pt_entry_t *l3p, vm_offset_t va,
@@ -3847,8 +3848,7 @@ pmap_remove_kernel_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t va)
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
ml3 = pmap_remove_pt_page(pmap, va);
- if (ml3 == NULL)
- panic("pmap_remove_kernel_l2: Missing pt page");
+ KASSERT(ml3 != NULL, ("pmap_remove_kernel_l2: missing pt page"));
ml3pa = VM_PAGE_TO_PHYS(ml3);
newl2 = PHYS_TO_PTE(ml3pa) | L2_TABLE;
@@ -3873,8 +3873,8 @@ pmap_remove_kernel_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t va)
* pmap_remove_l2: Do the things to unmap a level 2 superpage.
*/
static int
-pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva,
- pd_entry_t l1e, struct spglist *free, struct rwlock **lockp)
+pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva, pd_entry_t l1e,
+ bool demote_kl2e, struct spglist *free, struct rwlock **lockp)
{
struct md_page *pvh;
pt_entry_t old_l2;
@@ -3910,9 +3910,7 @@ pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva,
vm_page_aflag_clear(mt, PGA_WRITEABLE);
}
}
- if (pmap == kernel_pmap) {
- pmap_remove_kernel_l2(pmap, l2, sva);
- } else {
+ if (pmap != kernel_pmap) {
ml3 = pmap_remove_pt_page(pmap, sva);
if (ml3 != NULL) {
KASSERT(vm_page_any_valid(ml3),
@@ -3923,6 +3921,14 @@ pmap_remove_l2(pmap_t pmap, pt_entry_t *l2, vm_offset_t sva,
ml3->ref_count = 0;
pmap_add_delayed_free_list(ml3, free, false);
}
+ } else if (demote_kl2e) {
+ pmap_remove_kernel_l2(pmap, l2, sva);
+ } else {
+ ml3 = vm_radix_lookup(&pmap->pm_root, pmap_l2_pindex(sva));
+ if (vm_page_any_valid(ml3)) {
+ ml3->valid = 0;
+ pmap_zero_page(ml3);
+ }
}
return (pmap_unuse_pt(pmap, sva, l1e, free));
}
@@ -4232,7 +4238,7 @@ pmap_remove1(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, bool map_delete)
if ((l3_paddr & ATTR_DESCR_MASK) == L2_BLOCK) {
if (sva + L2_SIZE == va_next && eva >= va_next) {
pmap_remove_l2(pmap, l2, sva, pmap_load(l1),
- &free, &lock);
+ true, &free, &lock);
continue;
} else if (pmap_demote_l2_locked(pmap, l2, sva,
&lock) == NULL)
@@ -5703,6 +5709,9 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags,
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
KASSERT(ADDR_IS_CANONICAL(va),
("%s: Address not in canonical form: %lx", __func__, va));
+ KASSERT((flags & (PMAP_ENTER_NOREPLACE | PMAP_ENTER_NORECLAIM)) !=
+ PMAP_ENTER_NORECLAIM,
+ ("pmap_enter_l2: flags is missing PMAP_ENTER_NOREPLACE"));
if ((l2 = pmap_alloc_l2(pmap, va, &l2pg, (flags &
PMAP_ENTER_NOSLEEP) != 0 ? NULL : lockp)) == NULL) {
@@ -5747,33 +5756,51 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags,
}
}
SLIST_INIT(&free);
- if ((old_l2 & ATTR_DESCR_MASK) == L2_BLOCK)
+ if ((old_l2 & ATTR_DESCR_MASK) == L2_BLOCK) {
(void)pmap_remove_l2(pmap, l2, va,
- pmap_load(pmap_l1(pmap, va)), &free, lockp);
- else
+ pmap_load(pmap_l1(pmap, va)), false, &free, lockp);
+ } else {
+ if (ADDR_IS_KERNEL(va)) {
+ /*
+ * Try to save the ptp in the trie
+ * before any changes to mappings are
+ * made. Abort on failure.
+ */
+ mt = PTE_TO_VM_PAGE(old_l2);
+ if (pmap_insert_pt_page(pmap, mt, false,
+ false)) {
+ CTR1(KTR_PMAP,
+ "pmap_enter_l2: cannot ins kern ptp va %#lx",
+ va);
+ return (KERN_RESOURCE_SHORTAGE);
+ }
+ /*
+ * Both pmap_remove_l2() and
+ * pmap_remove_l3_range() will zero fill
+ * the L3 kernel page table page.
+ */
+ }
pmap_remove_l3_range(pmap, old_l2, va, va + L2_SIZE,
&free, lockp);
+ if (ADDR_IS_KERNEL(va)) {
+ /*
+ * The TLB could have an intermediate
+ * entry for the L3 kernel page table
+ * page, so request an invalidation at
+ * all levels after clearing the
+ * L2_TABLE entry.
+ */
+ pmap_clear(l2);
+ pmap_s1_invalidate_page(pmap, va, false);
+ }
+ }
+ KASSERT(pmap_load(l2) == 0,
+ ("pmap_enter_l2: non-zero L2 entry %p", l2));
if (!ADDR_IS_KERNEL(va)) {
vm_page_free_pages_toq(&free, true);
- KASSERT(pmap_load(l2) == 0,
- ("pmap_enter_l2: non-zero L2 entry %p", l2));
} else {
KASSERT(SLIST_EMPTY(&free),
("pmap_enter_l2: freed kernel page table page"));
-
- /*
- * Both pmap_remove_l2() and pmap_remove_l3_range()
- * will leave the kernel page table page zero filled.
- * Nonetheless, the TLB could have an intermediate
- * entry for the kernel page table page, so request
- * an invalidation at all levels after clearing
- * the L2_TABLE entry.
- */
- mt = PTE_TO_VM_PAGE(pmap_load(l2));
- if (pmap_insert_pt_page(pmap, mt, false, false))
- panic("pmap_enter_l2: trie insert failed");
- pmap_clear(l2);
- pmap_s1_invalidate_page(pmap, va, false);
}
}
@@ -5804,6 +5831,15 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags,
if (!pmap_pv_insert_l2(pmap, va, new_l2, flags, lockp)) {
if (l2pg != NULL)
pmap_abort_ptp(pmap, va, l2pg);
+ else {
+ KASSERT(ADDR_IS_KERNEL(va) &&
+ (pmap_load(l2) & ATTR_DESCR_MASK) ==
+ L2_TABLE,
+ ("pmap_enter_l2: invalid kernel L2E"));
+ mt = pmap_remove_pt_page(pmap, va);
+ KASSERT(mt != NULL,
+ ("pmap_enter_l2: missing kernel PTP"));
+ }
if (uwptpg != NULL) {
mt = pmap_remove_pt_page(pmap, va);
KASSERT(mt == uwptpg,
@@ -8045,6 +8081,8 @@ pmap_unmapbios(void *p, vm_size_t size)
void
pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma)
{
+ if (m->md.pv_memattr == ma)
+ return;
m->md.pv_memattr = ma;
@@ -8424,8 +8462,8 @@ pmap_demote_l2_abort(pmap_t pmap, vm_offset_t va, pt_entry_t *l2,
struct spglist free;
SLIST_INIT(&free);
- (void)pmap_remove_l2(pmap, l2, va, pmap_load(pmap_l1(pmap, va)), &free,
- lockp);
+ (void)pmap_remove_l2(pmap, l2, va, pmap_load(pmap_l1(pmap, va)), true,
+ &free, lockp);
vm_page_free_pages_toq(&free, true);
}
diff --git a/sys/arm64/broadcom/genet/if_genet.c b/sys/arm64/broadcom/genet/if_genet.c
index 0602f076b257..182b5582fb7c 100644
--- a/sys/arm64/broadcom/genet/if_genet.c
+++ b/sys/arm64/broadcom/genet/if_genet.c
@@ -349,7 +349,7 @@ gen_attach(device_t dev)
}
/* If address was not found, create one based on the hostid and name. */
- if (eaddr_found == 0)
+ if (!eaddr_found)
ether_gen_addr(sc->ifp, &eaddr);
/* Attach ethernet interface */
ether_ifattach(sc->ifp, eaddr.octet);
@@ -653,7 +653,7 @@ gen_bus_dma_teardown(struct gen_softc *sc)
error);
}
- if (sc->tx_buf_tag != NULL) {
+ if (sc->rx_buf_tag != NULL) {
for (i = 0; i < RX_DESC_COUNT; i++) {
error = bus_dmamap_destroy(sc->rx_buf_tag,
sc->rx_ring_ent[i].map);
diff --git a/sys/arm64/linux/linux_proto.h b/sys/arm64/linux/linux_proto.h
index ae3d8569df58..82f57f77ffae 100644
--- a/sys/arm64/linux/linux_proto.h
+++ b/sys/arm64/linux/linux_proto.h
@@ -141,10 +141,13 @@ struct linux_inotify_init1_args {
char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
};
struct linux_inotify_add_watch_args {
- syscallarg_t dummy;
+ char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)];
+ char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)];
+ char mask_l_[PADL_(uint32_t)]; uint32_t mask; char mask_r_[PADR_(uint32_t)];
};
struct linux_inotify_rm_watch_args {
- syscallarg_t dummy;
+ char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)];
+ char wd_l_[PADL_(uint32_t)]; uint32_t wd; char wd_r_[PADR_(uint32_t)];
};
struct linux_ioctl_args {
char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)];
diff --git a/sys/arm64/linux/linux_sysent.c b/sys/arm64/linux/linux_sysent.c
index 722ada465730..e54a76cfd55e 100644
--- a/sys/arm64/linux/linux_sysent.c
+++ b/sys/arm64/linux/linux_sysent.c
@@ -41,8 +41,8 @@ struct sysent linux_sysent[] = {
{ .sy_narg = AS(linux_dup3_args), .sy_call = (sy_call_t *)linux_dup3, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 24 = linux_dup3 */
{ .sy_narg = AS(linux_fcntl_args), .sy_call = (sy_call_t *)linux_fcntl, .sy_auevent = AUE_FCNTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 25 = linux_fcntl */
{ .sy_narg = AS(linux_inotify_init1_args), .sy_call = (sy_call_t *)linux_inotify_init1, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 26 = linux_inotify_init1 */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_add_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 27 = linux_inotify_add_watch */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_rm_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 28 = linux_inotify_rm_watch */
+ { .sy_narg = AS(linux_inotify_add_watch_args), .sy_call = (sy_call_t *)linux_inotify_add_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 27 = linux_inotify_add_watch */
+ { .sy_narg = AS(linux_inotify_rm_watch_args), .sy_call = (sy_call_t *)linux_inotify_rm_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 28 = linux_inotify_rm_watch */
{ .sy_narg = AS(linux_ioctl_args), .sy_call = (sy_call_t *)linux_ioctl, .sy_auevent = AUE_IOCTL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 29 = linux_ioctl */
{ .sy_narg = AS(linux_ioprio_set_args), .sy_call = (sy_call_t *)linux_ioprio_set, .sy_auevent = AUE_SETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 30 = linux_ioprio_set */
{ .sy_narg = AS(linux_ioprio_get_args), .sy_call = (sy_call_t *)linux_ioprio_get, .sy_auevent = AUE_GETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 31 = linux_ioprio_get */
diff --git a/sys/arm64/linux/linux_systrace_args.c b/sys/arm64/linux/linux_systrace_args.c
index 54e4dd82355d..1b946a9406a5 100644
--- a/sys/arm64/linux/linux_systrace_args.c
+++ b/sys/arm64/linux/linux_systrace_args.c
@@ -210,12 +210,19 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
}
/* linux_inotify_add_watch */
case 27: {
- *n_args = 0;
+ struct linux_inotify_add_watch_args *p = params;
+ iarg[a++] = p->fd; /* l_int */
+ uarg[a++] = (intptr_t)p->pathname; /* const char * */
+ uarg[a++] = p->mask; /* uint32_t */
+ *n_args = 3;
break;
}
/* linux_inotify_rm_watch */
case 28: {
- *n_args = 0;
+ struct linux_inotify_rm_watch_args *p = params;
+ iarg[a++] = p->fd; /* l_int */
+ uarg[a++] = p->wd; /* uint32_t */
+ *n_args = 2;
break;
}
/* linux_ioctl */
@@ -2780,9 +2787,32 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_inotify_add_watch */
case 27:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
break;
/* linux_inotify_rm_watch */
case 28:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
break;
/* linux_ioctl */
case 29:
@@ -6455,8 +6485,14 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_inotify_add_watch */
case 27:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_inotify_rm_watch */
case 28:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_ioctl */
case 29:
if (ndx == 0 || ndx == 1)
diff --git a/sys/arm64/linux/syscalls.master b/sys/arm64/linux/syscalls.master
index 79c04c398e00..2babdcaf03bf 100644
--- a/sys/arm64/linux/syscalls.master
+++ b/sys/arm64/linux/syscalls.master
@@ -170,10 +170,17 @@
);
}
27 AUE_NULL STD {
- int linux_inotify_add_watch(void);
+ int linux_inotify_add_watch(
+ l_int fd,
+ const char *pathname,
+ uint32_t mask
+ );
}
28 AUE_NULL STD {
- int linux_inotify_rm_watch(void);
+ int linux_inotify_rm_watch(
+ l_int fd,
+ uint32_t wd
+ );
}
29 AUE_IOCTL STD {
int linux_ioctl(
diff --git a/sys/arm64/nvidia/tegra210/max77620_gpio.c b/sys/arm64/nvidia/tegra210/max77620_gpio.c
index 8dcf98099dac..5d91e23324c7 100644
--- a/sys/arm64/nvidia/tegra210/max77620_gpio.c
+++ b/sys/arm64/nvidia/tegra210/max77620_gpio.c
@@ -672,7 +672,7 @@ max77620_gpio_attach(struct max77620_softc *sc, phandle_t node)
sx_init(&sc->gpio_lock, "MAX77620 GPIO lock");
- sc->gpio_busdev = gpiobus_attach_bus(sc->dev);
+ sc->gpio_busdev = gpiobus_add_bus(sc->dev);
if (sc->gpio_busdev == NULL)
return (ENXIO);
diff --git a/sys/arm64/rockchip/rk_gpio.c b/sys/arm64/rockchip/rk_gpio.c
index a86392f16624..847bc7394dd0 100644
--- a/sys/arm64/rockchip/rk_gpio.c
+++ b/sys/arm64/rockchip/rk_gpio.c
@@ -362,12 +362,6 @@ rk_gpio_attach(device_t dev)
return (ENXIO);
}
- sc->sc_busdev = gpiobus_attach_bus(dev);
- if (sc->sc_busdev == NULL) {
- rk_gpio_detach(dev);
- return (ENXIO);
- }
-
/* Set the cached value to unknown */
for (i = 0; i < RK_GPIO_MAX_PINS; i++)
sc->pin_cached[i].is_gpio = 2;
@@ -377,6 +371,12 @@ rk_gpio_attach(device_t dev)
sc->swporta_ddr = rk_gpio_read_4(sc, RK_GPIO_SWPORTA_DDR);
RK_GPIO_UNLOCK(sc);
+ sc->sc_busdev = gpiobus_attach_bus(dev);
+ if (sc->sc_busdev == NULL) {
+ rk_gpio_detach(dev);
+ return (ENXIO);
+ }
+
return (0);
}
diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h
index 0f110d5f9ddd..9381396f247c 100644
--- a/sys/bsm/audit_kevents.h
+++ b/sys/bsm/audit_kevents.h
@@ -663,6 +663,7 @@
#define AUE_FSPACECTL 43269 /* FreeBSD-specific. */
#define AUE_TIMERFD 43270 /* FreeBSD/Linux. */
#define AUE_SETCRED 43271 /* FreeBSD-specific. */
+#define AUE_INOTIFY 43272 /* FreeBSD/Linux. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index ae7cf14c8f8e..1facab47473c 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -1359,10 +1359,7 @@ adaasync(void *callback_arg, uint32_t code,
case AC_GETDEV_CHANGED:
{
softc = (struct ada_softc *)periph->softc;
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, periph->path);
/*
* Update our information based on the new Identify data.
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 833df6cfb99b..730656684e2a 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -767,27 +767,28 @@ camperiphfree(struct cam_periph *periph)
CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph destroyed\n"));
if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) {
- union ccb ccb;
- void *arg;
-
- memset(&ccb, 0, sizeof(ccb));
switch (periph->deferred_ac) {
- case AC_FOUND_DEVICE:
- ccb.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
- xpt_action(&ccb);
- arg = &ccb;
+ case AC_FOUND_DEVICE: {
+ struct ccb_getdev cgd;
+
+ xpt_gdev_type(&cgd, periph->path);
+ periph->deferred_callback(NULL, periph->deferred_ac,
+ periph->path, &cgd);
break;
- case AC_PATH_REGISTERED:
- xpt_path_inq(&ccb.cpi, periph->path);
- arg = &ccb;
+ }
+ case AC_PATH_REGISTERED: {
+ struct ccb_pathinq cpi;
+
+ xpt_path_inq(&cpi, periph->path);
+ periph->deferred_callback(NULL, periph->deferred_ac,
+ periph->path, &cpi);
break;
+ }
default:
- arg = NULL;
+ periph->deferred_callback(NULL, periph->deferred_ac,
+ periph->path, NULL);
break;
}
- periph->deferred_callback(NULL, periph->deferred_ac,
- periph->path, arg);
}
xpt_free_path(periph->path);
free(periph, M_CAMPERIPH);
@@ -1682,10 +1683,7 @@ camperiphscsisenseerror(union ccb *ccb, union ccb **orig,
/*
* Grab the inquiry data for this device.
*/
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, ccb->ccb_h.path);
err_action = scsi_error_action(&ccb->csio, &cgd.inq_data,
sense_flags);
@@ -2133,11 +2131,7 @@ cam_periph_devctl_notify(union ccb *ccb)
sbuf_cat(&sb, "serial=\"");
if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) != NULL) {
- xpt_setup_ccb(&cgd->ccb_h, ccb->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd->ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)cgd);
-
+ xpt_gdev_type(cgd, ccb->ccb_h.path);
if (cgd->ccb_h.status == CAM_REQ_CMP)
sbuf_bcat(&sb, cgd->serial_num, cgd->serial_num_len);
xpt_free_ccb((union ccb *)cgd);
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 38bc82c69aad..cae29226d13c 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -2471,15 +2471,12 @@ xptsetasyncfunc(struct cam_ed *device, void *arg)
if ((device->flags & CAM_DEV_UNCONFIGURED) != 0)
return (1);
- memset(&cgd, 0, sizeof(cgd));
xpt_compile_path(&path,
NULL,
device->target->bus->path_id,
device->target->target_id,
device->lun_id);
- xpt_setup_ccb(&cgd.ccb_h, &path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, &path);
csa->callback(csa->callback_arg,
AC_FOUND_DEVICE,
&path, &cgd);
@@ -2518,6 +2515,15 @@ xpt_action(union ccb *start_ccb)
("xpt_action: func %#x %s\n", start_ccb->ccb_h.func_code,
xpt_action_name(start_ccb->ccb_h.func_code)));
+ /*
+ * Either it isn't queued, or it has a real priority. There still too
+ * many places that reuse CCBs with a real priority to do immediate
+ * queries to do the other side of this assert.
+ */
+ KASSERT((start_ccb->ccb_h.func_code & XPT_FC_QUEUED) == 0 ||
+ start_ccb->ccb_h.pinfo.priority != CAM_PRIORITY_NONE,
+ ("%s: queued ccb and CAM_PRIORITY_NONE illegal.", __func__));
+
start_ccb->ccb_h.status = CAM_REQ_INPROG;
(*(start_ccb->ccb_h.path->bus->xport->ops->action))(start_ccb);
}
diff --git a/sys/cam/cam_xpt.h b/sys/cam/cam_xpt.h
index 06ef52580120..efa6c823245a 100644
--- a/sys/cam/cam_xpt.h
+++ b/sys/cam/cam_xpt.h
@@ -145,19 +145,31 @@ uint32_t xpt_poll_setup(union ccb *start_ccb);
void xpt_sim_poll(struct cam_sim *sim);
/*
- * Perform a path inquiry at the request priority. The bzero may be
- * unnecessary.
+ * Perform a path inquiry. bzero may be redundant for allocated CCBs, but for
+ * the on-stack CCBs it's required.
*/
static inline void
xpt_path_inq(struct ccb_pathinq *cpi, struct cam_path *path)
{
-
bzero(cpi, sizeof(*cpi));
- xpt_setup_ccb(&cpi->ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi->ccb_h, path, CAM_PRIORITY_NONE);
cpi->ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)cpi);
}
+/*
+ * Perform get device type. bzero may be redundant for allocated CCBs, but for
+ * the on-stack CCBs it's required.
+ */
+static inline void
+xpt_gdev_type(struct ccb_getdev *cgd, struct cam_path *path)
+{
+ bzero(cgd, sizeof(*cgd));
+ xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NONE);
+ cgd->ccb_h.func_code = XPT_GDEV_TYPE;
+ xpt_action((union ccb *)cgd);
+}
+
#endif /* _KERNEL */
#endif /* _CAM_CAM_XPT_H */
diff --git a/sys/cam/mmc/mmc_da.c b/sys/cam/mmc/mmc_da.c
index 1c455e1951d7..322141a72707 100644
--- a/sys/cam/mmc/mmc_da.c
+++ b/sys/cam/mmc/mmc_da.c
@@ -692,10 +692,7 @@ sddaasync(void *callback_arg, uint32_t code,
case AC_GETDEV_CHANGED:
{
CAM_DEBUG(path, CAM_DEBUG_TRACE, ("=> AC_GETDEV_CHANGED\n"));
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, periph->path);
cam_periph_async(periph, code, path, arg);
break;
}
@@ -789,7 +786,8 @@ sddaregister(struct cam_periph *periph, void *arg)
static int
mmc_exec_app_cmd(struct cam_periph *periph, union ccb *ccb,
- struct mmc_command *cmd) {
+ struct mmc_command *cmd)
+{
int err;
/* Send APP_CMD first */
@@ -843,7 +841,8 @@ mmc_exec_app_cmd(struct cam_periph *periph, union ccb *ccb,
}
static int
-mmc_app_get_scr(struct cam_periph *periph, union ccb *ccb, uint32_t *rawscr) {
+mmc_app_get_scr(struct cam_periph *periph, union ccb *ccb, uint32_t *rawscr)
+{
int err;
struct mmc_command cmd;
struct mmc_data d;
@@ -869,7 +868,8 @@ mmc_app_get_scr(struct cam_periph *periph, union ccb *ccb, uint32_t *rawscr) {
static int
mmc_send_ext_csd(struct cam_periph *periph, union ccb *ccb,
- uint8_t *rawextcsd, size_t buf_len) {
+ uint8_t *rawextcsd, size_t buf_len)
+{
int err;
struct mmc_data d;
@@ -966,14 +966,16 @@ mmc_switch(struct cam_periph *periph, union ccb *ccb,
}
static uint32_t
-mmc_get_spec_vers(struct cam_periph *periph) {
+mmc_get_spec_vers(struct cam_periph *periph)
+{
struct sdda_softc *softc = (struct sdda_softc *)periph->softc;
return (softc->csd.spec_vers);
}
static uint64_t
-mmc_get_media_size(struct cam_periph *periph) {
+mmc_get_media_size(struct cam_periph *periph)
+{
struct sdda_softc *softc = (struct sdda_softc *)periph->softc;
return (softc->mediasize);
@@ -992,7 +994,8 @@ mmc_get_cmd6_timeout(struct cam_periph *periph)
static int
mmc_sd_switch(struct cam_periph *periph, union ccb *ccb,
uint8_t mode, uint8_t grp, uint8_t value,
- uint8_t *res) {
+ uint8_t *res)
+{
struct mmc_data mmc_d;
uint32_t arg;
int err;
@@ -1069,7 +1072,8 @@ mmc_set_timing(struct cam_periph *periph,
}
static void
-sdda_start_init_task(void *context, int pending) {
+sdda_start_init_task(void *context, int pending)
+{
union ccb *new_ccb;
struct cam_periph *periph;
@@ -1077,7 +1081,7 @@ sdda_start_init_task(void *context, int pending) {
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdda_start_init_task\n"));
new_ccb = xpt_alloc_ccb();
xpt_setup_ccb(&new_ccb->ccb_h, periph->path,
- CAM_PRIORITY_NONE);
+ CAM_PRIORITY_NORMAL);
cam_periph_lock(periph);
cam_periph_hold(periph, PRIBIO|PCATCH);
@@ -1088,7 +1092,8 @@ sdda_start_init_task(void *context, int pending) {
}
static void
-sdda_set_bus_width(struct cam_periph *periph, union ccb *ccb, int width) {
+sdda_set_bus_width(struct cam_periph *periph, union ccb *ccb, int width)
+{
struct sdda_softc *softc = (struct sdda_softc *)periph->softc;
struct mmc_params *mmcp = &periph->path->device->mmc_ident_data;
int err;
@@ -1198,27 +1203,6 @@ sdda_get_host_caps(struct cam_periph *periph, union ccb *ccb)
return (cts->host_caps);
}
-static uint32_t
-sdda_get_max_data(struct cam_periph *periph, union ccb *ccb)
-{
- struct ccb_trans_settings_mmc *cts;
-
- cts = &ccb->cts.proto_specific.mmc;
- memset(cts, 0, sizeof(struct ccb_trans_settings_mmc));
-
- ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
- ccb->ccb_h.flags = CAM_DIR_NONE;
- ccb->ccb_h.retry_count = 0;
- ccb->ccb_h.timeout = 100;
- ccb->ccb_h.cbfcnp = NULL;
- xpt_action(ccb);
-
- if (ccb->ccb_h.status != CAM_REQ_CMP)
- panic("Cannot get host max data");
- KASSERT(cts->host_max_data != 0, ("host_max_data == 0?!"));
- return (cts->host_max_data);
-}
-
static void
sdda_start_init(void *context, union ccb *start_ccb)
{
@@ -1544,10 +1528,7 @@ sdda_add_part(struct cam_periph *periph, u_int type, const char *name,
bioq_init(&part->bio_queue);
- bzero(&cpi, sizeof(cpi));
- xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
- cpi.ccb_h.func_code = XPT_PATH_INQ;
- xpt_action((union ccb *)&cpi);
+ xpt_path_inq(&cpi, periph->path);
/*
* Register this media as a disk
diff --git a/sys/cam/mmc/mmc_xpt.c b/sys/cam/mmc/mmc_xpt.c
index 4fce03004994..f5f66f5214a8 100644
--- a/sys/cam/mmc/mmc_xpt.c
+++ b/sys/cam/mmc/mmc_xpt.c
@@ -610,7 +610,6 @@ mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb)
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_RESET\n"));
/* FALLTHROUGH */
case PROBE_IDENTIFY:
- xpt_path_inq(&start_ccb->cpi, periph->path);
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_IDENTIFY\n"));
init_standard_ccb(start_ccb, XPT_MMC_GET_TRAN_SETTINGS);
break;
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
index 13a376ebb6e3..b518f84454ad 100644
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -3708,11 +3708,7 @@ scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio,
/*
* Get the device information.
*/
- xpt_setup_ccb(&cgd->ccb_h,
- csio->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd->ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)cgd);
+ xpt_gdev_type(cgd, csio->ccb_h.path);
/*
* If the device is unconfigured, just pretend that it is a hard
@@ -5144,11 +5140,7 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
/*
* Get the device information.
*/
- xpt_setup_ccb(&cgd->ccb_h,
- csio->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd->ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)cgd);
+ xpt_gdev_type(cgd, csio->ccb_h.path);
/*
* If the device is unconfigured, just pretend that it is a hard
diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
index 00a417f65052..e622a96ec77e 100644
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -1240,13 +1240,7 @@ cddone(struct cam_periph *periph, union ccb *done_ccb)
/*getcount_only*/0);
status = done_ccb->ccb_h.status;
-
- bzero(&cgd, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h,
- done_ccb->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, done_ccb->ccb_h.path);
if (scsi_extract_sense_ccb(done_ccb,
&error_code, &sense_key, &asc, &ascq))
diff --git a/sys/cam/scsi/scsi_ch.c b/sys/cam/scsi/scsi_ch.c
index 89a817c1b488..3da22ba61392 100644
--- a/sys/cam/scsi/scsi_ch.c
+++ b/sys/cam/scsi/scsi_ch.c
@@ -1705,11 +1705,7 @@ chscsiversion(struct cam_periph *periph)
/*
* Get the device information.
*/
- xpt_setup_ccb(&cgd->ccb_h,
- periph->path,
- CAM_PRIORITY_NORMAL);
- cgd->ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)cgd);
+ xpt_gdev_type(cgd, periph->path);
if (cgd->ccb_h.status != CAM_REQ_CMP) {
xpt_free_ccb((union ccb *)cgd);
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index 0a2389cd9b5d..d02750aaacaf 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -5035,11 +5035,7 @@ dadone_proberc(struct cam_periph *periph, union ccb *done_ccb)
/*timeout*/0,
/*getcount_only*/0);
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, done_ccb->ccb_h.path,
- CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, done_ccb->ccb_h.path);
if (scsi_extract_sense_ccb(done_ccb,
&error_code, &sense_key, &asc, &ascq))
@@ -5077,6 +5073,18 @@ dadone_proberc(struct cam_periph *periph, union ccb *done_ccb)
* behind a SATL translation that's fallen into a
* terminally fatal state.
*
+ * 4/2 happens on some HGST drives that are quite
+ * ill. We've already sent the start unit command (for
+ * which we ignore a 44/0 asc/ascq, which I'm hesitant
+ * to change since it's so basic and there's other error
+ * conditions to the START UNIT we should ignore). So to
+ * require initialization at this point when it should
+ * be fine implies to me, at least, that we should
+ * invalidate. Since we do read capacity in geom tasting
+ * a lot, and since this timeout is long, this leads to
+ * up to a 10 minute delay in booting.
+ *
+ * 4/2: LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED
* 25/0: LOGICAL UNIT NOT SUPPORTED
* 44/0: INTERNAL TARGET FAILURE
* 44/1: PERSISTENT RESERVATION INFORMATION LOST
@@ -5084,6 +5092,7 @@ dadone_proberc(struct cam_periph *periph, union ccb *done_ccb)
*/
if ((have_sense)
&& (asc != 0x25) && (asc != 0x44)
+ && (asc != 0x04 && ascq != 0x02)
&& (error_code == SSD_CURRENT_ERROR
|| error_code == SSD_DESC_CURRENT_ERROR)) {
const char *sense_key_desc;
diff --git a/sys/cam/scsi/scsi_enc_ses.c b/sys/cam/scsi/scsi_enc_ses.c
index c429e820a1fd..435874a9874a 100644
--- a/sys/cam/scsi/scsi_enc_ses.c
+++ b/sys/cam/scsi/scsi_enc_ses.c
@@ -979,10 +979,7 @@ ses_paths_iter(enc_softc_t *enc, enc_element_t *elm,
!= CAM_REQ_CMP)
return;
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, path);
if (cam_ccb_success((union ccb *)&cgd))
callback(enc, elm, path, callback_arg);
diff --git a/sys/cam/scsi/scsi_sa.c b/sys/cam/scsi/scsi_sa.c
index cfd48c98f30e..88147393192f 100644
--- a/sys/cam/scsi/scsi_sa.c
+++ b/sys/cam/scsi/scsi_sa.c
@@ -4731,12 +4731,7 @@ saextget(struct cdev *dev, struct cam_periph *periph, struct sbuf *sb,
SASBADDVARSTR(sb, indent, periph->periph_name, %s, periph_name,
strlen(periph->periph_name) + 1);
SASBADDUINT(sb, indent, periph->unit_number, %u, unit_number);
- memset(&cgd, 0, sizeof(cgd));
- xpt_setup_ccb(&cgd.ccb_h,
- periph->path,
- CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ xpt_gdev_type(&cgd, periph->path);
if ((cgd.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
g->status = MT_EXT_GET_ERROR;
snprintf(g->error_str, sizeof(g->error_str),
diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c
index 439dd2050a95..bef35243af98 100644
--- a/sys/cam/scsi/scsi_xpt.c
+++ b/sys/cam/scsi/scsi_xpt.c
@@ -1915,6 +1915,15 @@ typedef struct {
int lunindex[0];
} scsi_scan_bus_info;
+static void
+free_scan_info(scsi_scan_bus_info *scan_info)
+{
+ KASSERT(scan_info->cpi != NULL,
+ ("scan_info (%p) missing its ccb_pathinq CCB\n", scan_info));
+ xpt_free_ccb((union ccb *)scan_info->cpi);
+ free(scan_info, M_CAMXPT);
+}
+
/*
* To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
* As the scan progresses, scsi_scan_bus is used as the
@@ -1945,10 +1954,7 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
xpt_done(request_ccb);
return;
}
- xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
- request_ccb->ccb_h.pinfo.priority);
- work_ccb->ccb_h.func_code = XPT_PATH_INQ;
- xpt_action(work_ccb);
+ xpt_path_inq(&work_ccb->cpi, request_ccb->ccb_h.path);
if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
request_ccb->ccb_h.status = work_ccb->ccb_h.status;
xpt_free_ccb(work_ccb);
@@ -2037,16 +2043,14 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
printf(
"scsi_scan_bus: xpt_create_path failed with status %#x, bus scan halted\n",
status);
- free(scan_info, M_CAMXPT);
+ free_scan_info(scan_info);
request_ccb->ccb_h.status = status;
- xpt_free_ccb(work_ccb);
xpt_done(request_ccb);
break;
}
work_ccb = xpt_alloc_ccb_nowait();
if (work_ccb == NULL) {
- xpt_free_ccb((union ccb *)scan_info->cpi);
- free(scan_info, M_CAMXPT);
+ free_scan_info(scan_info);
xpt_free_path(path);
request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
xpt_done(request_ccb);
@@ -2179,16 +2183,16 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
* Check to see if we scan any further luns.
*/
if (next_target) {
- int done;
+ bool done;
/*
* Free the current request path- we're done with it.
*/
xpt_free_path(oldpath);
hop_again:
- done = 0;
+ done = false;
if (scan_info->request_ccb->ccb_h.func_code == XPT_SCAN_TGT) {
- done = 1;
+ done = true;
} else if (scan_info->cpi->hba_misc & PIM_SEQSCAN) {
scan_info->counter++;
if (scan_info->counter ==
@@ -2197,23 +2201,22 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
}
if (scan_info->counter >=
scan_info->cpi->max_target+1) {
- done = 1;
+ done = true;
}
} else {
scan_info->counter--;
if (scan_info->counter == 0) {
- done = 1;
+ done = true;
}
}
if (done) {
mtx_unlock(mtx);
xpt_free_ccb(request_ccb);
- xpt_free_ccb((union ccb *)scan_info->cpi);
request_ccb = scan_info->request_ccb;
CAM_DEBUG(request_ccb->ccb_h.path,
CAM_DEBUG_TRACE,
("SCAN done for %p\n", scan_info));
- free(scan_info, M_CAMXPT);
+ free_scan_info(scan_info);
request_ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(request_ccb);
break;
@@ -2233,9 +2236,8 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
"scsi_scan_bus: xpt_create_path failed with status %#x, bus scan halted\n",
status);
xpt_free_ccb(request_ccb);
- xpt_free_ccb((union ccb *)scan_info->cpi);
request_ccb = scan_info->request_ccb;
- free(scan_info, M_CAMXPT);
+ free_scan_info(scan_info);
request_ccb->ccb_h.status = status;
xpt_done(request_ccb);
break;
@@ -2294,10 +2296,7 @@ scsi_scan_lun(struct cam_periph *periph, struct cam_path *path,
CAM_DEBUG(path, CAM_DEBUG_TRACE, ("scsi_scan_lun\n"));
- memset(&cpi, 0, sizeof(cpi));
- xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
- cpi.ccb_h.func_code = XPT_PATH_INQ;
- xpt_action((union ccb *)&cpi);
+ xpt_path_inq(&cpi, path);
if (cpi.ccb_h.status != CAM_REQ_CMP) {
if (request_ccb != NULL) {
@@ -2421,10 +2420,7 @@ scsi_devise_transport(struct cam_path *path)
struct scsi_inquiry_data *inq_buf;
/* Get transport information from the SIM */
- memset(&cpi, 0, sizeof(cpi));
- xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
- cpi.ccb_h.func_code = XPT_PATH_INQ;
- xpt_action((union ccb *)&cpi);
+ xpt_path_inq(&cpi, path);
inq_buf = NULL;
if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0)
@@ -2732,10 +2728,7 @@ scsi_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_path *path
inq_data = &device->inq_data;
scsi = &cts->proto_specific.scsi;
- memset(&cpi, 0, sizeof(cpi));
- xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
- cpi.ccb_h.func_code = XPT_PATH_INQ;
- xpt_action((union ccb *)&cpi);
+ xpt_path_inq(&cpi, path);
/* SCSI specific sanity checking */
if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
@@ -3046,10 +3039,7 @@ _scsi_announce_periph(struct cam_periph *periph, u_int *speed, u_int *freq, stru
return;
/* Ask the SIM for its base transfer speed */
- memset(&cpi, 0, sizeof(cpi));
- xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
- cpi.ccb_h.func_code = XPT_PATH_INQ;
- xpt_action((union ccb *)&cpi);
+ xpt_path_inq(&cpi, path);
/* Report connection speed */
*speed = cpi.base_transfer_speed;
diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h
index 0ce38384abbf..83d964360343 100644
--- a/sys/cddl/boot/zfs/zfsimpl.h
+++ b/sys/cddl/boot/zfs/zfsimpl.h
@@ -2019,6 +2019,7 @@ typedef struct vdev {
vdev_list_t v_children; /* children of this vdev */
const char *v_name; /* vdev name */
uint64_t v_guid; /* vdev guid */
+ uint64_t v_txg; /* most recent transaction */
uint64_t v_id; /* index in parent */
uint64_t v_psize; /* physical device capacity */
int v_ashift; /* offset to block shift */
@@ -2048,7 +2049,6 @@ typedef struct spa {
STAILQ_ENTRY(spa) spa_link; /* link in global pool list */
char *spa_name; /* pool name */
uint64_t spa_guid; /* pool guid */
- uint64_t spa_txg; /* most recent transaction */
struct uberblock *spa_uberblock; /* best uberblock so far */
vdev_t *spa_root_vdev; /* toplevel vdev container */
objset_phys_t *spa_mos; /* MOS for this pool */
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
index eaa086188b5f..8d2748098c00 100644
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -511,4 +511,6 @@
#define FREEBSD32_SYS_fchroot 590
#define FREEBSD32_SYS_freebsd32_setcred 591
#define FREEBSD32_SYS_exterrctl 592
-#define FREEBSD32_SYS_MAXSYSCALL 593
+#define FREEBSD32_SYS_inotify_add_watch_at 593
+#define FREEBSD32_SYS_inotify_rm_watch 594
+#define FREEBSD32_SYS_MAXSYSCALL 595
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
index 989f32a5c6f0..bda373268cc5 100644
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -598,4 +598,6 @@ const char *freebsd32_syscallnames[] = {
"fchroot", /* 590 = fchroot */
"freebsd32_setcred", /* 591 = freebsd32_setcred */
"exterrctl", /* 592 = exterrctl */
+ "inotify_add_watch_at", /* 593 = inotify_add_watch_at */
+ "inotify_rm_watch", /* 594 = inotify_rm_watch */
};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
index 476fe2ac3f80..ef0aff8bf852 100644
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -659,5 +659,7 @@ struct sysent freebsd32_sysent[] = {
{ .sy_narg = AS(getrlimitusage_args), .sy_call = (sy_call_t *)sys_getrlimitusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimitusage */
{ .sy_narg = AS(fchroot_args), .sy_call = (sy_call_t *)sys_fchroot, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 590 = fchroot */
{ .sy_narg = AS(freebsd32_setcred_args), .sy_call = (sy_call_t *)freebsd32_setcred, .sy_auevent = AUE_SETCRED, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 591 = freebsd32_setcred */
- { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */
+ { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */
+ { .sy_narg = AS(inotify_add_watch_at_args), .sy_call = (sy_call_t *)sys_inotify_add_watch_at, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 593 = inotify_add_watch_at */
+ { .sy_narg = AS(inotify_rm_watch_args), .sy_call = (sy_call_t *)sys_inotify_rm_watch, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 594 = inotify_rm_watch */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
index cf08938cd5de..37564a737a62 100644
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3395,6 +3395,24 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 3;
break;
}
+ /* inotify_add_watch_at */
+ case 593: {
+ struct inotify_add_watch_at_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ iarg[a++] = p->dfd; /* int */
+ uarg[a++] = (intptr_t)p->path; /* const char * */
+ uarg[a++] = p->mask; /* uint32_t */
+ *n_args = 4;
+ break;
+ }
+ /* inotify_rm_watch */
+ case 594: {
+ struct inotify_rm_watch_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ iarg[a++] = p->wd; /* int */
+ *n_args = 2;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9172,6 +9190,38 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
};
break;
+ /* inotify_add_watch_at */
+ case 593:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* inotify_rm_watch */
+ case 594:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11070,6 +11120,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* inotify_add_watch_at */
+ case 593:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* inotify_rm_watch */
+ case 594:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/compat/linux/linux_dummy.c b/sys/compat/linux/linux_dummy.c
index 35d6debe0da9..19cd55849f65 100644
--- a/sys/compat/linux/linux_dummy.c
+++ b/sys/compat/linux/linux_dummy.c
@@ -74,9 +74,6 @@ DUMMY(kexec_load);
DUMMY(add_key);
DUMMY(request_key);
DUMMY(keyctl);
-/* Linux 2.6.13: */
-DUMMY(inotify_add_watch);
-DUMMY(inotify_rm_watch);
/* Linux 2.6.16: */
DUMMY(migrate_pages);
DUMMY(unshare);
@@ -87,7 +84,6 @@ DUMMY(vmsplice);
DUMMY(move_pages);
/* Linux 2.6.27: */
DUMMY(signalfd4);
-DUMMY(inotify_init1);
/* Linux 2.6.31: */
DUMMY(perf_event_open);
/* Linux 2.6.36: */
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 246bc26d85d4..86834a7ecea8 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -32,11 +32,13 @@
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/filedesc.h>
+#include <sys/inotify.h>
#include <sys/lock.h>
#include <sys/mman.h>
#include <sys/selinfo.h>
#include <sys/pipe.h>
#include <sys/proc.h>
+#include <sys/specialfd.h>
#include <sys/stat.h>
#include <sys/sx.h>
#include <sys/syscallsubr.h>
@@ -1877,3 +1879,122 @@ linux_writev(struct thread *td, struct linux_writev_args *args)
freeuio(auio);
return (linux_enobufs2eagain(td, args->fd, error));
}
+
+static int
+linux_inotify_init_flags(int l_flags)
+{
+ int bsd_flags;
+
+ if ((l_flags & ~(LINUX_IN_CLOEXEC | LINUX_IN_NONBLOCK)) != 0)
+ linux_msg(NULL, "inotify_init1 unsupported flags 0x%x",
+ l_flags);
+
+ bsd_flags = 0;
+ if ((l_flags & LINUX_IN_CLOEXEC) != 0)
+ bsd_flags |= O_CLOEXEC;
+ if ((l_flags & LINUX_IN_NONBLOCK) != 0)
+ bsd_flags |= O_NONBLOCK;
+ return (bsd_flags);
+}
+
+static int
+inotify_init_common(struct thread *td, int flags)
+{
+ struct specialfd_inotify si;
+
+ si.flags = linux_inotify_init_flags(flags);
+ return (kern_specialfd(td, SPECIALFD_INOTIFY, &si));
+}
+
+#if defined(__i386__) || defined(__amd64__)
+int
+linux_inotify_init(struct thread *td, struct linux_inotify_init_args *args)
+{
+ return (inotify_init_common(td, 0));
+}
+#endif
+
+int
+linux_inotify_init1(struct thread *td, struct linux_inotify_init1_args *args)
+{
+ return (inotify_init_common(td, args->flags));
+}
+
+/*
+ * The native implementation uses the same values for inotify events as
+ * libinotify, which gives us binary compatibility with Linux. This simplifies
+ * the shim implementation a lot, as otherwise we would have to handle read(2)
+ * calls on inotify descriptors and translate events to Linux's ABI.
+ */
+_Static_assert(LINUX_IN_ACCESS == IN_ACCESS,
+ "IN_ACCESS mismatch");
+_Static_assert(LINUX_IN_MODIFY == IN_MODIFY,
+ "IN_MODIFY mismatch");
+_Static_assert(LINUX_IN_ATTRIB == IN_ATTRIB,
+ "IN_ATTRIB mismatch");
+_Static_assert(LINUX_IN_CLOSE_WRITE == IN_CLOSE_WRITE,
+ "IN_CLOSE_WRITE mismatch");
+_Static_assert(LINUX_IN_CLOSE_NOWRITE == IN_CLOSE_NOWRITE,
+ "IN_CLOSE_NOWRITE mismatch");
+_Static_assert(LINUX_IN_OPEN == IN_OPEN,
+ "IN_OPEN mismatch");
+_Static_assert(LINUX_IN_MOVED_FROM == IN_MOVED_FROM,
+ "IN_MOVED_FROM mismatch");
+_Static_assert(LINUX_IN_MOVED_TO == IN_MOVED_TO,
+ "IN_MOVED_TO mismatch");
+_Static_assert(LINUX_IN_CREATE == IN_CREATE,
+ "IN_CREATE mismatch");
+_Static_assert(LINUX_IN_DELETE == IN_DELETE,
+ "IN_DELETE mismatch");
+_Static_assert(LINUX_IN_DELETE_SELF == IN_DELETE_SELF,
+ "IN_DELETE_SELF mismatch");
+_Static_assert(LINUX_IN_MOVE_SELF == IN_MOVE_SELF,
+ "IN_MOVE_SELF mismatch");
+
+_Static_assert(LINUX_IN_UNMOUNT == IN_UNMOUNT,
+ "IN_UNMOUNT mismatch");
+_Static_assert(LINUX_IN_Q_OVERFLOW == IN_Q_OVERFLOW,
+ "IN_Q_OVERFLOW mismatch");
+_Static_assert(LINUX_IN_IGNORED == IN_IGNORED,
+ "IN_IGNORED mismatch");
+
+_Static_assert(LINUX_IN_ISDIR == IN_ISDIR,
+ "IN_ISDIR mismatch");
+_Static_assert(LINUX_IN_ONLYDIR == IN_ONLYDIR,
+ "IN_ONLYDIR mismatch");
+_Static_assert(LINUX_IN_DONT_FOLLOW == IN_DONT_FOLLOW,
+ "IN_DONT_FOLLOW mismatch");
+_Static_assert(LINUX_IN_MASK_CREATE == IN_MASK_CREATE,
+ "IN_MASK_CREATE mismatch");
+_Static_assert(LINUX_IN_MASK_ADD == IN_MASK_ADD,
+ "IN_MASK_ADD mismatch");
+_Static_assert(LINUX_IN_ONESHOT == IN_ONESHOT,
+ "IN_ONESHOT mismatch");
+_Static_assert(LINUX_IN_EXCL_UNLINK == IN_EXCL_UNLINK,
+ "IN_EXCL_UNLINK mismatch");
+
+static int
+linux_inotify_watch_flags(int l_flags)
+{
+ if ((l_flags & ~(LINUX_IN_ALL_EVENTS | LINUX_IN_ALL_FLAGS)) != 0) {
+ linux_msg(NULL, "inotify_add_watch unsupported flags 0x%x",
+ l_flags);
+ }
+
+ return (l_flags);
+}
+
+int
+linux_inotify_add_watch(struct thread *td,
+ struct linux_inotify_add_watch_args *args)
+{
+ return (kern_inotify_add_watch(args->fd, AT_FDCWD, args->pathname,
+ linux_inotify_watch_flags(args->mask), td));
+}
+
+int
+linux_inotify_rm_watch(struct thread *td,
+ struct linux_inotify_rm_watch_args *args)
+{
+ return (kern_inotify_rm_watch(args->fd, args->wd, td));
+}
diff --git a/sys/compat/linux/linux_file.h b/sys/compat/linux/linux_file.h
index 2e56942b0f40..7448dc597230 100644
--- a/sys/compat/linux/linux_file.h
+++ b/sys/compat/linux/linux_file.h
@@ -189,6 +189,38 @@
#define LINUX_HUGETLB_FLAG_ENCODE_2GB (31 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
#define LINUX_HUGETLB_FLAG_ENCODE_16GB (34U << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+/* inotify flags */
+#define LINUX_IN_ACCESS 0x00000001
+#define LINUX_IN_MODIFY 0x00000002
+#define LINUX_IN_ATTRIB 0x00000004
+#define LINUX_IN_CLOSE_WRITE 0x00000008
+#define LINUX_IN_CLOSE_NOWRITE 0x00000010
+#define LINUX_IN_OPEN 0x00000020
+#define LINUX_IN_MOVED_FROM 0x00000040
+#define LINUX_IN_MOVED_TO 0x00000080
+#define LINUX_IN_CREATE 0x00000100
+#define LINUX_IN_DELETE 0x00000200
+#define LINUX_IN_DELETE_SELF 0x00000400
+#define LINUX_IN_MOVE_SELF 0x00000800
+
+#define LINUX_IN_UNMOUNT 0x00002000
+#define LINUX_IN_Q_OVERFLOW 0x00004000
+#define LINUX_IN_IGNORED 0x00008000
+
+#define LINUX_IN_ONLYDIR 0x01000000
+#define LINUX_IN_DONT_FOLLOW 0x02000000
+#define LINUX_IN_EXCL_UNLINK 0x04000000
+#define LINUX_IN_MASK_CREATE 0x10000000
+#define LINUX_IN_MASK_ADD 0x20000000
+#define LINUX_IN_ISDIR 0x40000000
+#define LINUX_IN_ONESHOT 0x80000000
+
+#define LINUX_IN_ALL_EVENTS 0x00000fff
+#define LINUX_IN_ALL_FLAGS 0xf700e000
+
+#define LINUX_IN_NONBLOCK 0x00000800
+#define LINUX_IN_CLOEXEC 0x00080000
+
#if defined(_KERNEL)
struct l_file_handle {
l_uint handle_bytes;
diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h
index f3a840d9bf4b..efa5c8cb67b3 100644
--- a/sys/compat/linuxkpi/common/include/linux/slab.h
+++ b/sys/compat/linuxkpi/common/include/linux/slab.h
@@ -45,7 +45,7 @@
MALLOC_DECLARE(M_KMALLOC);
-#define kvzalloc(size, flags) kmalloc(size, (flags) | __GFP_ZERO)
+#define kvzalloc(size, flags) kvmalloc(size, (flags) | __GFP_ZERO)
#define kvcalloc(n, size, flags) kvmalloc_array(n, size, (flags) | __GFP_ZERO)
#define kzalloc(size, flags) kmalloc(size, (flags) | __GFP_ZERO)
#define kzalloc_node(size, flags, node) kmalloc_node(size, (flags) | __GFP_ZERO, node)
diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c
index ebb92eacbf9a..628af17df853 100644
--- a/sys/compat/linuxkpi/common/src/linux_page.c
+++ b/sys/compat/linuxkpi/common/src/linux_page.c
@@ -106,6 +106,7 @@ linux_alloc_pages(gfp_t flags, unsigned int order)
if ((flags & M_ZERO) != 0)
req |= VM_ALLOC_ZERO;
+
if (order == 0 && (flags & GFP_DMA32) == 0) {
page = vm_page_alloc_noobj(req);
if (page == NULL)
@@ -113,6 +114,10 @@ linux_alloc_pages(gfp_t flags, unsigned int order)
} else {
vm_paddr_t pmax = (flags & GFP_DMA32) ?
BUS_SPACE_MAXADDR_32BIT : BUS_SPACE_MAXADDR;
+
+ if ((flags & __GFP_NORETRY) != 0)
+ req |= VM_ALLOC_NORECLAIM;
+
retry:
page = vm_page_alloc_noobj_contig(req, npages, 0, pmax,
PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
diff --git a/sys/conf/files b/sys/conf/files
index f6d473b1431b..dd0d390962f2 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -598,42 +598,24 @@ contrib/dev/acpica/components/utilities/utxface.c optional acpi
contrib/dev/acpica/components/utilities/utxferror.c optional acpi
contrib/dev/acpica/components/utilities/utxfinit.c optional acpi
contrib/dev/acpica/os_specific/service_layers/osgendbg.c optional acpi acpi_debug
-netpfil/ipfilter/netinet/fil.c optional ipfilter inet \
- compile-with "${NORMAL_C} ${NO_WSELF_ASSIGN} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_auth.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_fil_freebsd.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_frag.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_log.c optional ipfilter inet \
- compile-with "${NORMAL_C} -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_nat.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_proxy.c optional ipfilter inet \
- compile-with "${NORMAL_C} ${NO_WSELF_ASSIGN} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_state.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_lookup.c optional ipfilter inet \
- compile-with "${NORMAL_C} ${NO_WSELF_ASSIGN} -Wno-unused -Wno-error -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_pool.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_htable.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter ${NO_WTAUTOLOGICAL_POINTER_COMPARE}"
-netpfil/ipfilter/netinet/ip_sync.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/mlfk_ipl.c optional ipfilter inet \
- compile-with "${NORMAL_C} -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_nat6.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_rules.c optional ipfilter inet \
- compile-with "${NORMAL_C} -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_scan.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/ip_dstlist.c optional ipfilter inet \
- compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter"
-netpfil/ipfilter/netinet/radix_ipf.c optional ipfilter inet \
- compile-with "${NORMAL_C} -I$S/netpfil/ipfilter"
+netpfil/ipfilter/netinet/fil.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_auth.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_fil_freebsd.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_frag.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_log.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_nat.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_proxy.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_state.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_lookup.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_pool.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_htable.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_sync.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/mlfk_ipl.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_nat6.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_rules.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_scan.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/ip_dstlist.c optional ipfilter inet compile-with "${IPFILTER_C}"
+netpfil/ipfilter/netinet/radix_ipf.c optional ipfilter inet compile-with "${IPFILTER_C}"
contrib/libfdt/fdt.c optional fdt
contrib/libfdt/fdt_ro.c optional fdt
contrib/libfdt/fdt_rw.c optional fdt
@@ -3173,8 +3155,6 @@ dev/sound/midi/midi.c optional sound
dev/sound/midi/mpu401.c optional sound
dev/sound/midi/mpu_if.m optional sound
dev/sound/midi/mpufoi_if.m optional sound
-dev/sound/midi/sequencer.c optional sound
-dev/sound/midi/synth_if.m optional sound
dev/spibus/acpi_spibus.c optional acpi spibus
dev/spibus/ofw_spibus.c optional fdt spibus
dev/spibus/spibus.c optional spibus \
@@ -3247,6 +3227,19 @@ dev/uart/uart_if.m optional uart
dev/uart/uart_subr.c optional uart
dev/uart/uart_tty.c optional uart
#
+# Universal Flash Storage Host Controller Interface drivers
+#
+dev/ufshci/ufshci.c optional ufshci
+dev/ufshci/ufshci_ctrlr.c optional ufshci
+dev/ufshci/ufshci_ctrlr_cmd.c optional ufshci
+dev/ufshci/ufshci_dev.c optional ufshci
+dev/ufshci/ufshci_pci.c optional ufshci
+dev/ufshci/ufshci_req_queue.c optional ufshci
+dev/ufshci/ufshci_req_sdb.c optional ufshci
+dev/ufshci/ufshci_sim.c optional ufshci
+dev/ufshci/ufshci_sysctl.c optional ufshci
+dev/ufshci/ufshci_uic_cmd.c optional ufshci
+#
# USB controller drivers
#
dev/usb/controller/musb_otg.c optional musb
@@ -3992,6 +3985,7 @@ kern/vfs_export.c standard
kern/vfs_extattr.c standard
kern/vfs_hash.c standard
kern/vfs_init.c standard
+kern/vfs_inotify.c standard
kern/vfs_lookup.c standard
kern/vfs_mount.c standard
kern/vfs_mountroot.c standard
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 0584fc29d039..80548320c3fc 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -84,8 +84,8 @@ amd64/amd64/xen-locore.S optional xenhvm \
amd64/amd64/machdep.c standard
amd64/amd64/mem.c optional mem
amd64/amd64/minidump_machdep.c standard
-amd64/amd64/mp_machdep.c optional smp
-amd64/amd64/mpboot.S optional smp
+amd64/amd64/mp_machdep.c standard
+amd64/amd64/mpboot.S standard
amd64/amd64/pmap.c standard
amd64/amd64/ptrace_machdep.c standard
amd64/amd64/support.S standard
@@ -191,6 +191,10 @@ dev/ice/irdma_di_if.m optional ice pci \
compile-with "${NORMAL_M} -I$S/dev/ice"
dev/ice/ice_ddp_common.c optional ice pci \
compile-with "${NORMAL_C} -I$S/dev/ice"
+dev/ice/ice_iov.c optional ice pci pci_iov \
+ compile-with "${NORMAL_C} -I$S/dev/ice"
+dev/ice/ice_vf_mbx.c optional ice pci pci_iov \
+ compile-with "${NORMAL_C} -I$S/dev/ice"
ice_ddp.c optional ice_ddp \
compile-with "${AWK} -f $S/tools/fw_stub.awk ice_ddp.fw:ice_ddp:0x01032900 -mice_ddp -c${.TARGET}" \
no-ctfconvert no-implicit-rule before-depend local \
diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk
index e6e42b33a9b7..78178065e15b 100644
--- a/sys/conf/kern.pre.mk
+++ b/sys/conf/kern.pre.mk
@@ -290,6 +290,10 @@ BNXT_CFLAGS= -I$S/dev/bnxt/bnxt_en ${OFEDCFLAGS}
BNXT_C_NOIMP= ${CC} -c -o ${.TARGET} ${BNXT_CFLAGS} ${WERROR}
BNXT_C= ${BNXT_C_NOIMP} ${.IMPSRC}
+# IP Filter
+IPFILTER_CFLAGS= -I$S/netpfil/ipfilter
+IPFILTER_C= ${NORMAL_C} ${IPFILTER_CFLAGS}
+
GEN_CFILES= $S/$M/$M/genassym.c ${MFILES:T:S/.m$/.c/}
SYSTEM_CFILES= config.c env.c hints.c vnode_if.c
SYSTEM_DEP= Makefile ${SYSTEM_OBJS}
diff --git a/sys/dev/drm2/drm_fb_helper.c b/sys/dev/drm2/drm_fb_helper.c
index f67cc9f60d02..1f4abd255690 100644
--- a/sys/dev/drm2/drm_fb_helper.c
+++ b/sys/dev/drm2/drm_fb_helper.c
@@ -51,7 +51,7 @@ struct vt_kms_softc {
struct task fb_mode_task;
};
-/* Call restore out of vt(9) locks. */
+/* Call restore out of vt(4) locks. */
static void
vt_restore_fbdev_mode(void *arg, int pending)
{
diff --git a/sys/dev/efidev/efirt.c b/sys/dev/efidev/efirt.c
index b0fa33daeca7..b55c1c191077 100644
--- a/sys/dev/efidev/efirt.c
+++ b/sys/dev/efidev/efirt.c
@@ -107,7 +107,8 @@ static int efi_status2err[25] = {
enum efi_table_type {
TYPE_ESRT = 0,
- TYPE_PROP
+ TYPE_PROP,
+ TYPE_MEMORY_ATTR
};
static int efi_enter(void);
@@ -445,6 +446,42 @@ get_table_length(enum efi_table_type type, size_t *table_len, void **taddr)
free(buf, M_TEMP);
return (0);
}
+ case TYPE_MEMORY_ATTR:
+ {
+ efi_guid_t guid = EFI_MEMORY_ATTRIBUTES_TABLE;
+ struct efi_memory_attribute_table *tbl_addr, *mem_addr;
+ int error;
+ void *buf;
+ size_t len = sizeof(struct efi_memory_attribute_table);
+
+ error = efi_get_table(&guid, (void **)&tbl_addr);
+ if (error)
+ return (error);
+
+ buf = malloc(len, M_TEMP, M_WAITOK);
+ error = physcopyout((vm_paddr_t)tbl_addr, buf, len);
+ if (error) {
+ free(buf, M_TEMP);
+ return (error);
+ }
+
+ mem_addr = (struct efi_memory_attribute_table *)buf;
+ if (mem_addr->version != 2) {
+ free(buf, M_TEMP);
+ return (EINVAL);
+ }
+ len += mem_addr->descriptor_size * mem_addr->num_ents;
+ if (len > EFI_TABLE_ALLOC_MAX) {
+ free(buf, M_TEMP);
+ return (ENOMEM);
+ }
+
+ *table_len = len;
+ if (taddr != NULL)
+ *taddr = tbl_addr;
+ free(buf, M_TEMP);
+ return (0);
+ }
}
return (ENOENT);
}
@@ -457,7 +494,8 @@ copy_table(efi_guid_t *guid, void **buf, size_t buf_len, size_t *table_len)
enum efi_table_type type;
} tables[] = {
{ EFI_TABLE_ESRT, TYPE_ESRT },
- { EFI_PROPERTIES_TABLE, TYPE_PROP }
+ { EFI_PROPERTIES_TABLE, TYPE_PROP },
+ { EFI_MEMORY_ATTRIBUTES_TABLE, TYPE_MEMORY_ATTR }
};
size_t table_idx;
void *taddr;
diff --git a/sys/dev/gpio/acpi_gpiobus.c b/sys/dev/gpio/acpi_gpiobus.c
index 2987af634866..94f4e5771266 100644
--- a/sys/dev/gpio/acpi_gpiobus.c
+++ b/sys/dev/gpio/acpi_gpiobus.c
@@ -36,6 +36,7 @@
#include <dev/gpio/gpiobusvar.h>
#include <dev/gpio/acpi_gpiobusvar.h>
+#include <dev/gpio/gpiobus_internal.h>
#include "gpiobus_if.h"
@@ -356,7 +357,7 @@ acpi_gpiobus_attach(device_t dev)
status = AcpiWalkResources(handle, "_AEI", acpi_gpiobus_enumerate_aei,
&ctx);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
device_printf(dev, "Failed to enumerate AEI resources\n");
return (0);
diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c
index 2e2618805e7b..764bcb7e6ee8 100644
--- a/sys/dev/gpio/gpiobus.c
+++ b/sys/dev/gpio/gpiobus.c
@@ -39,6 +39,7 @@
#include <sys/sbuf.h>
#include <dev/gpio/gpiobusvar.h>
+#include <dev/gpio/gpiobus_internal.h>
#include "gpiobus_if.h"
@@ -109,10 +110,9 @@ gpio_alloc_intr_resource(device_t consumer_dev, int *rid, u_int alloc_flags,
res = bus_alloc_resource(consumer_dev, SYS_RES_IRQ, rid, irq, irq, 1,
alloc_flags);
if (res == NULL) {
- intr_free_intr_map_data((struct intr_map_data *)gpio_data);
+ intr_unmap_irq(irq);
return (NULL);
}
- rman_set_virtual(res, gpio_data);
return (res);
}
#else
@@ -213,20 +213,40 @@ gpio_pin_is_active(gpio_pin_t pin, bool *active)
return (0);
}
+/*
+ * Note that this function should only
+ * be used in cases where a pre-existing
+ * gpiobus_pin structure exists. In most
+ * cases, the gpio_pin_get_by_* functions
+ * suffice.
+ */
+int
+gpio_pin_acquire(gpio_pin_t gpio)
+{
+ device_t busdev;
+
+ KASSERT(gpio != NULL, ("GPIO pin is NULL."));
+ KASSERT(gpio->dev != NULL, ("GPIO pin device is NULL."));
+
+ busdev = GPIO_GET_BUS(gpio->dev);
+ if (busdev == NULL)
+ return (ENXIO);
+
+ return (gpiobus_acquire_pin(busdev, gpio->pin));
+}
+
void
gpio_pin_release(gpio_pin_t gpio)
{
device_t busdev;
- if (gpio == NULL)
- return;
-
+ KASSERT(gpio != NULL, ("GPIO pin is NULL."));
KASSERT(gpio->dev != NULL, ("GPIO pin device is NULL."));
busdev = GPIO_GET_BUS(gpio->dev);
- if (busdev != NULL)
- gpiobus_release_pin(busdev, gpio->pin);
+ KASSERT(busdev != NULL, ("gpiobus dev is NULL."));
+ gpiobus_release_pin(busdev, gpio->pin);
free(gpio, M_DEVBUF);
}
@@ -293,7 +313,7 @@ gpiobus_print_pins(struct gpiobus_ivar *devi, struct sbuf *sb)
}
device_t
-gpiobus_attach_bus(device_t dev)
+gpiobus_add_bus(device_t dev)
{
device_t busdev;
@@ -307,8 +327,24 @@ gpiobus_attach_bus(device_t dev)
#ifdef FDT
ofw_gpiobus_register_provider(dev);
#endif
- bus_attach_children(dev);
+ return (busdev);
+}
+
+/*
+ * Attach a gpiobus child.
+ * Note that the controller is expected
+ * to be fully initialized at this point.
+ */
+device_t
+gpiobus_attach_bus(device_t dev)
+{
+ device_t busdev;
+
+ busdev = gpiobus_add_bus(dev);
+ if (busdev == NULL)
+ return (NULL);
+ bus_attach_children(dev);
return (busdev);
}
@@ -385,14 +421,13 @@ gpiobus_acquire_pin(device_t bus, uint32_t pin)
sc = device_get_softc(bus);
/* Consistency check. */
if (pin >= sc->sc_npins) {
- device_printf(bus,
- "invalid pin %d, max: %d\n", pin, sc->sc_npins - 1);
- return (-1);
+ panic("%s: invalid pin %d, max: %d",
+ device_get_nameunit(bus), pin, sc->sc_npins - 1);
}
/* Mark pin as mapped and give warning if it's already mapped. */
if (sc->sc_pins[pin].mapped) {
device_printf(bus, "warning: pin %d is already mapped\n", pin);
- return (-1);
+ return (EBUSY);
}
sc->sc_pins[pin].mapped = 1;
@@ -400,7 +435,7 @@ gpiobus_acquire_pin(device_t bus, uint32_t pin)
}
/* Release mapped pin */
-int
+void
gpiobus_release_pin(device_t bus, uint32_t pin)
{
struct gpiobus_softc *sc;
@@ -408,19 +443,15 @@ gpiobus_release_pin(device_t bus, uint32_t pin)
sc = device_get_softc(bus);
/* Consistency check. */
if (pin >= sc->sc_npins) {
- device_printf(bus,
- "invalid pin %d, max=%d\n",
- pin, sc->sc_npins - 1);
- return (-1);
+ panic("%s: invalid pin %d, max: %d",
+ device_get_nameunit(bus), pin, sc->sc_npins - 1);
}
- if (!sc->sc_pins[pin].mapped) {
- device_printf(bus, "pin %d is not mapped\n", pin);
- return (-1);
- }
- sc->sc_pins[pin].mapped = 0;
+ if (!sc->sc_pins[pin].mapped)
+ panic("%s: pin %d is not mapped", device_get_nameunit(bus),
+ pin);
- return (0);
+ sc->sc_pins[pin].mapped = 0;
}
static int
@@ -435,8 +466,7 @@ gpiobus_acquire_child_pins(device_t dev, device_t child)
device_printf(child, "cannot acquire pin %d\n",
devi->pins[i]);
while (--i >= 0) {
- (void)gpiobus_release_pin(dev,
- devi->pins[i]);
+ gpiobus_release_pin(dev, devi->pins[i]);
}
gpiobus_free_ivars(devi);
return (EBUSY);
@@ -835,6 +865,25 @@ gpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid,
end, count, flags));
}
+static int
+gpiobus_release_resource(device_t dev, device_t child, struct resource *r)
+{
+ int err;
+#ifdef INTRNG
+ u_int irq;
+
+ irq = rman_get_start(r);
+ MPASS(irq == rman_get_end(r));
+#endif
+ err = bus_generic_rman_release_resource(dev, child, r);
+ if (err != 0)
+ return (err);
+#ifdef INTRNG
+ intr_unmap_irq(irq);
+#endif
+ return (0);
+}
+
static struct resource_list *
gpiobus_get_resource_list(device_t bus __unused, device_t child)
{
@@ -1029,7 +1078,7 @@ static device_method_t gpiobus_methods[] = {
DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
DEVMETHOD(bus_alloc_resource, gpiobus_alloc_resource),
- DEVMETHOD(bus_release_resource, bus_generic_rman_release_resource),
+ DEVMETHOD(bus_release_resource, gpiobus_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_rman_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_rman_deactivate_resource),
DEVMETHOD(bus_get_resource_list, gpiobus_get_resource_list),
diff --git a/sys/dev/sound/midi/sequencer.h b/sys/dev/gpio/gpiobus_internal.h
index 22ea0ae6c1b6..de3f57663132 100644
--- a/sys/dev/sound/midi/sequencer.h
+++ b/sys/dev/gpio/gpiobus_internal.h
@@ -1,8 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2003 Mathew Kanner
- * Copyright (c) 1999 Seigo Tanimura
+ * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,65 +24,24 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
*/
-/*
- * Include file for the midi sequence driver.
- */
-
-#ifndef _SEQUENCER_H_
-#define _SEQUENCER_H_
-
-#define NSEQ_MAX 16
+#ifndef __GPIOBUS_INTERNAL_H__
+#define __GPIOBUS_INTERNAL_H__
/*
- * many variables should be reduced to a range. Here define a macro
+ * Functions shared between gpiobus and other bus classes that derive from it;
+ * these should not be called directly by other drivers.
*/
-
-#define RANGE(var, low, high) (var) = \
-((var)<(low)?(low) : (var)>(high)?(high) : (var))
-
-#ifdef _KERNEL
-
-void seq_timer(void *arg);
-
-SYSCTL_DECL(_hw_midi_seq);
-
-extern int seq_debug;
-
-#define SEQ_DEBUG(y, x) \
- do { \
- if (seq_debug >= y) { \
- (x); \
- } \
- } while (0)
-
-SYSCTL_DECL(_hw_midi);
-
-#endif /* _KERNEL */
-
-#define SYNTHPROP_MIDI 1
-#define SYNTHPROP_SYNTH 2
-#define SYNTHPROP_RX 4
-#define SYNTHPROP_TX 8
-
-struct _midi_cmdtab {
- int cmd;
- char *name;
-};
-typedef struct _midi_cmdtab midi_cmdtab;
-extern midi_cmdtab cmdtab_seqevent[];
-extern midi_cmdtab cmdtab_seqioctl[];
-extern midi_cmdtab cmdtab_timer[];
-extern midi_cmdtab cmdtab_seqcv[];
-extern midi_cmdtab cmdtab_seqccmn[];
-
-char *midi_cmdname(int cmd, midi_cmdtab * tab);
-
-enum {
- MORE,
- TIMERARMED,
- QUEUEFULL
-};
-
+int gpiobus_attach(device_t);
+int gpiobus_detach(device_t);
+int gpiobus_init_softc(device_t);
+int gpiobus_alloc_ivars(struct gpiobus_ivar *);
+void gpiobus_free_ivars(struct gpiobus_ivar *);
+int gpiobus_read_ivar(device_t, device_t, int, uintptr_t *);
+int gpiobus_acquire_pin(device_t, uint32_t);
+void gpiobus_release_pin(device_t, uint32_t);
+
+extern driver_t gpiobus_driver;
#endif
diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h
index 74783e112f89..7f504236a774 100644
--- a/sys/dev/gpio/gpiobusvar.h
+++ b/sys/dev/gpio/gpiobusvar.h
@@ -156,6 +156,8 @@ int gpio_pin_get_by_bus_pinnum(device_t _bus, uint32_t _pinnum, gpio_pin_t *_gp)
/* Acquire a pin by child and index (used by direct children of gpiobus). */
int gpio_pin_get_by_child_index(device_t _child, uint32_t _idx, gpio_pin_t *_gp);
+/* Acquire a pin from an existing gpio_pin_t. */
+int gpio_pin_acquire(gpio_pin_t gpio);
/* Release a pin acquired via any gpio_pin_get_xxx() function. */
void gpio_pin_release(gpio_pin_t gpio);
@@ -167,22 +169,9 @@ int gpio_pin_setflags(gpio_pin_t pin, uint32_t flags);
struct resource *gpio_alloc_intr_resource(device_t consumer_dev, int *rid,
u_int alloc_flags, gpio_pin_t pin, uint32_t intr_mode);
-/*
- * Functions shared between gpiobus and other bus classes that derive from it;
- * these should not be called directly by other drivers.
- */
int gpio_check_flags(uint32_t, uint32_t);
+device_t gpiobus_add_bus(device_t);
device_t gpiobus_attach_bus(device_t);
int gpiobus_detach_bus(device_t);
-int gpiobus_attach(device_t);
-int gpiobus_detach(device_t);
-int gpiobus_init_softc(device_t);
-int gpiobus_alloc_ivars(struct gpiobus_ivar *);
-void gpiobus_free_ivars(struct gpiobus_ivar *);
-int gpiobus_read_ivar(device_t, device_t, int, uintptr_t *);
-int gpiobus_acquire_pin(device_t, uint32_t);
-int gpiobus_release_pin(device_t, uint32_t);
-
-extern driver_t gpiobus_driver;
#endif /* __GPIOBUS_H__ */
diff --git a/sys/dev/gpio/gpiopps.c b/sys/dev/gpio/gpiopps.c
index bb8afa5e062c..82620a50a798 100644
--- a/sys/dev/gpio/gpiopps.c
+++ b/sys/dev/gpio/gpiopps.c
@@ -160,7 +160,7 @@ gpiopps_detach(device_t dev)
if (sc->ires != NULL)
bus_release_resource(dev, SYS_RES_IRQ, sc->irid, sc->ires);
if (sc->gpin != NULL)
- gpiobus_release_pin(GPIO_GET_BUS(sc->gpin->dev), sc->gpin->pin);
+ gpio_pin_release(sc->gpin);
return (0);
}
diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c
index 32dc5b55e698..fc5fb03d6824 100644
--- a/sys/dev/gpio/ofw_gpiobus.c
+++ b/sys/dev/gpio/ofw_gpiobus.c
@@ -36,6 +36,7 @@
#include <sys/module.h>
#include <dev/gpio/gpiobusvar.h>
+#include <dev/gpio/gpiobus_internal.h>
#include <dev/ofw/ofw_bus.h>
#include "gpiobus_if.h"
diff --git a/sys/dev/gpio/pl061.c b/sys/dev/gpio/pl061.c
index cc39790322b6..87d4310a6396 100644
--- a/sys/dev/gpio/pl061.c
+++ b/sys/dev/gpio/pl061.c
@@ -487,14 +487,21 @@ pl061_attach(device_t dev)
}
}
+ mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "pl061", MTX_SPIN);
+
+ if (sc->sc_xref != 0 && !intr_pic_register(dev, sc->sc_xref)) {
+ device_printf(dev, "couldn't register PIC\n");
+ PL061_LOCK_DESTROY(sc);
+ goto free_isrc;
+ }
+
sc->sc_busdev = gpiobus_attach_bus(dev);
if (sc->sc_busdev == NULL) {
device_printf(dev, "couldn't attach gpio bus\n");
+ PL061_LOCK_DESTROY(sc);
goto free_isrc;
}
- mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "pl061", MTX_SPIN);
-
return (0);
free_isrc:
@@ -503,6 +510,7 @@ free_isrc:
* for (irq = 0; irq < PL061_NUM_GPIO; irq++)
* intr_isrc_deregister(PIC_INTR_ISRC(sc, irq));
*/
+ bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_hdlr);
bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid,
sc->sc_irq_res);
free_pic:
diff --git a/sys/dev/gpio/pl061.h b/sys/dev/gpio/pl061.h
index 809a1168493d..d9fe23e502b1 100644
--- a/sys/dev/gpio/pl061.h
+++ b/sys/dev/gpio/pl061.h
@@ -46,6 +46,7 @@ struct pl061_softc {
struct resource *sc_mem_res;
struct resource *sc_irq_res;
void *sc_irq_hdlr;
+ intptr_t sc_xref;
int sc_mem_rid;
int sc_irq_rid;
struct pl061_pin_irqsrc sc_isrcs[PL061_NUM_GPIO];
diff --git a/sys/dev/gpio/pl061_acpi.c b/sys/dev/gpio/pl061_acpi.c
index f5885025083e..8e9921261e4e 100644
--- a/sys/dev/gpio/pl061_acpi.c
+++ b/sys/dev/gpio/pl061_acpi.c
@@ -67,19 +67,12 @@ pl061_acpi_probe(device_t dev)
static int
pl061_acpi_attach(device_t dev)
{
- int error;
+ struct pl061_softc *sc;
- error = pl061_attach(dev);
- if (error != 0)
- return (error);
+ sc = device_get_softc(dev);
+ sc->sc_xref = ACPI_GPIO_XREF;
- if (!intr_pic_register(dev, ACPI_GPIO_XREF)) {
- device_printf(dev, "couldn't register PIC\n");
- pl061_detach(dev);
- error = ENXIO;
- }
-
- return (error);
+ return (pl061_attach(dev));
}
static device_method_t pl061_acpi_methods[] = {
diff --git a/sys/dev/gpio/pl061_fdt.c b/sys/dev/gpio/pl061_fdt.c
index aa22298b43c6..681b3ccdfdeb 100644
--- a/sys/dev/gpio/pl061_fdt.c
+++ b/sys/dev/gpio/pl061_fdt.c
@@ -61,19 +61,12 @@ pl061_fdt_probe(device_t dev)
static int
pl061_fdt_attach(device_t dev)
{
- int error;
+ struct pl061_softc *sc;
- error = pl061_attach(dev);
- if (error != 0)
- return (error);
+ sc = device_get_softc(dev);
+ sc->sc_xref = OF_xref_from_node(ofw_bus_get_node(dev));
- if (!intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev)))) {
- device_printf(dev, "couldn't register PIC\n");
- pl061_detach(dev);
- error = ENXIO;
- }
-
- return (error);
+ return (pl061_attach(dev));
}
static device_method_t pl061_fdt_methods[] = {
diff --git a/sys/dev/gpio/qoriq_gpio.c b/sys/dev/gpio/qoriq_gpio.c
index 25dfccede29f..8b44cd256c79 100644
--- a/sys/dev/gpio/qoriq_gpio.c
+++ b/sys/dev/gpio/qoriq_gpio.c
@@ -369,11 +369,6 @@ qoriq_gpio_attach(device_t dev)
for (i = 0; i <= MAXPIN; i++)
sc->sc_pins[i].gp_caps = DEFAULT_CAPS;
- sc->busdev = gpiobus_attach_bus(dev);
- if (sc->busdev == NULL) {
- qoriq_gpio_detach(dev);
- return (ENOMEM);
- }
/*
* Enable the GPIO Input Buffer for all GPIOs.
* This is safe on devices without a GPIBE register, because those
@@ -384,6 +379,12 @@ qoriq_gpio_attach(device_t dev)
OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
+ sc->busdev = gpiobus_attach_bus(dev);
+ if (sc->busdev == NULL) {
+ qoriq_gpio_detach(dev);
+ return (ENOMEM);
+ }
+
return (0);
}
diff --git a/sys/dev/hyperv/vmbus/vmbus_chan.c b/sys/dev/hyperv/vmbus/vmbus_chan.c
index 189a3e66a039..7ea60a499c72 100644
--- a/sys/dev/hyperv/vmbus/vmbus_chan.c
+++ b/sys/dev/hyperv/vmbus/vmbus_chan.c
@@ -1555,7 +1555,7 @@ vmbus_event_flags_proc(struct vmbus_softc *sc, volatile u_long *event_flags,
continue;
flags = atomic_swap_long(&event_flags[f], 0);
- chid_base = f << VMBUS_EVTFLAG_SHIFT;
+ chid_base = f * VMBUS_EVTFLAG_LEN;
while ((chid_ofs = ffsl(flags)) != 0) {
struct vmbus_channel *chan;
@@ -1599,7 +1599,7 @@ vmbus_event_proc_compat(struct vmbus_softc *sc, int cpu)
eventf = VMBUS_PCPU_GET(sc, event_flags, cpu) + VMBUS_SINT_MESSAGE;
if (atomic_testandclear_long(&eventf->evt_flags[0], 0)) {
vmbus_event_flags_proc(sc, sc->vmbus_rx_evtflags,
- VMBUS_CHAN_MAX_COMPAT >> VMBUS_EVTFLAG_SHIFT);
+ VMBUS_CHAN_MAX_COMPAT / VMBUS_EVTFLAG_LEN);
}
}
@@ -1903,7 +1903,7 @@ vmbus_chan_msgproc_choffer(struct vmbus_softc *sc,
* Setup event flag.
*/
chan->ch_evtflag =
- &sc->vmbus_tx_evtflags[chan->ch_id >> VMBUS_EVTFLAG_SHIFT];
+ &sc->vmbus_tx_evtflags[chan->ch_id / VMBUS_EVTFLAG_LEN];
chan->ch_evtflag_mask = 1UL << (chan->ch_id & VMBUS_EVTFLAG_MASK);
/*
diff --git a/sys/dev/hyperv/vmbus/vmbus_reg.h b/sys/dev/hyperv/vmbus/vmbus_reg.h
index 4aa729475b5d..76cdca0ebeb2 100644
--- a/sys/dev/hyperv/vmbus/vmbus_reg.h
+++ b/sys/dev/hyperv/vmbus/vmbus_reg.h
@@ -60,16 +60,10 @@ CTASSERT(sizeof(struct vmbus_message) == VMBUS_MSG_SIZE);
* Hyper-V SynIC event flags
*/
-#ifdef __LP64__
-#define VMBUS_EVTFLAGS_MAX 32
-#define VMBUS_EVTFLAG_SHIFT 6
-#else
-#define VMBUS_EVTFLAGS_MAX 64
-#define VMBUS_EVTFLAG_SHIFT 5
-#endif
-#define VMBUS_EVTFLAG_LEN (1 << VMBUS_EVTFLAG_SHIFT)
+#define VMBUS_EVTFLAG_LEN (sizeof(u_long) * 8)
#define VMBUS_EVTFLAG_MASK (VMBUS_EVTFLAG_LEN - 1)
#define VMBUS_EVTFLAGS_SIZE 256
+#define VMBUS_EVTFLAGS_MAX (VMBUS_EVTFLAGS_SIZE / sizeof(u_long))
struct vmbus_evtflags {
u_long evt_flags[VMBUS_EVTFLAGS_MAX];
diff --git a/sys/dev/ice/ice_features.h b/sys/dev/ice/ice_features.h
index 821abe4806ca..5b23757b1c98 100644
--- a/sys/dev/ice/ice_features.h
+++ b/sys/dev/ice/ice_features.h
@@ -91,7 +91,9 @@ enum feat_list {
static inline void
ice_disable_unsupported_features(ice_bitmap_t __unused *bitmap)
{
+#ifndef PCI_IOV
ice_clear_bit(ICE_FEATURE_SRIOV, bitmap);
+#endif
#ifndef DEV_NETMAP
ice_clear_bit(ICE_FEATURE_NETMAP, bitmap);
#endif
diff --git a/sys/dev/ice/ice_iflib.h b/sys/dev/ice/ice_iflib.h
index 3a5dc201189a..e1d5307a9516 100644
--- a/sys/dev/ice/ice_iflib.h
+++ b/sys/dev/ice/ice_iflib.h
@@ -139,6 +139,9 @@ struct ice_irq_vector {
* @tc: traffic class queue belongs to
* @q_handle: qidx in tc; used in TXQ enable functions
*
+ * ice_iov.c requires the following parameters (when PCI_IOV is defined):
+ * @itr_idx: ITR index to use for this queue
+ *
* Other parameters may be iflib driver specific
*/
struct ice_tx_queue {
@@ -153,6 +156,9 @@ struct ice_tx_queue {
u32 me;
u16 q_handle;
u8 tc;
+#ifdef PCI_IOV
+ u8 itr_idx;
+#endif
/* descriptor writeback status */
qidx_t *tx_rsq;
@@ -175,6 +181,9 @@ struct ice_tx_queue {
* @stats: queue statistics
* @tc: traffic class queue belongs to
*
+ * ice_iov.c requires the following parameters (when PCI_IOV is defined):
+ * @itr_idx: ITR index to use for this queue
+ *
* Other parameters may be iflib driver specific
*/
struct ice_rx_queue {
@@ -187,6 +196,9 @@ struct ice_rx_queue {
struct ice_irq_vector *irqv;
u32 me;
u8 tc;
+#ifdef PCI_IOV
+ u8 itr_idx;
+#endif
struct if_irq que_irq;
};
@@ -332,6 +344,10 @@ struct ice_softc {
ice_declare_bitmap(feat_cap, ICE_FEATURE_COUNT);
ice_declare_bitmap(feat_en, ICE_FEATURE_COUNT);
+#ifdef PCI_IOV
+ struct ice_vf *vfs;
+ u16 num_vfs;
+#endif
struct ice_resmgr os_imgr;
/* For mirror interface */
struct ice_mirr_if *mirr_if;
diff --git a/sys/dev/ice/ice_iov.c b/sys/dev/ice/ice_iov.c
new file mode 100644
index 000000000000..c5a3e1060e44
--- /dev/null
+++ b/sys/dev/ice/ice_iov.c
@@ -0,0 +1,1856 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file ice_iov.c
+ * @brief Virtualization support functions
+ *
+ * Contains functions for enabling and managing PCIe virtual function devices,
+ * including enabling new VFs, and managing VFs over the virtchnl interface.
+ */
+
+#include "ice_iov.h"
+
+static struct ice_vf *ice_iov_get_vf(struct ice_softc *sc, int vf_num);
+static void ice_iov_ready_vf(struct ice_softc *sc, struct ice_vf *vf);
+static void ice_reset_vf(struct ice_softc *sc, struct ice_vf *vf,
+ bool trigger_vflr);
+static void ice_iov_setup_intr_mapping(struct ice_softc *sc, struct ice_vf *vf);
+
+static void ice_vc_version_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_get_vf_res_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_add_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_del_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static bool ice_vc_isvalid_ring_len(u16 ring_len);
+static void ice_vc_cfg_vsi_qs_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_cfg_rss_key_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_set_rss_hena_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_enable_queues_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_notify_vf_link_state(struct ice_softc *sc, struct ice_vf *vf);
+static void ice_vc_disable_queues_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_cfg_irq_map_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_get_stats_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_eth_stats_to_virtchnl_eth_stats(struct ice_eth_stats *istats,
+ struct virtchnl_eth_stats *vstats);
+static void ice_vc_cfg_rss_lut_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_cfg_promisc_mode_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_add_vlan_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_del_vlan_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static enum virtchnl_status_code ice_iov_err_to_virt_err(int ice_err);
+static int ice_vf_validate_mac(struct ice_vf *vf, const uint8_t *addr);
+
+/**
+ * ice_iov_attach - Initialize SR-IOV PF host support
+ * @sc: device softc structure
+ *
+ * Initialize SR-IOV PF host support at the end of the driver attach process.
+ *
+ * @pre Must be called from sleepable context (calls malloc() w/ M_WAITOK)
+ *
+ * @returns 0 if successful, or
+ * - ENOMEM if there is no memory for the PF/VF schemas or iov device
+ * - ENXIO if the device isn't PCI-E or doesn't support the same SR-IOV
+ * version as the kernel
+ * - ENOENT if the device doesn't have the SR-IOV capability
+ */
+int
+ice_iov_attach(struct ice_softc *sc)
+{
+ device_t dev = sc->dev;
+ nvlist_t *pf_schema, *vf_schema;
+ int error;
+
+ pf_schema = pci_iov_schema_alloc_node();
+ vf_schema = pci_iov_schema_alloc_node();
+
+ pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
+ pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
+ IOV_SCHEMA_HASDEFAULT, TRUE);
+ pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
+ IOV_SCHEMA_HASDEFAULT, FALSE);
+ pci_iov_schema_add_bool(vf_schema, "allow-promisc",
+ IOV_SCHEMA_HASDEFAULT, FALSE);
+ pci_iov_schema_add_uint16(vf_schema, "num-queues",
+ IOV_SCHEMA_HASDEFAULT, ICE_DEFAULT_VF_QUEUES);
+ pci_iov_schema_add_uint16(vf_schema, "mirror-src-vsi",
+ IOV_SCHEMA_HASDEFAULT, ICE_INVALID_MIRROR_VSI);
+ pci_iov_schema_add_uint16(vf_schema, "max-vlan-allowed",
+ IOV_SCHEMA_HASDEFAULT, ICE_DEFAULT_VF_VLAN_LIMIT);
+ pci_iov_schema_add_uint16(vf_schema, "max-mac-filters",
+ IOV_SCHEMA_HASDEFAULT, ICE_DEFAULT_VF_FILTER_LIMIT);
+
+ error = pci_iov_attach(dev, pf_schema, vf_schema);
+ if (error != 0) {
+ device_printf(dev,
+ "pci_iov_attach failed (error=%s)\n",
+ ice_err_str(error));
+ ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en);
+ } else
+ ice_set_bit(ICE_FEATURE_SRIOV, sc->feat_en);
+
+ return (error);
+}
+
+/**
+ * ice_iov_detach - Teardown SR-IOV PF host support
+ * @sc: device softc structure
+ *
+ * Teardown SR-IOV PF host support at the start of the driver detach process.
+ *
+ * @returns 0 if successful or IOV support hasn't been setup, or
+ * - EBUSY if VFs still exist
+ */
+int
+ice_iov_detach(struct ice_softc *sc)
+{
+ device_t dev = sc->dev;
+ int error;
+
+ error = pci_iov_detach(dev);
+ if (error != 0) {
+ device_printf(dev,
+ "pci_iov_detach failed (error=%s)\n",
+ ice_err_str(error));
+ }
+
+ return (error);
+}
+
+/**
+ * ice_iov_init - Called by the OS before the first VF is created.
+ * @sc: device softc structure
+ * @num_vfs: number of VFs to setup resources for
+ * @params: configuration parameters for the PF
+ *
+ * @returns 0 if successful or an error code on failure
+ */
+int
+ice_iov_init(struct ice_softc *sc, uint16_t num_vfs, const nvlist_t *params __unused)
+{
+ /* Allocate array of VFs, for tracking */
+ sc->vfs = (struct ice_vf *)malloc(sizeof(struct ice_vf) * num_vfs, M_ICE, M_NOWAIT |
+ M_ZERO);
+ if (sc->vfs == NULL)
+ return (ENOMEM);
+
+ /* Initialize each VF with basic information */
+ for (int i = 0; i < num_vfs; i++)
+ sc->vfs[i].vf_num = i;
+
+ /* Save off number of configured VFs */
+ sc->num_vfs = num_vfs;
+
+ return (0);
+}
+
+/**
+ * ice_iov_get_vf - Get pointer to VF at given index
+ * @sc: device softc structure
+ * @vf_num: Index of VF to retrieve
+ *
+ * @remark will throw an assertion if vf_num is not in the
+ * range of allocated VFs
+ *
+ * @returns a pointer to the VF structure at the given index
+ */
+static struct ice_vf *
+ice_iov_get_vf(struct ice_softc *sc, int vf_num)
+{
+ MPASS(vf_num < sc->num_vfs);
+
+ return &sc->vfs[vf_num];
+}
+
+/**
+ * ice_iov_add_vf - Called by the OS for each VF to create
+ * @sc: device softc structure
+ * @vfnum: index of VF to configure
+ * @params: configuration parameters for the VF
+ *
+ * @returns 0 if successful or an error code on failure
+ */
+int
+ice_iov_add_vf(struct ice_softc *sc, uint16_t vfnum, const nvlist_t *params)
+{
+ struct ice_tx_queue *txq;
+ struct ice_rx_queue *rxq;
+ device_t dev = sc->dev;
+ struct ice_vsi *vsi;
+ struct ice_vf *vf;
+ int vf_num_queues;
+ const void *mac;
+ size_t size;
+ int error;
+ int i;
+
+ vf = ice_iov_get_vf(sc, vfnum);
+ vf->vf_flags = VF_FLAG_ENABLED;
+
+ /* This VF needs at least one VSI */
+ vsi = ice_alloc_vsi(sc, ICE_VSI_VF);
+ if (vsi == NULL)
+ return (ENOMEM);
+ vf->vsi = vsi;
+ vsi->vf_num = vfnum;
+
+ vf_num_queues = nvlist_get_number(params, "num-queues");
+ /* Validate and clamp value if invalid */
+ if (vf_num_queues < 1 || vf_num_queues > ICE_MAX_SCATTERED_QUEUES)
+ device_printf(dev, "Invalid num-queues (%d) for VF %d\n",
+ vf_num_queues, vf->vf_num);
+ if (vf_num_queues < 1) {
+ device_printf(dev, "Setting VF %d num-queues to 1\n", vf->vf_num);
+ vf_num_queues = 1;
+ } else if (vf_num_queues > ICE_MAX_SCATTERED_QUEUES) {
+ device_printf(dev, "Setting VF %d num-queues to %d\n",
+ vf->vf_num, ICE_MAX_SCATTERED_QUEUES);
+ vf_num_queues = ICE_MAX_SCATTERED_QUEUES;
+ }
+ vsi->qmap_type = ICE_RESMGR_ALLOC_SCATTERED;
+
+ /* Reserve VF queue allocation from PF queues */
+ ice_alloc_vsi_qmap(vsi, vf_num_queues, vf_num_queues);
+ vsi->num_tx_queues = vsi->num_rx_queues = vf_num_queues;
+
+ /* Assign Tx queues from PF space */
+ error = ice_resmgr_assign_scattered(&sc->tx_qmgr, vsi->tx_qmap,
+ vsi->num_tx_queues);
+ if (error) {
+ device_printf(sc->dev, "Unable to assign VF Tx queues: %s\n",
+ ice_err_str(error));
+ goto release_vsi;
+ }
+
+ /* Assign Rx queues from PF space */
+ error = ice_resmgr_assign_scattered(&sc->rx_qmgr, vsi->rx_qmap,
+ vsi->num_rx_queues);
+ if (error) {
+ device_printf(sc->dev, "Unable to assign VF Rx queues: %s\n",
+ ice_err_str(error));
+ goto release_vsi;
+ }
+
+ vsi->max_frame_size = ICE_MAX_FRAME_SIZE;
+
+ /* Allocate queue structure memory */
+ vsi->tx_queues = (struct ice_tx_queue *)
+ malloc(sizeof(struct ice_tx_queue) * vsi->num_tx_queues, M_ICE,
+ M_NOWAIT | M_ZERO);
+ if (!vsi->tx_queues) {
+ device_printf(sc->dev, "VF-%d: Unable to allocate Tx queue memory\n",
+ vfnum);
+ error = ENOMEM;
+ goto release_vsi;
+ }
+ for (i = 0, txq = vsi->tx_queues; i < vsi->num_tx_queues; i++, txq++) {
+ txq->me = i;
+ txq->vsi = vsi;
+ }
+
+ /* Allocate queue structure memory */
+ vsi->rx_queues = (struct ice_rx_queue *)
+ malloc(sizeof(struct ice_rx_queue) * vsi->num_rx_queues, M_ICE,
+ M_NOWAIT | M_ZERO);
+ if (!vsi->rx_queues) {
+ device_printf(sc->dev, "VF-%d: Unable to allocate Rx queue memory\n",
+ vfnum);
+ error = ENOMEM;
+ goto free_txqs;
+ }
+ for (i = 0, rxq = vsi->rx_queues; i < vsi->num_rx_queues; i++, rxq++) {
+ rxq->me = i;
+ rxq->vsi = vsi;
+ }
+
+ /* Allocate space to store the IRQ vector data */
+ vf->num_irq_vectors = vf_num_queues + 1;
+ vf->tx_irqvs = (struct ice_irq_vector *)
+ malloc(sizeof(struct ice_irq_vector) * (vf->num_irq_vectors),
+ M_ICE, M_NOWAIT);
+ if (!vf->tx_irqvs) {
+ device_printf(sc->dev,
+ "Unable to allocate TX irqv memory for VF-%d's %d vectors\n",
+ vfnum, vf->num_irq_vectors);
+ error = ENOMEM;
+ goto free_rxqs;
+ }
+ vf->rx_irqvs = (struct ice_irq_vector *)
+ malloc(sizeof(struct ice_irq_vector) * (vf->num_irq_vectors),
+ M_ICE, M_NOWAIT);
+ if (!vf->rx_irqvs) {
+ device_printf(sc->dev,
+ "Unable to allocate RX irqv memory for VF-%d's %d vectors\n",
+ vfnum, vf->num_irq_vectors);
+ error = ENOMEM;
+ goto free_txirqvs;
+ }
+
+ /* Assign VF interrupts from PF space */
+ if (!(vf->vf_imap =
+ (u16 *)malloc(sizeof(u16) * vf->num_irq_vectors,
+ M_ICE, M_NOWAIT))) {
+ device_printf(dev, "Unable to allocate VF-%d imap memory\n", vfnum);
+ error = ENOMEM;
+ goto free_rxirqvs;
+ }
+ error = ice_resmgr_assign_contiguous(&sc->dev_imgr, vf->vf_imap, vf->num_irq_vectors);
+ if (error) {
+ device_printf(dev, "Unable to assign VF-%d interrupt mapping: %s\n",
+ vfnum, ice_err_str(error));
+ goto free_imap;
+ }
+
+ if (nvlist_exists_binary(params, "mac-addr")) {
+ mac = nvlist_get_binary(params, "mac-addr", &size);
+ memcpy(vf->mac, mac, ETHER_ADDR_LEN);
+
+ if (nvlist_get_bool(params, "allow-set-mac"))
+ vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
+ } else
+ /*
+ * If the administrator has not specified a MAC address then
+ * we must allow the VF to choose one.
+ */
+ vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
+
+ if (nvlist_get_bool(params, "mac-anti-spoof"))
+ vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF;
+
+ if (nvlist_get_bool(params, "allow-promisc"))
+ vf->vf_flags |= VF_FLAG_PROMISC_CAP;
+
+ vsi->mirror_src_vsi = nvlist_get_number(params, "mirror-src-vsi");
+
+ vf->vlan_limit = nvlist_get_number(params, "max-vlan-allowed");
+ vf->mac_filter_limit = nvlist_get_number(params, "max-mac-filters");
+
+ vf->vf_flags |= VF_FLAG_VLAN_CAP;
+
+ /* Create and setup VSI in HW */
+ error = ice_initialize_vsi(vsi);
+ if (error) {
+ device_printf(sc->dev, "Unable to initialize VF %d VSI: %s\n",
+ vfnum, ice_err_str(error));
+ goto release_imap;
+ }
+
+ /* Add the broadcast address */
+ error = ice_add_vsi_mac_filter(vsi, broadcastaddr);
+ if (error) {
+ device_printf(sc->dev, "Unable to add broadcast filter VF %d VSI: %s\n",
+ vfnum, ice_err_str(error));
+ goto release_imap;
+ }
+
+ ice_iov_ready_vf(sc, vf);
+
+ return (0);
+
+release_imap:
+ ice_resmgr_release_map(&sc->dev_imgr, vf->vf_imap,
+ vf->num_irq_vectors);
+free_imap:
+ free(vf->vf_imap, M_ICE);
+ vf->vf_imap = NULL;
+free_rxirqvs:
+ free(vf->rx_irqvs, M_ICE);
+ vf->rx_irqvs = NULL;
+free_txirqvs:
+ free(vf->tx_irqvs, M_ICE);
+ vf->tx_irqvs = NULL;
+free_rxqs:
+ free(vsi->rx_queues, M_ICE);
+ vsi->rx_queues = NULL;
+free_txqs:
+ free(vsi->tx_queues, M_ICE);
+ vsi->tx_queues = NULL;
+release_vsi:
+ ice_release_vsi(vsi);
+ vf->vsi = NULL;
+ return (error);
+}
+
+/**
+ * ice_iov_uninit - Called by the OS when VFs are destroyed
+ * @sc: device softc structure
+ */
+void
+ice_iov_uninit(struct ice_softc *sc)
+{
+ struct ice_vf *vf;
+ struct ice_vsi *vsi;
+
+ /* Release per-VF resources */
+ for (int i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ vsi = vf->vsi;
+
+ /* Free VF interrupt reservation */
+ if (vf->vf_imap) {
+ free(vf->vf_imap, M_ICE);
+ vf->vf_imap = NULL;
+ }
+
+ /* Free queue interrupt mapping trackers */
+ if (vf->tx_irqvs) {
+ free(vf->tx_irqvs, M_ICE);
+ vf->tx_irqvs = NULL;
+ }
+ if (vf->rx_irqvs) {
+ free(vf->rx_irqvs, M_ICE);
+ vf->rx_irqvs = NULL;
+ }
+
+ if (!vsi)
+ continue;
+
+ /* Free VSI queues */
+ if (vsi->tx_queues) {
+ free(vsi->tx_queues, M_ICE);
+ vsi->tx_queues = NULL;
+ }
+ if (vsi->rx_queues) {
+ free(vsi->rx_queues, M_ICE);
+ vsi->rx_queues = NULL;
+ }
+
+ ice_release_vsi(vsi);
+ vf->vsi = NULL;
+ }
+
+ /* Release memory used for VF tracking */
+ if (sc->vfs) {
+ free(sc->vfs, M_ICE);
+ sc->vfs = NULL;
+ }
+ sc->num_vfs = 0;
+}
+
+/**
+ * ice_iov_handle_vflr - Process VFLR event
+ * @sc: device softc structure
+ *
+ * Identifys which VFs have been reset and re-configure
+ * them.
+ */
+void
+ice_iov_handle_vflr(struct ice_softc *sc)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct ice_vf *vf;
+ u32 reg, reg_idx, bit_idx;
+
+ for (int i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+
+ reg_idx = (hw->func_caps.vf_base_id + vf->vf_num) / 32;
+ bit_idx = (hw->func_caps.vf_base_id + vf->vf_num) % 32;
+ reg = rd32(hw, GLGEN_VFLRSTAT(reg_idx));
+ if (reg & BIT(bit_idx))
+ ice_reset_vf(sc, vf, false);
+ }
+}
+
+/**
+ * ice_iov_ready_vf - Setup VF interrupts and mark it as ready
+ * @sc: device softc structure
+ * @vf: driver's VF structure for the VF to update
+ *
+ * Clears VF reset triggering bit, sets up the PF<->VF interrupt
+ * mapping and marks the VF as active in the HW so that the VF
+ * driver can use it.
+ */
+static void
+ice_iov_ready_vf(struct ice_softc *sc, struct ice_vf *vf)
+{
+ struct ice_hw *hw = &sc->hw;
+ u32 reg;
+
+ /* Clear the triggering bit */
+ reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_num));
+ reg &= ~VPGEN_VFRTRIG_VFSWR_M;
+ wr32(hw, VPGEN_VFRTRIG(vf->vf_num), reg);
+
+ /* Setup VF interrupt allocation and mapping */
+ ice_iov_setup_intr_mapping(sc, vf);
+
+ /* Indicate to the VF that reset is done */
+ wr32(hw, VFGEN_RSTAT(vf->vf_num), VIRTCHNL_VFR_VFACTIVE);
+
+ ice_flush(hw);
+}
+
+/**
+ * ice_reset_vf - Perform a hardware reset (VFR) on a VF
+ * @sc: device softc structure
+ * @vf: driver's VF structure for VF to be reset
+ * @trigger_vflr: trigger a reset or only handle already executed reset
+ *
+ * Performs a VFR for the given VF. This function busy waits until the
+ * reset completes in the HW, notifies the VF that the reset is done
+ * by setting a bit in a HW register, then returns.
+ *
+ * @remark This also sets up the PF<->VF interrupt mapping and allocations in
+ * the hardware after the hardware reset is finished, via
+ * ice_iov_setup_intr_mapping()
+ */
+static void
+ice_reset_vf(struct ice_softc *sc, struct ice_vf *vf, bool trigger_vflr)
+{
+ u16 global_vf_num, reg_idx, bit_idx;
+ struct ice_hw *hw = &sc->hw;
+ int status;
+ u32 reg;
+ int i;
+
+ global_vf_num = vf->vf_num + hw->func_caps.vf_base_id;
+
+ if (trigger_vflr) {
+ reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_num));
+ reg |= VPGEN_VFRTRIG_VFSWR_M;
+ wr32(hw, VPGEN_VFRTRIG(vf->vf_num), reg);
+ }
+
+ /* clear the VFLR bit for the VF in a GLGEN_VFLRSTAT register */
+ reg_idx = (global_vf_num) / 32;
+ bit_idx = (global_vf_num) % 32;
+ wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
+ ice_flush(hw);
+
+ /* Wait until there are no pending PCI transactions */
+ wr32(hw, PF_PCI_CIAA,
+ ICE_PCIE_DEV_STATUS | (global_vf_num << PF_PCI_CIAA_VF_NUM_S));
+
+ for (i = 0; i < ICE_PCI_CIAD_WAIT_COUNT; i++) {
+ reg = rd32(hw, PF_PCI_CIAD);
+ if (!(reg & PCIEM_STA_TRANSACTION_PND))
+ break;
+
+ DELAY(ICE_PCI_CIAD_WAIT_DELAY_US);
+ }
+ if (i == ICE_PCI_CIAD_WAIT_COUNT)
+ device_printf(sc->dev,
+ "VF-%d PCI transactions stuck\n", vf->vf_num);
+
+ /* Disable TX queues, which is required during VF reset */
+ status = ice_dis_vsi_txq(hw->port_info, vf->vsi->idx, 0, 0, NULL, NULL,
+ NULL, ICE_VF_RESET, vf->vf_num, NULL);
+ if (status)
+ device_printf(sc->dev,
+ "%s: Failed to disable LAN Tx queues: err %s aq_err %s\n",
+ __func__, ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+
+ /* Then check for the VF reset to finish in HW */
+ for (i = 0; i < ICE_VPGEN_VFRSTAT_WAIT_COUNT; i++) {
+ reg = rd32(hw, VPGEN_VFRSTAT(vf->vf_num));
+ if ((reg & VPGEN_VFRSTAT_VFRD_M))
+ break;
+
+ DELAY(ICE_VPGEN_VFRSTAT_WAIT_DELAY_US);
+ }
+ if (i == ICE_VPGEN_VFRSTAT_WAIT_COUNT)
+ device_printf(sc->dev,
+ "VF-%d Reset is stuck\n", vf->vf_num);
+
+ ice_iov_ready_vf(sc, vf);
+}
+
+/**
+ * ice_vc_get_vf_res_msg - Handle VIRTCHNL_OP_GET_VF_RESOURCES msg from VF
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Receives a message from the VF listing its supported capabilities, and
+ * replies to the VF with information about what resources the PF has
+ * allocated for the VF.
+ *
+ * @remark This always replies to the VF with a success status; it does not
+ * fail. It's up to the VF driver to reject or complain about the PF's response.
+ */
+static void
+ice_vc_get_vf_res_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_vf_resource *vf_res;
+ struct virtchnl_vsi_resource *vsi_res;
+ u16 vf_res_len;
+ u32 vf_caps;
+
+ /* XXX: Only support one VSI per VF, so this size doesn't need adjusting */
+ vf_res_len = sizeof(struct virtchnl_vf_resource);
+ vf_res = (struct virtchnl_vf_resource *)malloc(vf_res_len, M_ICE,
+ M_WAITOK | M_ZERO);
+
+ vf_res->num_vsis = 1;
+ vf_res->num_queue_pairs = vf->vsi->num_tx_queues;
+ vf_res->max_vectors = vf_res->num_queue_pairs + 1;
+
+ vf_res->rss_key_size = ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE;
+ vf_res->rss_lut_size = ICE_VSIQF_HLUT_ARRAY_SIZE;
+ vf_res->max_mtu = 0;
+
+ vf_res->vf_cap_flags = VF_BASE_MODE_OFFLOADS;
+ if (msg_buf != NULL) {
+ vf_caps = *((u32 *)(msg_buf));
+
+ if (vf_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
+ vf_res->vf_cap_flags |= VIRTCHNL_VF_CAP_ADV_LINK_SPEED;
+
+ if (vf_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
+ vf_res->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_WB_ON_ITR;
+ }
+
+ vsi_res = &vf_res->vsi_res[0];
+ vsi_res->vsi_id = vf->vsi->idx;
+ vsi_res->num_queue_pairs = vf->vsi->num_tx_queues;
+ vsi_res->vsi_type = VIRTCHNL_VSI_SRIOV;
+ vsi_res->qset_handle = 0;
+ if (!ETHER_IS_ZERO(vf->mac))
+ memcpy(vsi_res->default_mac_addr, vf->mac, ETHER_ADDR_LEN);
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_GET_VF_RESOURCES,
+ VIRTCHNL_STATUS_SUCCESS, (u8 *)vf_res, vf_res_len, NULL);
+
+ free(vf_res, M_ICE);
+}
+
+/**
+ * ice_vc_version_msg - Handle VIRTCHNL_OP_VERSION msg from VF
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Receives a version message from the VF, and responds to the VF with
+ * the version number that the PF will use.
+ *
+ * @remark This always replies to the VF with a success status; it does not
+ * fail.
+ */
+static void
+ice_vc_version_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct virtchnl_version_info *recv_vf_version;
+ struct ice_hw *hw = &sc->hw;
+ device_t dev = sc->dev;
+
+ recv_vf_version = (struct virtchnl_version_info *)msg_buf;
+
+ /* VFs running the 1.0 API expect to get 1.0 back */
+ if (VF_IS_V10(recv_vf_version)) {
+ vf->version.major = 1;
+ vf->version.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS;
+ } else {
+ vf->version.major = VIRTCHNL_VERSION_MAJOR;
+ vf->version.minor = VIRTCHNL_VERSION_MINOR;
+
+ if ((recv_vf_version->major != VIRTCHNL_VERSION_MAJOR) ||
+ (recv_vf_version->minor != VIRTCHNL_VERSION_MINOR))
+ device_printf(dev,
+ "%s: VF-%d requested version (%d.%d) differs from PF version (%d.%d)\n",
+ __func__, vf->vf_num,
+ recv_vf_version->major, recv_vf_version->minor,
+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+ }
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_VERSION,
+ VIRTCHNL_STATUS_SUCCESS, (u8 *)&vf->version, sizeof(vf->version),
+ NULL);
+}
+
+/**
+ * ice_vf_validate_mac - Validate MAC address before adding it
+ * @vf: VF tracking structure
+ * @addr: MAC address to validate
+ *
+ * Validate a MAC address before adding it to a VF during the handling
+ * of a VIRTCHNL_OP_ADD_ETH_ADDR operation. Notably, this also checks if
+ * the VF is allowed to set its own arbitrary MAC addresses.
+ *
+ * Returns 0 if MAC address is valid for the given vf
+ */
+static int
+ice_vf_validate_mac(struct ice_vf *vf, const uint8_t *addr)
+{
+
+ if (ETHER_IS_ZERO(addr) || ETHER_IS_BROADCAST(addr))
+ return (EINVAL);
+
+ /*
+ * If the VF is not allowed to change its MAC address, don't let it
+ * set a MAC filter for an address that is not a multicast address and
+ * is not its assigned MAC.
+ */
+ if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
+ !(ETHER_IS_MULTICAST(addr) || !bcmp(addr, vf->mac, ETHER_ADDR_LEN)))
+ return (EPERM);
+
+ return (0);
+}
+
+/**
+ * ice_vc_add_eth_addr_msg - Handle VIRTCHNL_OP_ADD_ETH_ADDR msg from VF
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Receives a list of MAC addresses from the VF and adds those addresses
+ * to the VSI's filter list.
+ */
+static void
+ice_vc_add_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct virtchnl_ether_addr_list *addr_list;
+ struct ice_hw *hw = &sc->hw;
+ u16 added_addr_cnt = 0;
+ int error = 0;
+
+ addr_list = (struct virtchnl_ether_addr_list *)msg_buf;
+
+ if (addr_list->num_elements >
+ (vf->mac_filter_limit - vf->mac_filter_cnt)) {
+ v_status = VIRTCHNL_STATUS_ERR_NO_MEMORY;
+ goto done;
+ }
+
+ for (int i = 0; i < addr_list->num_elements; i++) {
+ u8 *addr = addr_list->list[i].addr;
+
+ /* The type flag is currently ignored; every MAC address is
+ * treated as the LEGACY type
+ */
+
+ error = ice_vf_validate_mac(vf, addr);
+ if (error == EPERM) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Not permitted to add MAC addr for VSI %d\n",
+ __func__, vf->vf_num, vf->vsi->idx);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ continue;
+ } else if (error) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Did not add invalid MAC addr for VSI %d\n",
+ __func__, vf->vf_num, vf->vsi->idx);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ continue;
+ }
+
+ error = ice_add_vsi_mac_filter(vf->vsi, addr);
+ if (error) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Error adding MAC addr for VSI %d\n",
+ __func__, vf->vf_num, vf->vsi->idx);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ continue;
+ }
+ /* Don't count VF's MAC against its MAC filter limit */
+ if (memcmp(addr, vf->mac, ETHER_ADDR_LEN))
+ added_addr_cnt++;
+ }
+
+ vf->mac_filter_cnt += added_addr_cnt;
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_ADD_ETH_ADDR,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_del_eth_addr_msg - Handle VIRTCHNL_OP_DEL_ETH_ADDR msg from VF
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Receives a list of MAC addresses from the VF and removes those addresses
+ * from the VSI's filter list.
+ */
+static void
+ice_vc_del_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct virtchnl_ether_addr_list *addr_list;
+ struct ice_hw *hw = &sc->hw;
+ u16 deleted_addr_cnt = 0;
+ int error = 0;
+
+ addr_list = (struct virtchnl_ether_addr_list *)msg_buf;
+
+ for (int i = 0; i < addr_list->num_elements; i++) {
+ error = ice_remove_vsi_mac_filter(vf->vsi, addr_list->list[i].addr);
+ if (error) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Error removing MAC addr for VSI %d\n",
+ __func__, vf->vf_num, vf->vsi->idx);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ continue;
+ }
+ /* Don't count VF's MAC against its MAC filter limit */
+ if (memcmp(addr_list->list[i].addr, vf->mac, ETHER_ADDR_LEN))
+ deleted_addr_cnt++;
+ }
+
+ if (deleted_addr_cnt >= vf->mac_filter_cnt)
+ vf->mac_filter_cnt = 0;
+ else
+ vf->mac_filter_cnt -= deleted_addr_cnt;
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_DEL_ETH_ADDR,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_add_vlan_msg - Handle VIRTCHNL_OP_ADD_VLAN msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Adds the VLANs in msg_buf to the VF's VLAN filter list.
+ */
+static void
+ice_vc_add_vlan_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_vlan_filter_list *vlan_list;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+
+ vlan_list = (struct virtchnl_vlan_filter_list *)msg_buf;
+
+ if (vlan_list->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vlan_list->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if (vlan_list->num_elements > (vf->vlan_limit - vf->vlan_cnt)) {
+ v_status = VIRTCHNL_STATUS_ERR_NO_MEMORY;
+ goto done;
+ }
+
+ status = ice_add_vlan_hw_filters(vsi, vlan_list->vlan_id,
+ vlan_list->num_elements);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failure adding VLANs to VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx, ice_status_str(status),
+ ice_aq_str(sc->hw.adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+
+ vf->vlan_cnt += vlan_list->num_elements;
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_ADD_VLAN,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_del_vlan_msg - Handle VIRTCHNL_OP_DEL_VLAN msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Removes the VLANs in msg_buf from the VF's VLAN filter list.
+ */
+static void
+ice_vc_del_vlan_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_vlan_filter_list *vlan_list;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+
+ vlan_list = (struct virtchnl_vlan_filter_list *)msg_buf;
+
+ if (vlan_list->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vlan_list->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ status = ice_remove_vlan_hw_filters(vsi, vlan_list->vlan_id,
+ vlan_list->num_elements);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failure deleting VLANs from VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx, ice_status_str(status),
+ ice_aq_str(sc->hw.adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+
+ if (vlan_list->num_elements >= vf->vlan_cnt)
+ vf->vlan_cnt = 0;
+ else
+ vf->vlan_cnt -= vlan_list->num_elements;
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_DEL_VLAN,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_validate_ring_len - Check to see if a descriptor ring length is valid
+ * @ring_len: length of ring
+ *
+ * Check whether a ring size value is valid.
+ *
+ * @returns true if given ring size is valid
+ */
+static bool
+ice_vc_isvalid_ring_len(u16 ring_len)
+{
+ return (ring_len >= ICE_MIN_DESC_COUNT &&
+ ring_len <= ICE_MAX_DESC_COUNT &&
+ !(ring_len % ICE_DESC_COUNT_INCR));
+}
+
+/**
+ * ice_vc_cfg_vsi_qs_msg - Handle VIRTCHNL_OP_CONFIG_VSI_QUEUES msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ */
+static void
+ice_vc_cfg_vsi_qs_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ device_t dev = sc->dev;
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_vsi_queue_config_info *vqci;
+ struct virtchnl_queue_pair_info *vqpi;
+ enum virtchnl_status_code status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+ struct ice_tx_queue *txq;
+ struct ice_rx_queue *rxq;
+ int i, error = 0;
+
+ vqci = (struct virtchnl_vsi_queue_config_info *)msg_buf;
+
+ if (vqci->num_queue_pairs > vf->vsi->num_tx_queues &&
+ vqci->num_queue_pairs > vf->vsi->num_rx_queues) {
+ status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ ice_vsi_disable_tx(vf->vsi);
+ ice_control_all_rx_queues(vf->vsi, false);
+
+ /*
+ * Clear TX and RX queues config in case VF
+ * requests different number of queues.
+ */
+ for (i = 0; i < vsi->num_tx_queues; i++) {
+ txq = &vsi->tx_queues[i];
+
+ txq->desc_count = 0;
+ txq->tx_paddr = 0;
+ txq->tc = 0;
+ }
+
+ for (i = 0; i < vsi->num_rx_queues; i++) {
+ rxq = &vsi->rx_queues[i];
+
+ rxq->desc_count = 0;
+ rxq->rx_paddr = 0;
+ }
+
+ vqpi = vqci->qpair;
+ for (i = 0; i < vqci->num_queue_pairs; i++, vqpi++) {
+ /* Initial parameter validation */
+ if (vqpi->txq.vsi_id != vf->vsi->idx ||
+ vqpi->rxq.vsi_id != vf->vsi->idx ||
+ vqpi->txq.queue_id != vqpi->rxq.queue_id ||
+ vqpi->txq.headwb_enabled ||
+ vqpi->rxq.splithdr_enabled ||
+ vqpi->rxq.crc_disable ||
+ !(ice_vc_isvalid_ring_len(vqpi->txq.ring_len)) ||
+ !(ice_vc_isvalid_ring_len(vqpi->rxq.ring_len))) {
+ status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* Copy parameters into VF's queue/VSI structs */
+ txq = &vsi->tx_queues[vqpi->txq.queue_id];
+
+ txq->desc_count = vqpi->txq.ring_len;
+ txq->tx_paddr = vqpi->txq.dma_ring_addr;
+ txq->q_handle = vqpi->txq.queue_id;
+ txq->tc = 0;
+
+ rxq = &vsi->rx_queues[vqpi->rxq.queue_id];
+
+ rxq->desc_count = vqpi->rxq.ring_len;
+ rxq->rx_paddr = vqpi->rxq.dma_ring_addr;
+ vsi->mbuf_sz = vqpi->rxq.databuffer_size;
+ }
+
+ /* Configure TX queues in HW */
+ error = ice_cfg_vsi_for_tx(vsi);
+ if (error) {
+ device_printf(dev,
+ "VF-%d: Unable to configure VSI for Tx: %s\n",
+ vf->vf_num, ice_err_str(error));
+ status = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
+ goto done;
+ }
+
+ /* Configure RX queues in HW */
+ error = ice_cfg_vsi_for_rx(vsi);
+ if (error) {
+ device_printf(dev,
+ "VF-%d: Unable to configure VSI for Rx: %s\n",
+ vf->vf_num, ice_err_str(error));
+ status = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
+ ice_vsi_disable_tx(vsi);
+ goto done;
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
+ status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_cfg_rss_key_msg - Handle VIRTCHNL_OP_CONFIG_RSS_KEY msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Sets the RSS key for the given VF, using the contents of msg_buf.
+ */
+static void
+ice_vc_cfg_rss_key_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_aqc_get_set_rss_keys keydata =
+ { .standard_rss_key = {0}, .extended_hash_key = {0} };
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_rss_key *vrk;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+
+ vrk = (struct virtchnl_rss_key *)msg_buf;
+
+ if (vrk->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vrk->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if ((vrk->key_len >
+ (ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE +
+ ICE_AQC_GET_SET_RSS_KEY_DATA_HASH_KEY_SIZE)) ||
+ vrk->key_len == 0) {
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ memcpy(&keydata, vrk->key, vrk->key_len);
+
+ status = ice_aq_set_rss_key(hw, vsi->idx, &keydata);
+ if (status) {
+ device_printf(sc->dev,
+ "ice_aq_set_rss_key status %s, error %s\n",
+ ice_status_str(status), ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_RSS_KEY,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_cfg_rss_lut_msg - Handle VIRTCHNL_OP_CONFIG_RSS_LUT msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Adds the LUT from the VF in msg_buf to the PF via an admin queue call.
+ */
+static void
+ice_vc_cfg_rss_lut_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_rss_lut *vrl;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_aq_get_set_rss_lut_params lut_params = {};
+ struct ice_vsi *vsi = vf->vsi;
+
+ vrl = (struct virtchnl_rss_lut *)msg_buf;
+
+ if (vrl->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vrl->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if (vrl->lut_entries > ICE_VSIQF_HLUT_ARRAY_SIZE) {
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ lut_params.vsi_handle = vsi->idx;
+ lut_params.lut_size = vsi->rss_table_size;
+ lut_params.lut_type = vsi->rss_lut_type;
+ lut_params.lut = vrl->lut;
+ lut_params.global_lut_id = 0;
+
+ status = ice_aq_set_rss_lut(hw, &lut_params);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Cannot set RSS lut, err %s aq_err %s\n",
+ vf->vf_num, ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_RSS_LUT,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_set_rss_hena_msg - Handle VIRTCHNL_OP_SET_RSS_HENA msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Adds the VF's hena (hash enable) bits as flow types to the PF's RSS flow
+ * type list.
+ */
+static void
+ice_vc_set_rss_hena_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_rss_hena *vrh;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+
+ MPASS(vsi != NULL);
+
+ vrh = (struct virtchnl_rss_hena *)msg_buf;
+
+ /*
+ * Remove existing configuration to make sure only requested
+ * config is applied and allow VFs to disable RSS completly.
+ */
+ status = ice_rem_vsi_rss_cfg(hw, vsi->idx);
+ if (vrh->hena) {
+ /*
+ * Problem with removing config is not fatal, when new one
+ * is requested. Warn about it but try to apply new config
+ * anyway.
+ */
+ if (status)
+ device_printf(sc->dev,
+ "ice_rem_vsi_rss_cfg status %s, error %s\n",
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ status = ice_add_avf_rss_cfg(hw, vsi->idx, vrh->hena);
+ if (status)
+ device_printf(sc->dev,
+ "ice_add_avf_rss_cfg status %s, error %s\n",
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ }
+ v_status = ice_iov_err_to_virt_err(status);
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_SET_RSS_HENA,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_enable_queues_msg - Handle VIRTCHNL_OP_ENABLE_QUEUES msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Enables VF queues selected in msg_buf for Tx/Rx traffic.
+ *
+ * @remark Only actually operates on Rx queues; Tx queues are enabled in
+ * CONFIG_VSI_QUEUES message handler.
+ */
+static void
+ice_vc_enable_queues_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_queue_select *vqs;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+ int bit, error = 0;
+
+ vqs = (struct virtchnl_queue_select *)msg_buf;
+
+ if (vqs->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ __func__, vf->vf_num, vsi->idx, vqs->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if (!vqs->rx_queues && !vqs->tx_queues) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message queue masks are empty\n",
+ __func__, vf->vf_num);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* Validate rx_queue mask */
+ bit = fls(vqs->rx_queues);
+ if (bit > vsi->num_rx_queues) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message's rx_queues map (0x%08x) has invalid bit set (%d)\n",
+ __func__, vf->vf_num, vqs->rx_queues, bit);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* Tx ring enable is handled in an earlier message. */
+ for_each_set_bit(bit, &vqs->rx_queues, 32) {
+ error = ice_control_rx_queue(vsi, bit, true);
+ if (error) {
+ device_printf(sc->dev,
+ "Unable to enable Rx ring %d for receive: %s\n",
+ bit, ice_err_str(error));
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_ENABLE_QUEUES,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_disable_queues_msg - Handle VIRTCHNL_OP_DISABLE_QUEUES msg
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Disables all VF queues for the VF's VSI.
+ *
+ * @remark Unlike the ENABLE_QUEUES handler, this operates on both
+ * Tx and Rx queues
+ */
+static void
+ice_vc_disable_queues_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf __unused)
+{
+ struct ice_hw *hw = &sc->hw;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+ int error = 0;
+
+ error = ice_control_all_rx_queues(vsi, false);
+ if (error) {
+ device_printf(sc->dev,
+ "Unable to disable Rx rings for transmit: %s\n",
+ ice_err_str(error));
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ error = ice_vsi_disable_tx(vsi);
+ if (error) {
+ /* Already prints an error message */
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_DISABLE_QUEUES,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_cfg_irq_map_msg - Handle VIRTCHNL_OP_CFG_IRQ_MAP msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Configures the interrupt vectors described in the message in msg_buf. The
+ * VF needs to send this message during init, so that queues can be allowed
+ * to generate interrupts.
+ */
+static void
+ice_vc_cfg_irq_map_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+#define ICE_VIRTCHNL_QUEUE_MAP_SIZE 16
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_irq_map_info *vimi;
+ struct virtchnl_vector_map *vvm;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+ u16 vector;
+
+ vimi = (struct virtchnl_irq_map_info *)msg_buf;
+
+ if (vimi->num_vectors > vf->num_irq_vectors) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message has more vectors (%d) than configured for VF (%d)\n",
+ __func__, vf->vf_num, vimi->num_vectors, vf->num_irq_vectors);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ vvm = vimi->vecmap;
+ /* Save off information from message */
+ for (int i = 0; i < vimi->num_vectors; i++, vvm++) {
+ struct ice_tx_queue *txq;
+ struct ice_rx_queue *rxq;
+ int bit;
+
+ if (vvm->vsi_id != vf->vsi->idx) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message's VSI ID (%d) does not match VF's (%d) for vector %d\n",
+ __func__, vf->vf_num, vvm->vsi_id, vf->vsi->idx, i);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* vvm->vector_id is relative to VF space */
+ vector = vvm->vector_id;
+
+ if (vector >= vf->num_irq_vectors) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message's vector ID (%d) is greater than VF's max ID (%d)\n",
+ __func__, vf->vf_num, vector, vf->num_irq_vectors - 1);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* The Misc/Admin Queue vector doesn't need mapping */
+ if (vector == 0)
+ continue;
+
+ /* coverity[address_of] */
+ for_each_set_bit(bit, &vvm->txq_map, ICE_VIRTCHNL_QUEUE_MAP_SIZE) {
+ if (bit >= vsi->num_tx_queues) {
+ device_printf(sc->dev,
+ "%s: VF-%d: txq map has invalid bit set\n",
+ __func__, vf->vf_num);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ vf->tx_irqvs[vector].me = vector;
+
+ txq = &vsi->tx_queues[bit];
+ txq->irqv = &vf->tx_irqvs[vector];
+ txq->itr_idx = vvm->txitr_idx;
+ }
+ /* coverity[address_of] */
+ for_each_set_bit(bit, &vvm->rxq_map, ICE_VIRTCHNL_QUEUE_MAP_SIZE) {
+ if (bit >= vsi->num_rx_queues) {
+ device_printf(sc->dev,
+ "%s: VF-%d: rxq map has invalid bit set\n",
+ __func__, vf->vf_num);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+ vf->rx_irqvs[vector].me = vector;
+
+ rxq = &vsi->rx_queues[bit];
+ rxq->irqv = &vf->rx_irqvs[vector];
+ rxq->itr_idx = vvm->rxitr_idx;
+ }
+ }
+
+ /* Write to T/RQCTL registers to actually map vectors to queues */
+ for (int i = 0; i < vf->vsi->num_rx_queues; i++)
+ if (vsi->rx_queues[i].irqv != NULL)
+ ice_configure_rxq_interrupt(hw, vsi->rx_qmap[i],
+ vsi->rx_queues[i].irqv->me, vsi->rx_queues[i].itr_idx);
+
+ for (int i = 0; i < vf->vsi->num_tx_queues; i++)
+ if (vsi->tx_queues[i].irqv != NULL)
+ ice_configure_txq_interrupt(hw, vsi->tx_qmap[i],
+ vsi->tx_queues[i].irqv->me, vsi->tx_queues[i].itr_idx);
+
+ ice_flush(hw);
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_IRQ_MAP,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_eth_stats_to_virtchnl_eth_stats - Convert stats for virtchnl
+ * @istats: VSI stats from HW to convert
+ * @vstats: stats struct to copy to
+ *
+ * This function copies all known stats in struct virtchnl_eth_stats from the
+ * input struct ice_eth_stats to an output struct virtchnl_eth_stats.
+ *
+ * @remark These two structure types currently have the same definition up to
+ * the size of struct virtchnl_eth_stats (on FreeBSD), but that could change
+ * in the future.
+ */
+static void
+ice_eth_stats_to_virtchnl_eth_stats(struct ice_eth_stats *istats,
+ struct virtchnl_eth_stats *vstats)
+{
+ vstats->rx_bytes = istats->rx_bytes;
+ vstats->rx_unicast = istats->rx_unicast;
+ vstats->rx_multicast = istats->rx_multicast;
+ vstats->rx_broadcast = istats->rx_broadcast;
+ vstats->rx_discards = istats->rx_discards;
+ vstats->rx_unknown_protocol = istats->rx_unknown_protocol;
+ vstats->tx_bytes = istats->tx_bytes;
+ vstats->tx_unicast = istats->tx_unicast;
+ vstats->tx_multicast = istats->tx_multicast;
+ vstats->tx_broadcast = istats->tx_broadcast;
+ vstats->tx_discards = istats->tx_discards;
+ vstats->tx_errors = istats->tx_errors;
+}
+
+/**
+ * ice_vc_get_stats_msg - Handle VIRTCHNL_OP_GET_STATS msg
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Updates the VF's VSI stats and sends those stats back to the VF.
+ */
+static void
+ice_vc_get_stats_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct virtchnl_queue_select *vqs;
+ struct virtchnl_eth_stats stats;
+ struct ice_vsi *vsi = vf->vsi;
+ struct ice_hw *hw = &sc->hw;
+
+ vqs = (struct virtchnl_queue_select *)msg_buf;
+
+ if (vqs->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message has invalid VSI ID %d (VF has VSI ID %d)\n",
+ __func__, vf->vf_num, vqs->vsi_id, vsi->idx);
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_GET_STATS,
+ VIRTCHNL_STATUS_ERR_PARAM, NULL, 0, NULL);
+ }
+
+ ice_update_vsi_hw_stats(vf->vsi);
+ ice_eth_stats_to_virtchnl_eth_stats(&vsi->hw_stats.cur, &stats);
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_GET_STATS,
+ VIRTCHNL_STATUS_SUCCESS, (u8 *)&stats,
+ sizeof(struct virtchnl_eth_stats), NULL);
+}
+
+/**
+ * ice_vc_cfg_promisc_mode_msg - Handle VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Configures the promiscuous modes for the given VSI in msg_buf.
+ */
+static void
+ice_vc_cfg_promisc_mode_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_promisc_info *vpi;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ int status = 0;
+ struct ice_vsi *vsi = vf->vsi;
+ ice_declare_bitmap(old_promisc_mask, ICE_PROMISC_MAX);
+ ice_declare_bitmap(req_promisc_mask, ICE_PROMISC_MAX);
+ ice_declare_bitmap(clear_promisc_mask, ICE_PROMISC_MAX);
+ ice_declare_bitmap(set_promisc_mask, ICE_PROMISC_MAX);
+ ice_declare_bitmap(old_req_xor_mask, ICE_PROMISC_MAX);
+ u16 vid;
+
+ vpi = (struct virtchnl_promisc_info *)msg_buf;
+
+ /* Check to see if VF has permission to configure promiscuous mode */
+ if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) {
+ device_printf(sc->dev,
+ "VF-%d: attempted to configure promiscuous mode\n",
+ vf->vf_num);
+ /* Don't reply to VF with an error */
+ goto done;
+ }
+
+ if (vpi->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vpi->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if (vpi->flags & ~ICE_VIRTCHNL_VALID_PROMISC_FLAGS) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid promiscuous flags set (valid 0x%02x, got 0x%02x)\n",
+ vf->vf_num, ICE_VIRTCHNL_VALID_PROMISC_FLAGS,
+ vpi->flags);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+
+ }
+
+ ice_zero_bitmap(req_promisc_mask, ICE_PROMISC_MAX);
+ /* Convert virtchnl flags to ice AQ promiscuous mode flags */
+ if (vpi->flags & FLAG_VF_UNICAST_PROMISC) {
+ ice_set_bit(ICE_PROMISC_UCAST_TX, req_promisc_mask);
+ ice_set_bit(ICE_PROMISC_UCAST_RX, req_promisc_mask);
+ }
+ if (vpi->flags & FLAG_VF_MULTICAST_PROMISC) {
+ ice_set_bit(ICE_PROMISC_MCAST_TX, req_promisc_mask);
+ ice_set_bit(ICE_PROMISC_MCAST_RX, req_promisc_mask);
+ }
+
+ status = ice_get_vsi_promisc(hw, vsi->idx, old_promisc_mask, &vid);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failed to get promiscuous mode mask for VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx,
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+
+ /* Figure out what got added and what got removed */
+ ice_zero_bitmap(old_req_xor_mask, ICE_PROMISC_MAX);
+ ice_xor_bitmap(old_req_xor_mask, old_promisc_mask, req_promisc_mask, ICE_PROMISC_MAX);
+ ice_and_bitmap(clear_promisc_mask, old_req_xor_mask, old_promisc_mask, ICE_PROMISC_MAX);
+ ice_and_bitmap(set_promisc_mask, old_req_xor_mask, req_promisc_mask, ICE_PROMISC_MAX);
+
+ if (ice_is_any_bit_set(clear_promisc_mask, ICE_PROMISC_MAX)) {
+ status = ice_clear_vsi_promisc(hw, vsi->idx,
+ clear_promisc_mask, 0);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failed to clear promiscuous mode for VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx,
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+ }
+
+ if (ice_is_any_bit_set(set_promisc_mask, ICE_PROMISC_MAX)) {
+ status = ice_set_vsi_promisc(hw, vsi->idx, set_promisc_mask, 0);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failed to set promiscuous mode for VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx,
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_notify_all_vfs_link_state - Notify all VFs of PF link state
+ * @sc: device private structure
+ *
+ * Sends a message to all VFs about the status of the PF's link
+ * state. For more details, @see ice_vc_notify_vf_link_state.
+ */
+void
+ice_vc_notify_all_vfs_link_state(struct ice_softc *sc)
+{
+ for (int i = 0; i < sc->num_vfs; i++)
+ ice_vc_notify_vf_link_state(sc, &sc->vfs[i]);
+}
+
+/**
+ * ice_vc_notify_vf_link_state - Notify VF of PF link state
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ *
+ * Sends an event message to the specified VF with information about
+ * the current link state from the PF's port. This includes whether
+ * link is up or down, and the link speed in 100Mbps units.
+ */
+static void
+ice_vc_notify_vf_link_state(struct ice_softc *sc, struct ice_vf *vf)
+{
+ struct virtchnl_pf_event event = {};
+ struct ice_hw *hw = &sc->hw;
+
+ event.event = VIRTCHNL_EVENT_LINK_CHANGE;
+ event.severity = PF_EVENT_SEVERITY_INFO;
+ event.event_data.link_event_adv.link_status = sc->link_up;
+ event.event_data.link_event_adv.link_speed =
+ (u32)ice_conv_link_speed_to_virtchnl(true,
+ hw->port_info->phy.link_info.link_speed);
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_EVENT,
+ VIRTCHNL_STATUS_SUCCESS, (u8 *)&event, sizeof(event), NULL);
+}
+
+/**
+ * ice_vc_handle_vf_msg - Handle a message from a VF
+ * @sc: device private structure
+ * @event: event received from the HW MBX queue
+ *
+ * Called whenever an event is received from a VF on the HW mailbox queue.
+ * Responsible for handling these messages as well as responding to the
+ * VF afterwards, depending on the received message type.
+ */
+void
+ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event)
+{
+ struct ice_hw *hw = &sc->hw;
+ device_t dev = sc->dev;
+ struct ice_vf *vf;
+ int err = 0;
+
+ u32 v_opcode = event->desc.cookie_high;
+ u16 v_id = event->desc.retval;
+ u8 *msg = event->msg_buf;
+ u16 msglen = event->msg_len;
+
+ if (v_id >= sc->num_vfs) {
+ device_printf(dev, "%s: Received msg from invalid VF-%d: opcode %d, len %d\n",
+ __func__, v_id, v_opcode, msglen);
+ return;
+ }
+
+ vf = &sc->vfs[v_id];
+
+ /* Perform basic checks on the msg */
+ err = virtchnl_vc_validate_vf_msg(&vf->version, v_opcode, msg, msglen);
+ if (err) {
+ device_printf(dev, "%s: Received invalid msg from VF-%d: opcode %d, len %d, error %d\n",
+ __func__, vf->vf_num, v_opcode, msglen, err);
+ ice_aq_send_msg_to_vf(hw, v_id, v_opcode, VIRTCHNL_STATUS_ERR_PARAM, NULL, 0, NULL);
+ return;
+ }
+
+ switch (v_opcode) {
+ case VIRTCHNL_OP_VERSION:
+ ice_vc_version_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_RESET_VF:
+ ice_reset_vf(sc, vf, true);
+ break;
+ case VIRTCHNL_OP_GET_VF_RESOURCES:
+ ice_vc_get_vf_res_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_ADD_ETH_ADDR:
+ ice_vc_add_eth_addr_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_DEL_ETH_ADDR:
+ ice_vc_del_eth_addr_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_ADD_VLAN:
+ ice_vc_add_vlan_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_DEL_VLAN:
+ ice_vc_del_vlan_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
+ ice_vc_cfg_vsi_qs_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_RSS_KEY:
+ ice_vc_cfg_rss_key_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_RSS_LUT:
+ ice_vc_cfg_rss_lut_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_SET_RSS_HENA:
+ ice_vc_set_rss_hena_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_ENABLE_QUEUES:
+ ice_vc_enable_queues_msg(sc, vf, msg);
+ ice_vc_notify_vf_link_state(sc, vf);
+ break;
+ case VIRTCHNL_OP_DISABLE_QUEUES:
+ ice_vc_disable_queues_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_IRQ_MAP:
+ ice_vc_cfg_irq_map_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_GET_STATS:
+ ice_vc_get_stats_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
+ ice_vc_cfg_promisc_mode_msg(sc, vf, msg);
+ break;
+ default:
+ device_printf(dev, "%s: Received unknown msg from VF-%d: opcode %d, len %d\n",
+ __func__, vf->vf_num, v_opcode, msglen);
+ ice_aq_send_msg_to_vf(hw, v_id, v_opcode,
+ VIRTCHNL_STATUS_ERR_NOT_SUPPORTED, NULL, 0, NULL);
+ break;
+ }
+}
+
+/**
+ * ice_iov_setup_intr_mapping - Setup interrupt config for a VF
+ * @sc: device softc structure
+ * @vf: driver's VF structure for VF to be configured
+ *
+ * Before a VF can be used, and after a VF reset, the PF must configure
+ * the VF's interrupt allocation registers. This includes allocating
+ * interrupts from the PF's interrupt pool to the VF using the
+ * VPINT_ALLOC(_PCI) registers, and setting up a mapping from PF vectors
+ * to VF vectors in GLINT_VECT2FUNC.
+ *
+ * As well, this sets up queue allocation registers and maps the mailbox
+ * interrupt for the VF.
+ */
+static void
+ice_iov_setup_intr_mapping(struct ice_softc *sc, struct ice_vf *vf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct ice_vsi *vsi = vf->vsi;
+ u16 v;
+
+ /* Calculate indices for register ops below */
+ u16 vf_first_irq_idx = vf->vf_imap[0];
+ u16 vf_last_irq_idx = (vf_first_irq_idx + vf->num_irq_vectors) - 1;
+ u16 abs_vf_first_irq_idx = hw->func_caps.common_cap.msix_vector_first_id +
+ vf_first_irq_idx;
+ u16 abs_vf_last_irq_idx = (abs_vf_first_irq_idx + vf->num_irq_vectors) - 1;
+ u16 abs_vf_num = vf->vf_num + hw->func_caps.vf_base_id;
+
+ /* Map out VF interrupt allocation in global device space. Both
+ * VPINT_ALLOC and VPINT_ALLOC_PCI use the same values.
+ */
+ wr32(hw, VPINT_ALLOC(vf->vf_num),
+ (((abs_vf_first_irq_idx << VPINT_ALLOC_FIRST_S) & VPINT_ALLOC_FIRST_M) |
+ ((abs_vf_last_irq_idx << VPINT_ALLOC_LAST_S) & VPINT_ALLOC_LAST_M) |
+ VPINT_ALLOC_VALID_M));
+ wr32(hw, VPINT_ALLOC_PCI(vf->vf_num),
+ (((abs_vf_first_irq_idx << VPINT_ALLOC_PCI_FIRST_S) & VPINT_ALLOC_PCI_FIRST_M) |
+ ((abs_vf_last_irq_idx << VPINT_ALLOC_PCI_LAST_S) & VPINT_ALLOC_PCI_LAST_M) |
+ VPINT_ALLOC_PCI_VALID_M));
+
+ /* Create inverse mapping of vectors to PF/VF combinations */
+ for (v = vf_first_irq_idx; v <= vf_last_irq_idx; v++)
+ {
+ wr32(hw, GLINT_VECT2FUNC(v),
+ (((abs_vf_num << GLINT_VECT2FUNC_VF_NUM_S) & GLINT_VECT2FUNC_VF_NUM_M) |
+ ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) & GLINT_VECT2FUNC_PF_NUM_M)));
+ }
+
+ /* Map mailbox interrupt to MSI-X index 0. Disable ITR for it, too. */
+ wr32(hw, VPINT_MBX_CTL(abs_vf_num),
+ ((0 << VPINT_MBX_CTL_MSIX_INDX_S) & VPINT_MBX_CTL_MSIX_INDX_M) |
+ ((0x3 << VPINT_MBX_CTL_ITR_INDX_S) & VPINT_MBX_CTL_ITR_INDX_M) |
+ VPINT_MBX_CTL_CAUSE_ENA_M);
+
+ /* Mark the TX queue mapping registers as valid */
+ wr32(hw, VPLAN_TXQ_MAPENA(vf->vf_num), VPLAN_TXQ_MAPENA_TX_ENA_M);
+
+ /* Indicate to HW that VF has scattered queue allocation */
+ wr32(hw, VPLAN_TX_QBASE(vf->vf_num), VPLAN_TX_QBASE_VFQTABLE_ENA_M);
+ for (int i = 0; i < vsi->num_tx_queues; i++) {
+ wr32(hw, VPLAN_TX_QTABLE(i, vf->vf_num),
+ (vsi->tx_qmap[i] << VPLAN_TX_QTABLE_QINDEX_S) & VPLAN_TX_QTABLE_QINDEX_M);
+ }
+
+ /* Mark the RX queue mapping registers as valid */
+ wr32(hw, VPLAN_RXQ_MAPENA(vf->vf_num), VPLAN_RXQ_MAPENA_RX_ENA_M);
+ wr32(hw, VPLAN_RX_QBASE(vf->vf_num), VPLAN_RX_QBASE_VFQTABLE_ENA_M);
+ for (int i = 0; i < vsi->num_rx_queues; i++) {
+ wr32(hw, VPLAN_RX_QTABLE(i, vf->vf_num),
+ (vsi->rx_qmap[i] << VPLAN_RX_QTABLE_QINDEX_S) & VPLAN_RX_QTABLE_QINDEX_M);
+ }
+}
+
+/**
+ * ice_err_to_virt err - translate ice errors into virtchnl errors
+ * @ice_err: status returned from ice function
+ */
+static enum virtchnl_status_code
+ice_iov_err_to_virt_err(int ice_err)
+{
+ switch (ice_err) {
+ case 0:
+ return VIRTCHNL_STATUS_SUCCESS;
+ case ICE_ERR_BAD_PTR:
+ case ICE_ERR_INVAL_SIZE:
+ case ICE_ERR_DEVICE_NOT_SUPPORTED:
+ case ICE_ERR_PARAM:
+ case ICE_ERR_CFG:
+ return VIRTCHNL_STATUS_ERR_PARAM;
+ case ICE_ERR_NO_MEMORY:
+ return VIRTCHNL_STATUS_ERR_NO_MEMORY;
+ case ICE_ERR_NOT_READY:
+ case ICE_ERR_RESET_FAILED:
+ case ICE_ERR_FW_API_VER:
+ case ICE_ERR_AQ_ERROR:
+ case ICE_ERR_AQ_TIMEOUT:
+ case ICE_ERR_AQ_FULL:
+ case ICE_ERR_AQ_NO_WORK:
+ case ICE_ERR_AQ_EMPTY:
+ return VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
+ default:
+ return VIRTCHNL_STATUS_ERR_NOT_SUPPORTED;
+ }
+}
diff --git a/sys/dev/ice/ice_iov.h b/sys/dev/ice/ice_iov.h
new file mode 100644
index 000000000000..c4fb3e932e3f
--- /dev/null
+++ b/sys/dev/ice/ice_iov.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file ice_iov.h
+ * @brief header for IOV functionality
+ *
+ * This header includes definitions used to implement device Virtual Functions
+ * for the ice driver.
+ */
+
+#ifndef _ICE_IOV_H_
+#define _ICE_IOV_H_
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/nv.h>
+#include <sys/iov_schema.h>
+#include <sys/param.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <dev/pci/pci_iov.h>
+
+#include "ice_iflib.h"
+#include "ice_vf_mbx.h"
+
+/**
+ * @enum ice_vf_flags
+ * @brief VF state flags
+ *
+ * Used to indicate the status of a PF's VF, as well as indicating what each VF
+ * is capabile of. Intended to be modified only using atomic operations, so
+ * they can be read and modified in places that aren't locked.
+ *
+ * Used in struct ice_vf's vf_flags field.
+ */
+enum ice_vf_flags {
+ VF_FLAG_ENABLED = BIT(0),
+ VF_FLAG_SET_MAC_CAP = BIT(1),
+ VF_FLAG_VLAN_CAP = BIT(2),
+ VF_FLAG_PROMISC_CAP = BIT(3),
+ VF_FLAG_MAC_ANTI_SPOOF = BIT(4),
+};
+
+/**
+ * @struct ice_vf
+ * @brief PF's VF software context
+ *
+ * Represents the state and options for a VF spawned from a PF.
+ */
+struct ice_vf {
+ struct ice_vsi *vsi;
+ u32 vf_flags;
+
+ u8 mac[ETHER_ADDR_LEN];
+ u16 vf_num;
+ struct virtchnl_version_info version;
+
+ u16 mac_filter_limit;
+ u16 mac_filter_cnt;
+ u16 vlan_limit;
+ u16 vlan_cnt;
+
+ u16 num_irq_vectors;
+ u16 *vf_imap;
+ struct ice_irq_vector *tx_irqvs;
+ struct ice_irq_vector *rx_irqvs;
+};
+
+#define ICE_PCIE_DEV_STATUS 0xAA
+
+#define ICE_PCI_CIAD_WAIT_COUNT 100
+#define ICE_PCI_CIAD_WAIT_DELAY_US 1
+#define ICE_VPGEN_VFRSTAT_WAIT_COUNT 100
+#define ICE_VPGEN_VFRSTAT_WAIT_DELAY_US 20
+
+#define ICE_VIRTCHNL_VALID_PROMISC_FLAGS (FLAG_VF_UNICAST_PROMISC | \
+ FLAG_VF_MULTICAST_PROMISC)
+
+#define ICE_DEFAULT_VF_VLAN_LIMIT 64
+#define ICE_DEFAULT_VF_FILTER_LIMIT 16
+
+int ice_iov_attach(struct ice_softc *sc);
+int ice_iov_detach(struct ice_softc *sc);
+
+int ice_iov_init(struct ice_softc *sc, uint16_t num_vfs, const nvlist_t *params);
+int ice_iov_add_vf(struct ice_softc *sc, uint16_t vfnum, const nvlist_t *params);
+void ice_iov_uninit(struct ice_softc *sc);
+
+void ice_iov_handle_vflr(struct ice_softc *sc);
+
+void ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event);
+void ice_vc_notify_all_vfs_link_state(struct ice_softc *sc);
+
+#endif /* _ICE_IOV_H_ */
+
diff --git a/sys/dev/ice/ice_lib.c b/sys/dev/ice/ice_lib.c
index d44ae5f37750..442111e5ffaf 100644
--- a/sys/dev/ice/ice_lib.c
+++ b/sys/dev/ice/ice_lib.c
@@ -42,6 +42,9 @@
#include "ice_lib.h"
#include "ice_iflib.h"
+#ifdef PCI_IOV
+#include "ice_iov.h"
+#endif
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <machine/resource.h>
@@ -741,6 +744,12 @@ ice_initialize_vsi(struct ice_vsi *vsi)
case ICE_VSI_VMDQ2:
ctx.flags = ICE_AQ_VSI_TYPE_VMDQ2;
break;
+#ifdef PCI_IOV
+ case ICE_VSI_VF:
+ ctx.flags = ICE_AQ_VSI_TYPE_VF;
+ ctx.vf_num = vsi->vf_num;
+ break;
+#endif
default:
return (ENODEV);
}
@@ -1607,6 +1616,12 @@ ice_setup_tx_ctx(struct ice_tx_queue *txq, struct ice_tlan_ctx *tlan_ctx, u16 pf
case ICE_VSI_VMDQ2:
tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VMQ;
break;
+#ifdef PCI_IOV
+ case ICE_VSI_VF:
+ tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF;
+ tlan_ctx->vmvf_num = hw->func_caps.vf_base_id + vsi->vf_num;
+ break;
+#endif
default:
return (ENODEV);
}
@@ -1660,6 +1675,10 @@ ice_cfg_vsi_for_tx(struct ice_vsi *vsi)
struct ice_tlan_ctx tlan_ctx = { 0 };
struct ice_tx_queue *txq = &vsi->tx_queues[i];
+ /* Last configured queue */
+ if (txq->desc_count == 0)
+ break;
+
pf_q = vsi->tx_qmap[txq->me];
qg->txqs[0].txq_id = htole16(pf_q);
@@ -1788,6 +1807,10 @@ ice_cfg_vsi_for_rx(struct ice_vsi *vsi)
for (i = 0; i < vsi->num_rx_queues; i++) {
MPASS(vsi->mbuf_sz > 0);
+ /* Last configured queue */
+ if (vsi->rx_queues[i].desc_count == 0)
+ break;
+
err = ice_setup_rx_ctx(&vsi->rx_queues[i]);
if (err)
return err;
@@ -2257,6 +2280,11 @@ ice_process_ctrlq_event(struct ice_softc *sc, const char *qname,
case ice_aqc_opc_get_link_status:
ice_process_link_event(sc, event);
break;
+#ifdef PCI_IOV
+ case ice_mbx_opc_send_msg_to_pf:
+ ice_vc_handle_vf_msg(sc, event);
+ break;
+#endif
case ice_aqc_opc_fw_logs_event:
ice_handle_fw_log_event(sc, &event->desc, event->msg_buf);
break;
diff --git a/sys/dev/ice/ice_lib.h b/sys/dev/ice/ice_lib.h
index b6b23ec82161..308b2bda2790 100644
--- a/sys/dev/ice/ice_lib.h
+++ b/sys/dev/ice/ice_lib.h
@@ -611,6 +611,10 @@ struct ice_vsi {
u16 mirror_src_vsi;
u16 rule_mir_ingress;
u16 rule_mir_egress;
+
+#ifdef PCI_IOV
+ u8 vf_num; /* Index of owning VF, if applicable */
+#endif
};
/**
diff --git a/sys/dev/ice/ice_vf_mbx.c b/sys/dev/ice/ice_vf_mbx.c
new file mode 100644
index 000000000000..387a1c6739a6
--- /dev/null
+++ b/sys/dev/ice/ice_vf_mbx.c
@@ -0,0 +1,471 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ice_common.h"
+#include "ice_hw_autogen.h"
+#include "ice_vf_mbx.h"
+
+/**
+ * ice_aq_send_msg_to_vf
+ * @hw: pointer to the hardware structure
+ * @vfid: VF ID to send msg
+ * @v_opcode: opcodes for VF-PF communication
+ * @v_retval: return error code
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @cd: pointer to command details
+ *
+ * Send message to VF driver (0x0802) using mailbox
+ * queue and asynchronously sending message via
+ * ice_sq_send_cmd() function
+ */
+int
+ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
+ u8 *msg, u16 msglen, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_pf_vf_msg *cmd;
+ struct ice_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_mbx_opc_send_msg_to_vf);
+
+ cmd = &desc.params.virt;
+ cmd->id = CPU_TO_LE32(vfid);
+
+ desc.cookie_high = CPU_TO_LE32(v_opcode);
+ desc.cookie_low = CPU_TO_LE32(v_retval);
+
+ if (msglen)
+ desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
+
+ return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd);
+}
+
+/**
+ * ice_aq_send_msg_to_pf
+ * @hw: pointer to the hardware structure
+ * @v_opcode: opcodes for VF-PF communication
+ * @v_retval: return error code
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @cd: pointer to command details
+ *
+ * Send message to PF driver using mailbox queue. By default, this
+ * message is sent asynchronously, i.e. ice_sq_send_cmd()
+ * does not wait for completion before returning.
+ */
+int
+ice_aq_send_msg_to_pf(struct ice_hw *hw, enum virtchnl_ops v_opcode,
+ int v_retval, u8 *msg, u16 msglen,
+ struct ice_sq_cd *cd)
+{
+ struct ice_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_mbx_opc_send_msg_to_pf);
+ desc.cookie_high = CPU_TO_LE32(v_opcode);
+ desc.cookie_low = CPU_TO_LE32(v_retval);
+
+ if (msglen)
+ desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
+
+ return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd);
+}
+
+static const u32 ice_legacy_aq_to_vc_speed[] = {
+ VIRTCHNL_LINK_SPEED_100MB, /* BIT(0) */
+ VIRTCHNL_LINK_SPEED_100MB,
+ VIRTCHNL_LINK_SPEED_1GB,
+ VIRTCHNL_LINK_SPEED_1GB,
+ VIRTCHNL_LINK_SPEED_1GB,
+ VIRTCHNL_LINK_SPEED_10GB,
+ VIRTCHNL_LINK_SPEED_20GB,
+ VIRTCHNL_LINK_SPEED_25GB,
+ VIRTCHNL_LINK_SPEED_40GB,
+ VIRTCHNL_LINK_SPEED_40GB,
+ VIRTCHNL_LINK_SPEED_40GB,
+};
+
+/**
+ * ice_conv_link_speed_to_virtchnl
+ * @adv_link_support: determines the format of the returned link speed
+ * @link_speed: variable containing the link_speed to be converted
+ *
+ * Convert link speed supported by HW to link speed supported by virtchnl.
+ * If adv_link_support is true, then return link speed in Mbps. Else return
+ * link speed as a VIRTCHNL_LINK_SPEED_* casted to a u32. Note that the caller
+ * needs to cast back to an enum virtchnl_link_speed in the case where
+ * adv_link_support is false, but when adv_link_support is true the caller can
+ * expect the speed in Mbps.
+ */
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed)
+{
+ /* convert a BIT() value into an array index */
+ u16 index = (u16)(ice_fls(link_speed) - 1);
+
+ if (adv_link_support)
+ return ice_get_link_speed(index);
+ else if (index < ARRAY_SIZE(ice_legacy_aq_to_vc_speed))
+ /* Virtchnl speeds are not defined for every speed supported in
+ * the hardware. To maintain compatibility with older AVF
+ * drivers, while reporting the speed the new speed values are
+ * resolved to the closest known virtchnl speeds
+ */
+ return ice_legacy_aq_to_vc_speed[index];
+
+ return VIRTCHNL_LINK_SPEED_UNKNOWN;
+}
+
+/* The mailbox overflow detection algorithm helps to check if there
+ * is a possibility of a malicious VF transmitting too many MBX messages to the
+ * PF.
+ * 1. The mailbox snapshot structure, ice_mbx_snapshot, is initialized during
+ * driver initialization in ice_init_hw() using ice_mbx_init_snapshot().
+ * The struct ice_mbx_snapshot helps to track and traverse a static window of
+ * messages within the mailbox queue while looking for a malicious VF.
+ *
+ * 2. When the caller starts processing its mailbox queue in response to an
+ * interrupt, the structure ice_mbx_snapshot is expected to be cleared before
+ * the algorithm can be run for the first time for that interrupt. This
+ * requires calling ice_mbx_reset_snapshot() as well as calling
+ * ice_mbx_reset_vf_info() for each VF tracking structure.
+ *
+ * 3. For every message read by the caller from the MBX Queue, the caller must
+ * call the detection algorithm's entry function ice_mbx_vf_state_handler().
+ * Before every call to ice_mbx_vf_state_handler() the struct ice_mbx_data is
+ * filled as it is required to be passed to the algorithm.
+ *
+ * 4. Every time a message is read from the MBX queue, a tracking structure
+ * for the VF must be passed to the state handler. The boolean output
+ * report_malvf from ice_mbx_vf_state_handler() serves as an indicator to the
+ * caller whether it must report this VF as malicious or not.
+ *
+ * 5. When a VF is identified to be malicious, the caller can send a message
+ * to the system administrator.
+ *
+ * 6. The PF is responsible for maintaining the struct ice_mbx_vf_info
+ * structure for each VF. The PF should clear the VF tracking structure if the
+ * VF is reset. When a VF is shut down and brought back up, we will then
+ * assume that the new VF is not malicious and may report it again if we
+ * detect it again.
+ *
+ * 7. The function ice_mbx_reset_snapshot() is called to reset the information
+ * in ice_mbx_snapshot for every new mailbox interrupt handled.
+ */
+#define ICE_RQ_DATA_MASK(rq_data) ((rq_data) & PF_MBX_ARQH_ARQH_M)
+/* Using the highest value for an unsigned 16-bit value 0xFFFF to indicate that
+ * the max messages check must be ignored in the algorithm
+ */
+#define ICE_IGNORE_MAX_MSG_CNT 0xFFFF
+
+/**
+ * ice_mbx_reset_snapshot - Initialize mailbox snapshot structure
+ * @snap: pointer to the mailbox snapshot
+ */
+static void ice_mbx_reset_snapshot(struct ice_mbx_snapshot *snap)
+{
+ struct ice_mbx_vf_info *vf_info;
+
+ /* Clear mbx_buf in the mailbox snaphot structure and setting the
+ * mailbox snapshot state to a new capture.
+ */
+ ice_memset(&snap->mbx_buf, 0, sizeof(snap->mbx_buf), ICE_NONDMA_MEM);
+ snap->mbx_buf.state = ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
+
+ /* Reset message counts for all VFs to zero */
+ LIST_FOR_EACH_ENTRY(vf_info, &snap->mbx_vf, ice_mbx_vf_info, list_entry)
+ vf_info->msg_count = 0;
+}
+
+/**
+ * ice_mbx_traverse - Pass through mailbox snapshot
+ * @hw: pointer to the HW struct
+ * @new_state: new algorithm state
+ *
+ * Traversing the mailbox static snapshot without checking
+ * for malicious VFs.
+ */
+static void
+ice_mbx_traverse(struct ice_hw *hw,
+ enum ice_mbx_snapshot_state *new_state)
+{
+ struct ice_mbx_snap_buffer_data *snap_buf;
+ u32 num_iterations;
+
+ snap_buf = &hw->mbx_snapshot.mbx_buf;
+
+ /* As mailbox buffer is circular, applying a mask
+ * on the incremented iteration count.
+ */
+ num_iterations = ICE_RQ_DATA_MASK(++snap_buf->num_iterations);
+
+ /* Checking either of the below conditions to exit snapshot traversal:
+ * Condition-1: If the number of iterations in the mailbox is equal to
+ * the mailbox head which would indicate that we have reached the end
+ * of the static snapshot.
+ * Condition-2: If the maximum messages serviced in the mailbox for a
+ * given interrupt is the highest possible value then there is no need
+ * to check if the number of messages processed is equal to it. If not
+ * check if the number of messages processed is greater than or equal
+ * to the maximum number of mailbox entries serviced in current work item.
+ */
+ if (num_iterations == snap_buf->head ||
+ (snap_buf->max_num_msgs_mbx < ICE_IGNORE_MAX_MSG_CNT &&
+ ++snap_buf->num_msg_proc >= snap_buf->max_num_msgs_mbx))
+ *new_state = ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
+}
+
+/**
+ * ice_mbx_detect_malvf - Detect malicious VF in snapshot
+ * @hw: pointer to the HW struct
+ * @vf_info: mailbox tracking structure for a VF
+ * @new_state: new algorithm state
+ * @is_malvf: boolean output to indicate if VF is malicious
+ *
+ * This function tracks the number of asynchronous messages
+ * sent per VF and marks the VF as malicious if it exceeds
+ * the permissible number of messages to send.
+ */
+static int
+ice_mbx_detect_malvf(struct ice_hw *hw, struct ice_mbx_vf_info *vf_info,
+ enum ice_mbx_snapshot_state *new_state,
+ bool *is_malvf)
+{
+ /* increment the message count for this VF */
+ vf_info->msg_count++;
+
+ if (vf_info->msg_count >= ICE_ASYNC_VF_MSG_THRESHOLD)
+ *is_malvf = true;
+
+ /* continue to iterate through the mailbox snapshot */
+ ice_mbx_traverse(hw, new_state);
+
+ return 0;
+}
+
+/**
+ * ice_e830_mbx_vf_dec_trig - Decrements the VF mailbox queue counter
+ * @hw: pointer to the HW struct
+ * @event: pointer to the control queue receive event
+ *
+ * This function triggers to decrement the counter
+ * MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT when the driver replenishes
+ * the buffers at the PF mailbox queue.
+ */
+void ice_e830_mbx_vf_dec_trig(struct ice_hw *hw,
+ struct ice_rq_event_info *event)
+{
+ u16 vfid = LE16_TO_CPU(event->desc.retval);
+
+ wr32(hw, E830_MBX_VF_DEC_TRIG(vfid), 1);
+}
+
+/**
+ * ice_mbx_vf_clear_cnt_e830 - Clear the VF mailbox queue count
+ * @hw: pointer to the HW struct
+ * @vf_id: VF ID in the PF space
+ *
+ * This function clears the counter MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT, and should
+ * be called when a VF is created and on VF reset.
+ */
+void ice_mbx_vf_clear_cnt_e830(struct ice_hw *hw, u16 vf_id)
+{
+ u32 reg = rd32(hw, E830_MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT(vf_id));
+
+ wr32(hw, E830_MBX_VF_DEC_TRIG(vf_id), reg);
+}
+
+/**
+ * ice_mbx_vf_state_handler - Handle states of the overflow algorithm
+ * @hw: pointer to the HW struct
+ * @mbx_data: pointer to structure containing mailbox data
+ * @vf_info: mailbox tracking structure for the VF in question
+ * @report_malvf: boolean output to indicate whether VF should be reported
+ *
+ * The function serves as an entry point for the malicious VF
+ * detection algorithm by handling the different states and state
+ * transitions of the algorithm:
+ * New snapshot: This state is entered when creating a new static
+ * snapshot. The data from any previous mailbox snapshot is
+ * cleared and a new capture of the mailbox head and tail is
+ * logged. This will be the new static snapshot to detect
+ * asynchronous messages sent by VFs. On capturing the snapshot
+ * and depending on whether the number of pending messages in that
+ * snapshot exceed the watermark value, the state machine enters
+ * traverse or detect states.
+ * Traverse: If pending message count is below watermark then iterate
+ * through the snapshot without any action on VF.
+ * Detect: If pending message count exceeds watermark traverse
+ * the static snapshot and look for a malicious VF.
+ */
+int
+ice_mbx_vf_state_handler(struct ice_hw *hw, struct ice_mbx_data *mbx_data,
+ struct ice_mbx_vf_info *vf_info, bool *report_malvf)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+ struct ice_mbx_snap_buffer_data *snap_buf;
+ struct ice_ctl_q_info *cq = &hw->mailboxq;
+ enum ice_mbx_snapshot_state new_state;
+ int status = 0;
+ bool is_malvf = false;
+
+ if (!report_malvf || !mbx_data || !vf_info)
+ return ICE_ERR_BAD_PTR;
+
+ *report_malvf = false;
+
+ /* When entering the mailbox state machine assume that the VF
+ * is not malicious until detected.
+ */
+ /* Checking if max messages allowed to be processed while servicing current
+ * interrupt is not less than the defined AVF message threshold.
+ */
+ if (mbx_data->max_num_msgs_mbx <= ICE_ASYNC_VF_MSG_THRESHOLD)
+ return ICE_ERR_INVAL_SIZE;
+
+ /* The watermark value should not be lesser than the threshold limit
+ * set for the number of asynchronous messages a VF can send to mailbox
+ * nor should it be greater than the maximum number of messages in the
+ * mailbox serviced in current interrupt.
+ */
+ if (mbx_data->async_watermark_val < ICE_ASYNC_VF_MSG_THRESHOLD ||
+ mbx_data->async_watermark_val > mbx_data->max_num_msgs_mbx)
+ return ICE_ERR_PARAM;
+
+ new_state = ICE_MAL_VF_DETECT_STATE_INVALID;
+ snap_buf = &snap->mbx_buf;
+
+ switch (snap_buf->state) {
+ case ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT:
+ /* Clear any previously held data in mailbox snapshot structure. */
+ ice_mbx_reset_snapshot(snap);
+
+ /* Collect the pending ARQ count, number of messages processed and
+ * the maximum number of messages allowed to be processed from the
+ * Mailbox for current interrupt.
+ */
+ snap_buf->num_pending_arq = mbx_data->num_pending_arq;
+ snap_buf->num_msg_proc = mbx_data->num_msg_proc;
+ snap_buf->max_num_msgs_mbx = mbx_data->max_num_msgs_mbx;
+
+ /* Capture a new static snapshot of the mailbox by logging the
+ * head and tail of snapshot and set num_iterations to the tail
+ * value to mark the start of the iteration through the snapshot.
+ */
+ snap_buf->head = ICE_RQ_DATA_MASK(cq->rq.next_to_clean +
+ mbx_data->num_pending_arq);
+ snap_buf->tail = ICE_RQ_DATA_MASK(cq->rq.next_to_clean - 1);
+ snap_buf->num_iterations = snap_buf->tail;
+
+ /* Pending ARQ messages returned by ice_clean_rq_elem
+ * is the difference between the head and tail of the
+ * mailbox queue. Comparing this value against the watermark
+ * helps to check if we potentially have malicious VFs.
+ */
+ if (snap_buf->num_pending_arq >=
+ mbx_data->async_watermark_val) {
+ new_state = ICE_MAL_VF_DETECT_STATE_DETECT;
+ status = ice_mbx_detect_malvf(hw, vf_info, &new_state, &is_malvf);
+ } else {
+ new_state = ICE_MAL_VF_DETECT_STATE_TRAVERSE;
+ ice_mbx_traverse(hw, &new_state);
+ }
+ break;
+
+ case ICE_MAL_VF_DETECT_STATE_TRAVERSE:
+ new_state = ICE_MAL_VF_DETECT_STATE_TRAVERSE;
+ ice_mbx_traverse(hw, &new_state);
+ break;
+
+ case ICE_MAL_VF_DETECT_STATE_DETECT:
+ new_state = ICE_MAL_VF_DETECT_STATE_DETECT;
+ status = ice_mbx_detect_malvf(hw, vf_info, &new_state, &is_malvf);
+ break;
+
+ default:
+ new_state = ICE_MAL_VF_DETECT_STATE_INVALID;
+ status = ICE_ERR_CFG;
+ }
+
+ snap_buf->state = new_state;
+
+ /* Only report VFs as malicious the first time we detect it */
+ if (is_malvf && !vf_info->malicious) {
+ vf_info->malicious = 1;
+ *report_malvf = true;
+ }
+
+ return status;
+}
+
+/**
+ * ice_mbx_clear_malvf - Clear VF mailbox info
+ * @vf_info: the mailbox tracking structure for a VF
+ *
+ * In case of a VF reset, this function shall be called to clear the VF's
+ * current mailbox tracking state.
+ */
+void ice_mbx_clear_malvf(struct ice_mbx_vf_info *vf_info)
+{
+ vf_info->malicious = 0;
+ vf_info->msg_count = 0;
+}
+
+/**
+ * ice_mbx_init_vf_info - Initialize a new VF mailbox tracking info
+ * @hw: pointer to the hardware structure
+ * @vf_info: the mailbox tracking info structure for a VF
+ *
+ * Initialize a VF mailbox tracking info structure and insert it into the
+ * snapshot list.
+ *
+ * If you remove the VF, you must also delete the associated VF info structure
+ * from the linked list.
+ */
+void ice_mbx_init_vf_info(struct ice_hw *hw, struct ice_mbx_vf_info *vf_info)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+
+ ice_mbx_clear_malvf(vf_info);
+ LIST_ADD(&vf_info->list_entry, &snap->mbx_vf);
+}
+
+/**
+ * ice_mbx_init_snapshot - Initialize mailbox snapshot data
+ * @hw: pointer to the hardware structure
+ *
+ * Clear the mailbox snapshot structure and initialize the VF mailbox list.
+ */
+void ice_mbx_init_snapshot(struct ice_hw *hw)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+
+ INIT_LIST_HEAD(&snap->mbx_vf);
+ ice_mbx_reset_snapshot(snap);
+}
diff --git a/sys/dev/ice/ice_vf_mbx.h b/sys/dev/ice/ice_vf_mbx.h
new file mode 100644
index 000000000000..3b185ac89c11
--- /dev/null
+++ b/sys/dev/ice/ice_vf_mbx.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ICE_VF_MBX_H_
+#define _ICE_VF_MBX_H_
+
+#include "ice_type.h"
+#include "ice_controlq.h"
+
+/* Defining the mailbox message threshold as 63 asynchronous
+ * pending messages. Normal VF functionality does not require
+ * sending more than 63 asynchronous pending message.
+ */
+
+ /* Threshold value should be used to initialize
+ * MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT register.
+ */
+#define ICE_ASYNC_VF_MSG_THRESHOLD 63
+
+int
+ice_aq_send_msg_to_pf(struct ice_hw *hw, enum virtchnl_ops v_opcode,
+ int v_retval, u8 *msg, u16 msglen,
+ struct ice_sq_cd *cd);
+int
+ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
+ u8 *msg, u16 msglen, struct ice_sq_cd *cd);
+
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed);
+
+void ice_e830_mbx_vf_dec_trig(struct ice_hw *hw,
+ struct ice_rq_event_info *event);
+void ice_mbx_vf_clear_cnt_e830(struct ice_hw *hw, u16 vf_id);
+int
+ice_mbx_vf_state_handler(struct ice_hw *hw, struct ice_mbx_data *mbx_data,
+ struct ice_mbx_vf_info *vf_info, bool *report_malvf);
+void ice_mbx_clear_malvf(struct ice_mbx_vf_info *vf_info);
+void ice_mbx_init_vf_info(struct ice_hw *hw, struct ice_mbx_vf_info *vf_info);
+void ice_mbx_init_snapshot(struct ice_hw *hw);
+#endif /* _ICE_VF_MBX_H_ */
diff --git a/sys/dev/ice/if_ice_iflib.c b/sys/dev/ice/if_ice_iflib.c
index e60ee0f1c5c3..1469d2916465 100644
--- a/sys/dev/ice/if_ice_iflib.c
+++ b/sys/dev/ice/if_ice_iflib.c
@@ -42,6 +42,9 @@
#include "ice_drv_info.h"
#include "ice_switch.h"
#include "ice_sched.h"
+#ifdef PCI_IOV
+#include "ice_iov.h"
+#endif
#include <sys/module.h>
#include <sys/sockio.h>
@@ -85,6 +88,12 @@ static int ice_if_suspend(if_ctx_t ctx);
static int ice_if_resume(if_ctx_t ctx);
static bool ice_if_needs_restart(if_ctx_t ctx, enum iflib_restart_event event);
static void ice_init_link(struct ice_softc *sc);
+#ifdef PCI_IOV
+static int ice_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params);
+static void ice_if_iov_uninit(if_ctx_t ctx);
+static int ice_if_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params);
+static void ice_if_vflr_handle(if_ctx_t ctx);
+#endif
static int ice_setup_mirror_vsi(struct ice_mirr_if *mif);
static int ice_wire_mirror_intrs(struct ice_mirr_if *mif);
static void ice_free_irqvs_subif(struct ice_mirr_if *mif);
@@ -158,6 +167,11 @@ static device_method_t ice_methods[] = {
DEVMETHOD(device_shutdown, iflib_device_shutdown),
DEVMETHOD(device_suspend, iflib_device_suspend),
DEVMETHOD(device_resume, iflib_device_resume),
+#ifdef PCI_IOV
+ DEVMETHOD(pci_iov_init, iflib_device_iov_init),
+ DEVMETHOD(pci_iov_uninit, iflib_device_iov_uninit),
+ DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf),
+#endif
DEVMETHOD_END
};
@@ -198,6 +212,12 @@ static device_method_t ice_iflib_methods[] = {
DEVMETHOD(ifdi_suspend, ice_if_suspend),
DEVMETHOD(ifdi_resume, ice_if_resume),
DEVMETHOD(ifdi_needs_restart, ice_if_needs_restart),
+#ifdef PCI_IOV
+ DEVMETHOD(ifdi_iov_vf_add, ice_if_iov_vf_add),
+ DEVMETHOD(ifdi_iov_init, ice_if_iov_init),
+ DEVMETHOD(ifdi_iov_uninit, ice_if_iov_uninit),
+ DEVMETHOD(ifdi_vflr_handle, ice_if_vflr_handle),
+#endif
DEVMETHOD_END
};
@@ -733,6 +753,9 @@ ice_update_link_status(struct ice_softc *sc, bool update_media)
iflib_link_state_change(sc->ctx, LINK_STATE_DOWN, 0);
ice_rdma_link_change(sc, LINK_STATE_DOWN, 0);
}
+#ifdef PCI_IOV
+ ice_vc_notify_all_vfs_link_state(sc);
+#endif
update_media = true;
}
@@ -831,6 +854,14 @@ ice_if_attach_post(if_ctx_t ctx)
ice_add_device_sysctls(sc);
+#ifdef PCI_IOV
+ if (ice_is_bit_set(sc->feat_cap, ICE_FEATURE_SRIOV)) {
+ err = ice_iov_attach(sc);
+ if (err == ENOMEM)
+ return (err);
+ }
+#endif /* PCI_IOV */
+
/* Get DCBX/LLDP state and start DCBX agent */
ice_init_dcb_setup(sc);
@@ -953,6 +984,11 @@ ice_if_detach(if_ctx_t ctx)
ice_destroy_mirror_interface(sc);
ice_rdma_pf_detach(sc);
+#ifdef PCI_IOV
+ if (ice_is_bit_set(sc->feat_cap, ICE_FEATURE_SRIOV))
+ ice_iov_detach(sc);
+#endif /* PCI_IOV */
+
/* Free allocated media types */
ifmedia_removeall(sc->media);
@@ -1676,6 +1712,11 @@ ice_if_msix_intr_assign(if_ctx_t ctx, int msix)
/* For future interrupt assignments */
sc->last_rid = rid + sc->irdma_vectors;
+#ifdef PCI_IOV
+ /* Create soft IRQ for handling VF resets */
+ iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_IOV, sc, 0, "iov");
+#endif
+
return (0);
fail:
for (; i >= 0; i--, vector--)
@@ -2277,7 +2318,12 @@ ice_transition_recovery_mode(struct ice_softc *sc)
ice_rdma_pf_detach(sc);
ice_clear_bit(ICE_FEATURE_RDMA, sc->feat_cap);
+#ifdef PCI_IOV
+ if (ice_test_and_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en))
+ ice_iov_detach(sc);
+#else
ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en);
+#endif /* PCI_IOV */
ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_cap);
ice_vsi_del_txqs_ctx(vsi);
@@ -2325,7 +2371,12 @@ ice_transition_safe_mode(struct ice_softc *sc)
ice_rdma_pf_detach(sc);
ice_clear_bit(ICE_FEATURE_RDMA, sc->feat_cap);
+#ifdef PCI_IOV
+ if (ice_test_and_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en))
+ ice_iov_detach(sc);
+#else
ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en);
+#endif /* PCI_IOV */
ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_cap);
ice_clear_bit(ICE_FEATURE_RSS, sc->feat_cap);
@@ -2410,6 +2461,15 @@ ice_if_update_admin_status(if_ctx_t ctx)
/* Check and update link status */
ice_update_link_status(sc, false);
+#ifdef PCI_IOV
+ /*
+ * Schedule VFs' reset handler after global resets
+ * and other events were processed.
+ */
+ if (ice_testandclear_state(&sc->state, ICE_STATE_VFLR_PENDING))
+ iflib_iov_intr_deferred(ctx);
+#endif
+
/*
* If there are still messages to process, we need to reschedule
* ourselves. Otherwise, we can just re-enable the interrupt. We'll be
@@ -3349,6 +3409,78 @@ ice_init_link(struct ice_softc *sc)
}
+#ifdef PCI_IOV
+/**
+ * ice_if_iov_init - iov init handler for iflib
+ * @ctx: iflib context pointer
+ * @num_vfs: number of VFs to create
+ * @params: configuration parameters for the PF
+ *
+ * Configure the driver for SR-IOV mode. Used to setup things like memory
+ * before any VFs are created.
+ *
+ * @remark This is a wrapper for ice_iov_init
+ */
+static int
+ice_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params)
+{
+ struct ice_softc *sc = (struct ice_softc *)iflib_get_softc(ctx);
+
+ return ice_iov_init(sc, num_vfs, params);
+}
+
+/**
+ * ice_if_iov_uninit - iov uninit handler for iflib
+ * @ctx: iflib context pointer
+ *
+ * Destroys VFs and frees their memory and resources.
+ *
+ * @remark This is a wrapper for ice_iov_uninit
+ */
+static void
+ice_if_iov_uninit(if_ctx_t ctx)
+{
+ struct ice_softc *sc = (struct ice_softc *)iflib_get_softc(ctx);
+
+ ice_iov_uninit(sc);
+}
+
+/**
+ * ice_if_iov_vf_add - iov add vf handler for iflib
+ * @ctx: iflib context pointer
+ * @vfnum: index of VF to configure
+ * @params: configuration parameters for the VF
+ *
+ * Sets up the VF given by the vfnum index. This is called by the OS
+ * for each VF created by the PF driver after it is spawned.
+ *
+ * @remark This is a wrapper for ice_iov_vf_add
+ */
+static int
+ice_if_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params)
+{
+ struct ice_softc *sc = (struct ice_softc *)iflib_get_softc(ctx);
+
+ return ice_iov_add_vf(sc, vfnum, params);
+}
+
+/**
+ * ice_if_vflr_handle - iov VFLR handler
+ * @ctx: iflib context pointer
+ *
+ * Performs the necessar teardown or setup required for a VF after
+ * a VFLR is initiated.
+ *
+ * @remark This is a wrapper for ice_iov_handle_vflr
+ */
+static void
+ice_if_vflr_handle(if_ctx_t ctx)
+{
+ struct ice_softc *sc = (struct ice_softc *)iflib_get_softc(ctx);
+ ice_iov_handle_vflr(sc);
+}
+#endif /* PCI_IOV */
+
extern struct if_txrx ice_subif_txrx;
/**
diff --git a/sys/dev/ichiic/ig4_pci.c b/sys/dev/ichiic/ig4_pci.c
index 0195466150eb..3a49e220e335 100644
--- a/sys/dev/ichiic/ig4_pci.c
+++ b/sys/dev/ichiic/ig4_pci.c
@@ -186,6 +186,12 @@ static int ig4iic_pci_detach(device_t dev);
#define PCI_CHIP_METEORLAKE_M_I2C_3 0x7e518086
#define PCI_CHIP_METEORLAKE_M_I2C_4 0x7e7a8086
#define PCI_CHIP_METEORLAKE_M_I2C_5 0x7e7b8086
+#define PCI_CHIP_ARROWLAKE_U_I2C_0 0x77788086
+#define PCI_CHIP_ARROWLAKE_U_I2C_1 0x77798086
+#define PCI_CHIP_ARROWLAKE_U_I2C_2 0x777a8086
+#define PCI_CHIP_ARROWLAKE_U_I2C_3 0x777b8086
+#define PCI_CHIP_ARROWLAKE_U_I2C_4 0x77508086
+#define PCI_CHIP_ARROWLAKE_U_I2C_5 0x77518086
struct ig4iic_pci_device {
uint32_t devid;
@@ -316,6 +322,12 @@ static struct ig4iic_pci_device ig4iic_pci_devices[] = {
{ PCI_CHIP_METEORLAKE_M_I2C_3, "Intel Meteor Lake-M I2C Controller-3", IG4_TIGERLAKE},
{ PCI_CHIP_METEORLAKE_M_I2C_4, "Intel Meteor Lake-M I2C Controller-4", IG4_TIGERLAKE},
{ PCI_CHIP_METEORLAKE_M_I2C_5, "Intel Meteor Lake-M I2C Controller-5", IG4_TIGERLAKE},
+ { PCI_CHIP_ARROWLAKE_U_I2C_0, "Intel Arrow Lake-H/U I2C Controller-0", IG4_TIGERLAKE},
+ { PCI_CHIP_ARROWLAKE_U_I2C_1, "Intel Arrow Lake-H/U I2C Controller-1", IG4_TIGERLAKE},
+ { PCI_CHIP_ARROWLAKE_U_I2C_2, "Intel Arrow Lake-H/U I2C Controller-2", IG4_TIGERLAKE},
+ { PCI_CHIP_ARROWLAKE_U_I2C_3, "Intel Arrow Lake-H/U I2C Controller-3", IG4_TIGERLAKE},
+ { PCI_CHIP_ARROWLAKE_U_I2C_4, "Intel Arrow Lake-H/U I2C Controller-4", IG4_TIGERLAKE},
+ { PCI_CHIP_ARROWLAKE_U_I2C_5, "Intel Arrow Lake-H/U I2C Controller-5", IG4_TIGERLAKE},
};
static int
diff --git a/sys/dev/iicbus/gpio/tca64xx.c b/sys/dev/iicbus/gpio/tca64xx.c
index 3b3bca9936f1..cd011ae9be75 100644
--- a/sys/dev/iicbus/gpio/tca64xx.c
+++ b/sys/dev/iicbus/gpio/tca64xx.c
@@ -261,14 +261,13 @@ tca64xx_attach(device_t dev)
sc->addr = iicbus_get_addr(dev);
mtx_init(&sc->mtx, "tca64xx gpio", "gpio", MTX_DEF);
+ OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
sc->busdev = gpiobus_attach_bus(dev);
if (sc->busdev == NULL) {
device_printf(dev, "Could not create busdev child\n");
return (ENXIO);
}
- OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
-
#ifdef DEBUG
switch (sc->chip) {
case TCA6416_TYPE:
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 741a7c013f7d..29dc0c880e3a 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -11,9 +11,9 @@
*/
/*-
- * The following functions are based on the vn(4) driver: mdstart_swap(),
- * mdstart_vnode(), mdcreate_swap(), mdcreate_vnode() and mddestroy(),
- * and as such under the following copyright:
+ * The following functions are based on the historical vn(4) driver:
+ * mdstart_swap(), mdstart_vnode(), mdcreate_swap(), mdcreate_vnode()
+ * and mddestroy(), and as such under the following copyright:
*
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990, 1993
diff --git a/sys/dev/mem/memutil.c b/sys/dev/mem/memutil.c
index cf9714d6ec8f..20ce337df0ab 100644
--- a/sys/dev/mem/memutil.c
+++ b/sys/dev/mem/memutil.c
@@ -26,15 +26,14 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/memrange.h>
-#include <sys/rwlock.h>
-#include <sys/systm.h>
+#include <sys/sx.h>
-static struct rwlock mr_lock;
+static struct sx mr_lock;
/*
* Implementation-neutral, kernel-callable functions for manipulating
@@ -46,7 +45,7 @@ mem_range_init(void)
if (mem_range_softc.mr_op == NULL)
return;
- rw_init(&mr_lock, "memrange");
+ sx_init(&mr_lock, "memrange");
mem_range_softc.mr_op->init(&mem_range_softc);
}
@@ -56,7 +55,7 @@ mem_range_destroy(void)
if (mem_range_softc.mr_op == NULL)
return;
- rw_destroy(&mr_lock);
+ sx_destroy(&mr_lock);
}
int
@@ -67,12 +66,12 @@ mem_range_attr_get(struct mem_range_desc *mrd, int *arg)
if (mem_range_softc.mr_op == NULL)
return (EOPNOTSUPP);
nd = *arg;
- rw_rlock(&mr_lock);
+ sx_slock(&mr_lock);
if (nd == 0)
*arg = mem_range_softc.mr_ndesc;
else
bcopy(mem_range_softc.mr_desc, mrd, nd * sizeof(*mrd));
- rw_runlock(&mr_lock);
+ sx_sunlock(&mr_lock);
return (0);
}
@@ -83,8 +82,8 @@ mem_range_attr_set(struct mem_range_desc *mrd, int *arg)
if (mem_range_softc.mr_op == NULL)
return (EOPNOTSUPP);
- rw_wlock(&mr_lock);
+ sx_xlock(&mr_lock);
ret = mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg);
- rw_wunlock(&mr_lock);
+ sx_xunlock(&mr_lock);
return (ret);
}
diff --git a/sys/dev/mgb/if_mgb.c b/sys/dev/mgb/if_mgb.c
index 1240d0f84415..409f34167df0 100644
--- a/sys/dev/mgb/if_mgb.c
+++ b/sys/dev/mgb/if_mgb.c
@@ -1435,7 +1435,7 @@ mgb_hw_teardown(struct mgb_softc *sc)
/* Stop MAC */
CSR_CLEAR_REG(sc, MGB_MAC_RX, MGB_MAC_ENBL);
- CSR_WRITE_REG(sc, MGB_MAC_TX, MGB_MAC_ENBL);
+ CSR_CLEAR_REG(sc, MGB_MAC_TX, MGB_MAC_ENBL);
if ((err = mgb_wait_for_bits(sc, MGB_MAC_RX, MGB_MAC_DSBL, 0)))
return (err);
if ((err = mgb_wait_for_bits(sc, MGB_MAC_TX, MGB_MAC_DSBL, 0)))
diff --git a/sys/dev/mlx5/mlx5_accel/ipsec.h b/sys/dev/mlx5/mlx5_accel/ipsec.h
index 361b9f72d873..c3f3a2372482 100644
--- a/sys/dev/mlx5/mlx5_accel/ipsec.h
+++ b/sys/dev/mlx5/mlx5_accel/ipsec.h
@@ -260,8 +260,8 @@ int mlx5e_accel_ipsec_fs_rx_tables_create(struct mlx5e_priv *priv);
void mlx5e_accel_ipsec_fs_rx_catchall_rules_destroy(struct mlx5e_priv *priv);
int mlx5e_accel_ipsec_fs_rx_catchall_rules(struct mlx5e_priv *priv);
int mlx5_accel_ipsec_rx_tag_add(if_t ifp, struct mlx5e_rq_mbuf *mr);
-void mlx5e_accel_ipsec_handle_rx_cqe(struct mbuf *mb, struct mlx5_cqe64 *cqe,
- struct mlx5e_rq_mbuf *mr);
+void mlx5e_accel_ipsec_handle_rx_cqe(if_t ifp, struct mbuf *mb,
+ struct mlx5_cqe64 *cqe, struct mlx5e_rq_mbuf *mr);
static inline int mlx5e_accel_ipsec_flow(struct mlx5_cqe64 *cqe)
{
@@ -269,12 +269,12 @@ static inline int mlx5e_accel_ipsec_flow(struct mlx5_cqe64 *cqe)
}
static inline void
-mlx5e_accel_ipsec_handle_rx(struct mbuf *mb, struct mlx5_cqe64 *cqe,
+mlx5e_accel_ipsec_handle_rx(if_t ifp, struct mbuf *mb, struct mlx5_cqe64 *cqe,
struct mlx5e_rq_mbuf *mr)
{
u32 ipsec_meta_data = be32_to_cpu(cqe->ft_metadata);
if (MLX5_IPSEC_METADATA_MARKER(ipsec_meta_data))
- mlx5e_accel_ipsec_handle_rx_cqe(mb, cqe, mr);
+ mlx5e_accel_ipsec_handle_rx_cqe(ifp, mb, cqe, mr);
}
#endif /* __MLX5_ACCEL_IPSEC_H__ */
diff --git a/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c b/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c
index 0883cfb2d510..5dccb8bc2b87 100644
--- a/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c
+++ b/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c
@@ -24,11 +24,14 @@
*
*/
+#include "opt_ipsec.h"
+
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netipsec/keydb.h>
#include <netipsec/ipsec_offload.h>
+#include <netipsec/xform.h>
#include <dev/mlx5/qp.h>
#include <dev/mlx5/mlx5_en/en.h>
#include <dev/mlx5/mlx5_accel/ipsec.h>
@@ -48,7 +51,8 @@ mlx5_accel_ipsec_rx_tag_add(if_t ifp, struct mlx5e_rq_mbuf *mr)
return (0);
mtag = (struct ipsec_accel_in_tag *)m_tag_get(
- PACKET_TAG_IPSEC_ACCEL_IN, sizeof(*mtag), M_NOWAIT);
+ PACKET_TAG_IPSEC_ACCEL_IN, sizeof(struct ipsec_accel_in_tag) -
+ __offsetof(struct ipsec_accel_in_tag, xh), M_NOWAIT);
if (mtag == NULL)
return (-ENOMEM);
mr->ipsec_mtag = mtag;
@@ -56,8 +60,8 @@ mlx5_accel_ipsec_rx_tag_add(if_t ifp, struct mlx5e_rq_mbuf *mr)
}
void
-mlx5e_accel_ipsec_handle_rx_cqe(struct mbuf *mb, struct mlx5_cqe64 *cqe,
- struct mlx5e_rq_mbuf *mr)
+mlx5e_accel_ipsec_handle_rx_cqe(if_t ifp, struct mbuf *mb,
+ struct mlx5_cqe64 *cqe, struct mlx5e_rq_mbuf *mr)
{
struct ipsec_accel_in_tag *mtag;
u32 drv_spi;
@@ -65,10 +69,12 @@ mlx5e_accel_ipsec_handle_rx_cqe(struct mbuf *mb, struct mlx5_cqe64 *cqe,
drv_spi = MLX5_IPSEC_METADATA_HANDLE(be32_to_cpu(cqe->ft_metadata));
mtag = mr->ipsec_mtag;
WARN_ON(mtag == NULL);
- mr->ipsec_mtag = NULL;
if (mtag != NULL) {
mtag->drv_spi = drv_spi;
- m_tag_prepend(mb, &mtag->tag);
+ if (ipsec_accel_fill_xh(ifp, drv_spi, &mtag->xh)) {
+ m_tag_prepend(mb, &mtag->tag);
+ mr->ipsec_mtag = NULL;
+ }
}
}
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c
index 8b8f2e570245..89d2010656c5 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c
@@ -42,13 +42,30 @@
static if_snd_tag_free_t mlx5e_tls_rx_snd_tag_free;
static if_snd_tag_modify_t mlx5e_tls_rx_snd_tag_modify;
+static if_snd_tag_status_str_t mlx5e_tls_rx_snd_tag_status_str;
static const struct if_snd_tag_sw mlx5e_tls_rx_snd_tag_sw = {
.snd_tag_modify = mlx5e_tls_rx_snd_tag_modify,
.snd_tag_free = mlx5e_tls_rx_snd_tag_free,
+ .snd_tag_status_str = mlx5e_tls_rx_snd_tag_status_str,
.type = IF_SND_TAG_TYPE_TLS_RX
};
+static const char *mlx5e_tls_rx_progress_params_auth_state_str[] = {
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_NO_OFFLOAD] = "no_offload",
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_OFFLOAD] = "offload",
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_AUTHENTICATION] =
+ "authentication",
+};
+
+static const char *mlx5e_tls_rx_progress_params_record_tracker_state_str[] = {
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START] = "start",
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING] =
+ "tracking",
+ [MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING] =
+ "searching",
+};
+
MALLOC_DEFINE(M_MLX5E_TLS_RX, "MLX5E_TLS_RX", "MLX5 ethernet HW TLS RX");
/* software TLS RX context */
@@ -250,7 +267,8 @@ mlx5e_tls_rx_send_progress_parameters_sync(struct mlx5e_iq *iq,
mtx_unlock(&iq->lock);
while (1) {
- if (wait_for_completion_timeout(&ptag->progress_complete, hz) != 0)
+ if (wait_for_completion_timeout(&ptag->progress_complete,
+ msecs_to_jiffies(1000)) != 0)
break;
priv = container_of(iq, struct mlx5e_channel, iq)->priv;
if (priv->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR ||
@@ -331,7 +349,8 @@ done:
* Zero is returned upon success, else some error happened.
*/
static int
-mlx5e_tls_rx_receive_progress_parameters(struct mlx5e_iq *iq, struct mlx5e_tls_rx_tag *ptag)
+mlx5e_tls_rx_receive_progress_parameters(struct mlx5e_iq *iq,
+ struct mlx5e_tls_rx_tag *ptag, mlx5e_iq_callback_t *cb)
{
struct mlx5e_get_tls_progress_params_wqe *wqe;
const u32 ds_cnt = DIV_ROUND_UP(sizeof(*wqe), MLX5_SEND_WQE_DS);
@@ -367,7 +386,7 @@ mlx5e_tls_rx_receive_progress_parameters(struct mlx5e_iq *iq, struct mlx5e_tls_r
memcpy(iq->doorbell.d32, &wqe->ctrl, sizeof(iq->doorbell.d32));
iq->data[pi].num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
- iq->data[pi].callback = &mlx5e_tls_rx_receive_progress_parameters_cb;
+ iq->data[pi].callback = cb;
iq->data[pi].arg = ptag;
m_snd_tag_ref(&ptag->tag);
@@ -640,7 +659,8 @@ mlx5e_tls_rx_set_params(void *ctx, struct inpcb *inp, const struct tls_session_p
return (EINVAL);
MLX5_SET64(sw_tls_rx_cntx, ctx, param.initial_record_number, tls_sn_he);
- MLX5_SET(sw_tls_rx_cntx, ctx, param.resync_tcp_sn, tcp_sn_he);
+ MLX5_SET(sw_tls_rx_cntx, ctx, param.resync_tcp_sn, 0);
+ MLX5_SET(sw_tls_rx_cntx, ctx, progress.next_record_tcp_sn, tcp_sn_he);
return (0);
}
@@ -819,6 +839,7 @@ mlx5e_tls_rx_snd_tag_alloc(if_t ifp,
}
ptag->flow_rule = flow_rule;
+ init_completion(&ptag->progress_complete);
return (0);
@@ -968,7 +989,8 @@ mlx5e_tls_rx_snd_tag_modify(struct m_snd_tag *pmt, union if_snd_tag_modify_param
params->tls_rx.tls_rec_length,
params->tls_rx.tls_seq_number) &&
ptag->tcp_resync_pending == 0) {
- err = mlx5e_tls_rx_receive_progress_parameters(iq, ptag);
+ err = mlx5e_tls_rx_receive_progress_parameters(iq, ptag,
+ &mlx5e_tls_rx_receive_progress_parameters_cb);
if (err != 0) {
MLX5E_TLS_RX_STAT_INC(ptag, rx_resync_err, 1);
} else {
@@ -1001,6 +1023,74 @@ mlx5e_tls_rx_snd_tag_free(struct m_snd_tag *pmt)
queue_work(priv->tls_rx.wq, &ptag->work);
}
+static void
+mlx5e_tls_rx_str_status_cb(void *arg)
+{
+ struct mlx5e_tls_rx_tag *ptag;
+
+ ptag = (struct mlx5e_tls_rx_tag *)arg;
+ complete_all(&ptag->progress_complete);
+ m_snd_tag_rele(&ptag->tag);
+}
+
+static int
+mlx5e_tls_rx_snd_tag_status_str(struct m_snd_tag *pmt, char *buf, size_t *sz)
+{
+ int err, out_size;
+ struct mlx5e_iq *iq;
+ void *buffer;
+ uint32_t tracker_state_val;
+ uint32_t auth_state_val;
+ struct mlx5e_priv *priv;
+ struct mlx5e_tls_rx_tag *ptag =
+ container_of(pmt, struct mlx5e_tls_rx_tag, tag);
+
+ if (buf == NULL)
+ return (0);
+
+ MLX5E_TLS_RX_TAG_LOCK(ptag);
+ priv = container_of(ptag->tls_rx, struct mlx5e_priv, tls_rx);
+ iq = mlx5e_tls_rx_get_iq(priv, ptag->flowid, ptag->flowtype);
+ reinit_completion(&ptag->progress_complete);
+ err = mlx5e_tls_rx_receive_progress_parameters(iq, ptag,
+ &mlx5e_tls_rx_str_status_cb);
+ MLX5E_TLS_RX_TAG_UNLOCK(ptag);
+ if (err != 0)
+ return (err);
+
+ for (;;) {
+ if (wait_for_completion_timeout(&ptag->progress_complete,
+ msecs_to_jiffies(1000)) != 0)
+ break;
+ if (priv->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR ||
+ pci_channel_offline(priv->mdev->pdev) != 0)
+ return (ENXIO);
+ }
+ buffer = mlx5e_tls_rx_get_progress_buffer(ptag);
+ tracker_state_val = MLX5_GET(tls_progress_params, buffer,
+ record_tracker_state);
+ auth_state_val = MLX5_GET(tls_progress_params, buffer, auth_state);
+
+ /* Validate tracker state value is in range */
+ if (tracker_state_val >
+ MLX5E_TLS_RX_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING)
+ return (EINVAL);
+
+ /* Validate auth state value is in range */
+ if (auth_state_val >
+ MLX5E_TLS_RX_PROGRESS_PARAMS_AUTH_STATE_AUTHENTICATION)
+ return (EINVAL);
+
+ out_size = snprintf(buf, *sz, "tracker_state: %s, auth_state: %s",
+ mlx5e_tls_rx_progress_params_record_tracker_state_str[
+ tracker_state_val],
+ mlx5e_tls_rx_progress_params_auth_state_str[auth_state_val]);
+
+ if (out_size <= *sz)
+ *sz = out_size;
+ return (0);
+}
+
#else
int
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
index 6b53db6fea23..eb569488631a 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
@@ -467,7 +467,7 @@ mlx5e_build_rx_mbuf(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
break;
}
- mlx5e_accel_ipsec_handle_rx(mb, cqe, mr);
+ mlx5e_accel_ipsec_handle_rx(ifp, mb, cqe, mr);
}
static inline void
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index 73a7cee4aad0..fd7f00ced14b 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -48,7 +48,7 @@
#define B4_CHK_RDY_DELAY_MS 2300 /* work around controller bug */
static void nvme_ctrlr_construct_and_submit_aer(struct nvme_controller *ctrlr,
- struct nvme_async_event_request *aer);
+ struct nvme_async_event_request *aer);
static void
nvme_ctrlr_barrier(struct nvme_controller *ctrlr, int flags)
@@ -680,96 +680,6 @@ nvme_ctrlr_log_critical_warnings(struct nvme_controller *ctrlr,
}
static void
-nvme_ctrlr_async_event_log_page_cb(void *arg, const struct nvme_completion *cpl)
-{
- struct nvme_async_event_request *aer = arg;
- struct nvme_health_information_page *health_info;
- struct nvme_ns_list *nsl;
- struct nvme_error_information_entry *err;
- int i;
-
- /*
- * If the log page fetch for some reason completed with an error,
- * don't pass log page data to the consumers. In practice, this case
- * should never happen.
- */
- if (nvme_completion_is_error(cpl))
- nvme_notify_async_consumers(aer->ctrlr, &aer->cpl,
- aer->log_page_id, NULL, 0);
- else {
- /* Convert data to host endian */
- switch (aer->log_page_id) {
- case NVME_LOG_ERROR:
- err = (struct nvme_error_information_entry *)aer->log_page_buffer;
- for (i = 0; i < (aer->ctrlr->cdata.elpe + 1); i++)
- nvme_error_information_entry_swapbytes(err++);
- break;
- case NVME_LOG_HEALTH_INFORMATION:
- nvme_health_information_page_swapbytes(
- (struct nvme_health_information_page *)aer->log_page_buffer);
- break;
- case NVME_LOG_CHANGED_NAMESPACE:
- nvme_ns_list_swapbytes(
- (struct nvme_ns_list *)aer->log_page_buffer);
- break;
- case NVME_LOG_COMMAND_EFFECT:
- nvme_command_effects_page_swapbytes(
- (struct nvme_command_effects_page *)aer->log_page_buffer);
- break;
- case NVME_LOG_RES_NOTIFICATION:
- nvme_res_notification_page_swapbytes(
- (struct nvme_res_notification_page *)aer->log_page_buffer);
- break;
- case NVME_LOG_SANITIZE_STATUS:
- nvme_sanitize_status_page_swapbytes(
- (struct nvme_sanitize_status_page *)aer->log_page_buffer);
- break;
- default:
- break;
- }
-
- if (aer->log_page_id == NVME_LOG_HEALTH_INFORMATION) {
- health_info = (struct nvme_health_information_page *)
- aer->log_page_buffer;
- nvme_ctrlr_log_critical_warnings(aer->ctrlr,
- health_info->critical_warning);
- /*
- * Critical warnings reported through the
- * SMART/health log page are persistent, so
- * clear the associated bits in the async event
- * config so that we do not receive repeated
- * notifications for the same event.
- */
- aer->ctrlr->async_event_config &=
- ~health_info->critical_warning;
- nvme_ctrlr_cmd_set_async_event_config(aer->ctrlr,
- aer->ctrlr->async_event_config, NULL, NULL);
- } else if (aer->log_page_id == NVME_LOG_CHANGED_NAMESPACE &&
- !nvme_use_nvd) {
- nsl = (struct nvme_ns_list *)aer->log_page_buffer;
- for (i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) {
- if (nsl->ns[i] > NVME_MAX_NAMESPACES)
- break;
- nvme_notify_ns(aer->ctrlr, nsl->ns[i]);
- }
- }
-
- /*
- * Pass the cpl data from the original async event completion,
- * not the log page fetch.
- */
- nvme_notify_async_consumers(aer->ctrlr, &aer->cpl,
- aer->log_page_id, aer->log_page_buffer, aer->log_page_size);
- }
-
- /*
- * Repost another asynchronous event request to replace the one
- * that just completed.
- */
- nvme_ctrlr_construct_and_submit_aer(aer->ctrlr, aer);
-}
-
-static void
nvme_ctrlr_async_event_cb(void *arg, const struct nvme_completion *cpl)
{
struct nvme_async_event_request *aer = arg;
@@ -784,33 +694,18 @@ nvme_ctrlr_async_event_cb(void *arg, const struct nvme_completion *cpl)
return;
}
- /* Associated log page is in bits 23:16 of completion entry dw0. */
+ /*
+ * Save the completion status and associated log page is in bits 23:16
+ * of completion entry dw0. Print a message and queue it for further
+ * processing.
+ */
+ memcpy(&aer->cpl, cpl, sizeof(*cpl));
aer->log_page_id = NVMEV(NVME_ASYNC_EVENT_LOG_PAGE_ID, cpl->cdw0);
-
nvme_printf(aer->ctrlr, "async event occurred (type 0x%x, info 0x%02x,"
" page 0x%02x)\n", NVMEV(NVME_ASYNC_EVENT_TYPE, cpl->cdw0),
NVMEV(NVME_ASYNC_EVENT_INFO, cpl->cdw0),
aer->log_page_id);
-
- if (is_log_page_id_valid(aer->log_page_id)) {
- aer->log_page_size = nvme_ctrlr_get_log_page_size(aer->ctrlr,
- aer->log_page_id);
- memcpy(&aer->cpl, cpl, sizeof(*cpl));
- nvme_ctrlr_cmd_get_log_page(aer->ctrlr, aer->log_page_id,
- NVME_GLOBAL_NAMESPACE_TAG, aer->log_page_buffer,
- aer->log_page_size, nvme_ctrlr_async_event_log_page_cb,
- aer);
- /* Wait to notify consumers until after log page is fetched. */
- } else {
- nvme_notify_async_consumers(aer->ctrlr, cpl, aer->log_page_id,
- NULL, 0);
-
- /*
- * Repost another asynchronous event request to replace the one
- * that just completed.
- */
- nvme_ctrlr_construct_and_submit_aer(aer->ctrlr, aer);
- }
+ taskqueue_enqueue(aer->ctrlr->taskqueue, &aer->task);
}
static void
@@ -819,15 +714,21 @@ nvme_ctrlr_construct_and_submit_aer(struct nvme_controller *ctrlr,
{
struct nvme_request *req;
- aer->ctrlr = ctrlr;
/*
- * XXX-MJ this should be M_WAITOK but we might be in a non-sleepable
- * callback context. AER completions should be handled on a dedicated
- * thread.
+ * We're racing the reset thread, so let that process submit this again.
+ * XXX does this really solve that race? And is that race even possible
+ * since we only reset when we've no theard from the card in a long
+ * time. Why would we get an AER in the middle of that just before we
+ * kick off the reset?
*/
- req = nvme_allocate_request_null(M_NOWAIT, nvme_ctrlr_async_event_cb,
+ if (ctrlr->is_resetting)
+ return;
+
+ aer->ctrlr = ctrlr;
+ req = nvme_allocate_request_null(M_WAITOK, nvme_ctrlr_async_event_cb,
aer);
aer->req = req;
+ aer->log_page_id = 0; /* Not a valid page */
/*
* Disable timeout here, since asynchronous event requests should by
@@ -1203,6 +1104,140 @@ nvme_ctrlr_reset_task(void *arg, int pending)
atomic_cmpset_32(&ctrlr->is_resetting, 1, 0);
}
+static void
+nvme_ctrlr_aer_done(void *arg, const struct nvme_completion *cpl)
+{
+ struct nvme_async_event_request *aer = arg;
+
+ mtx_lock(&aer->mtx);
+ if (nvme_completion_is_error(cpl))
+ aer->log_page_size = (uint32_t)-1;
+ else
+ aer->log_page_size = nvme_ctrlr_get_log_page_size(
+ aer->ctrlr, aer->log_page_id);
+ wakeup(aer);
+ mtx_unlock(&aer->mtx);
+}
+
+static void
+nvme_ctrlr_aer_task(void *arg, int pending)
+{
+ struct nvme_async_event_request *aer = arg;
+ struct nvme_controller *ctrlr = aer->ctrlr;
+ uint32_t len;
+
+ /*
+ * We're resetting, so just punt.
+ */
+ if (ctrlr->is_resetting)
+ return;
+
+ if (!is_log_page_id_valid(aer->log_page_id)) {
+ /*
+ * Repost another asynchronous event request to replace the one
+ * that just completed.
+ */
+ nvme_notify_async_consumers(ctrlr, &aer->cpl, aer->log_page_id,
+ NULL, 0);
+ nvme_ctrlr_construct_and_submit_aer(ctrlr, aer);
+ goto out;
+ }
+
+ aer->log_page_size = 0;
+ len = nvme_ctrlr_get_log_page_size(aer->ctrlr, aer->log_page_id);
+ nvme_ctrlr_cmd_get_log_page(aer->ctrlr, aer->log_page_id,
+ NVME_GLOBAL_NAMESPACE_TAG, aer->log_page_buffer, len,
+ nvme_ctrlr_aer_done, aer);
+ mtx_lock(&aer->mtx);
+ while (aer->log_page_size == 0)
+ mtx_sleep(aer, &aer->mtx, PRIBIO, "nvme_pt", 0);
+ mtx_unlock(&aer->mtx);
+
+ if (aer->log_page_size != (uint32_t)-1) {
+ /*
+ * If the log page fetch for some reason completed with an
+ * error, don't pass log page data to the consumers. In
+ * practice, this case should never happen.
+ */
+ nvme_notify_async_consumers(aer->ctrlr, &aer->cpl,
+ aer->log_page_id, NULL, 0);
+ goto out;
+ }
+
+ /* Convert data to host endian */
+ switch (aer->log_page_id) {
+ case NVME_LOG_ERROR: {
+ struct nvme_error_information_entry *err =
+ (struct nvme_error_information_entry *)aer->log_page_buffer;
+ for (int i = 0; i < (aer->ctrlr->cdata.elpe + 1); i++)
+ nvme_error_information_entry_swapbytes(err++);
+ break;
+ }
+ case NVME_LOG_HEALTH_INFORMATION:
+ nvme_health_information_page_swapbytes(
+ (struct nvme_health_information_page *)aer->log_page_buffer);
+ break;
+ case NVME_LOG_CHANGED_NAMESPACE:
+ nvme_ns_list_swapbytes(
+ (struct nvme_ns_list *)aer->log_page_buffer);
+ break;
+ case NVME_LOG_COMMAND_EFFECT:
+ nvme_command_effects_page_swapbytes(
+ (struct nvme_command_effects_page *)aer->log_page_buffer);
+ break;
+ case NVME_LOG_RES_NOTIFICATION:
+ nvme_res_notification_page_swapbytes(
+ (struct nvme_res_notification_page *)aer->log_page_buffer);
+ break;
+ case NVME_LOG_SANITIZE_STATUS:
+ nvme_sanitize_status_page_swapbytes(
+ (struct nvme_sanitize_status_page *)aer->log_page_buffer);
+ break;
+ default:
+ break;
+ }
+
+ if (aer->log_page_id == NVME_LOG_HEALTH_INFORMATION) {
+ struct nvme_health_information_page *health_info =
+ (struct nvme_health_information_page *)aer->log_page_buffer;
+
+ /*
+ * Critical warnings reported through the SMART/health log page
+ * are persistent, so clear the associated bits in the async
+ * event config so that we do not receive repeated notifications
+ * for the same event.
+ */
+ nvme_ctrlr_log_critical_warnings(aer->ctrlr,
+ health_info->critical_warning);
+ aer->ctrlr->async_event_config &=
+ ~health_info->critical_warning;
+ nvme_ctrlr_cmd_set_async_event_config(aer->ctrlr,
+ aer->ctrlr->async_event_config, NULL, NULL);
+ } else if (aer->log_page_id == NVME_LOG_CHANGED_NAMESPACE) {
+ struct nvme_ns_list *nsl =
+ (struct nvme_ns_list *)aer->log_page_buffer;
+ for (int i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) {
+ if (nsl->ns[i] > NVME_MAX_NAMESPACES)
+ break;
+ nvme_notify_ns(aer->ctrlr, nsl->ns[i]);
+ }
+ }
+
+ /*
+ * Pass the cpl data from the original async event completion, not the
+ * log page fetch.
+ */
+ nvme_notify_async_consumers(aer->ctrlr, &aer->cpl,
+ aer->log_page_id, aer->log_page_buffer, aer->log_page_size);
+
+ /*
+ * Repost another asynchronous event request to replace the one
+ * that just completed.
+ */
+out:
+ nvme_ctrlr_construct_and_submit_aer(ctrlr, aer);
+}
+
/*
* Poll all the queues enabled on the device for completion.
*/
@@ -1574,13 +1609,8 @@ nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev)
/*
* Create 2 threads for the taskqueue. The reset thread will block when
* it detects that the controller has failed until all I/O has been
- * failed up the stack. The fail_req task needs to be able to run in
- * this case to finish the request failure for some cases.
- *
- * We could partially solve this race by draining the failed requeust
- * queue before proceding to free the sim, though nothing would stop
- * new I/O from coming in after we do that drain, but before we reach
- * cam_sim_free, so this big hammer is used instead.
+ * failed up the stack. The second thread is used for AER events, which
+ * can block, but only briefly for memory and log page fetching.
*/
ctrlr->taskqueue = taskqueue_create("nvme_taskq", M_WAITOK,
taskqueue_thread_enqueue, &ctrlr->taskqueue);
@@ -1590,7 +1620,12 @@ nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev)
ctrlr->is_initialized = false;
ctrlr->notification_sent = 0;
TASK_INIT(&ctrlr->reset_task, 0, nvme_ctrlr_reset_task, ctrlr);
- STAILQ_INIT(&ctrlr->fail_req);
+ for (int i = 0; i < NVME_MAX_ASYNC_EVENTS; i++) {
+ struct nvme_async_event_request *aer = &ctrlr->aer[i];
+
+ TASK_INIT(&aer->task, 0, nvme_ctrlr_aer_task, aer);
+ mtx_init(&aer->mtx, "AER mutex", NULL, MTX_DEF);
+ }
ctrlr->is_failed = false;
make_dev_args_init(&md_args);
@@ -1678,8 +1713,14 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev)
}
noadminq:
- if (ctrlr->taskqueue)
+ if (ctrlr->taskqueue) {
taskqueue_free(ctrlr->taskqueue);
+ for (int i = 0; i < NVME_MAX_ASYNC_EVENTS; i++) {
+ struct nvme_async_event_request *aer = &ctrlr->aer[i];
+
+ mtx_destroy(&aer->mtx);
+ }
+ }
if (ctrlr->tag)
bus_teardown_intr(ctrlr->dev, ctrlr->res, ctrlr->tag);
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
index 949e69ec9290..36f00fedc48e 100644
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -123,6 +123,8 @@ struct nvme_request {
struct nvme_async_event_request {
struct nvme_controller *ctrlr;
struct nvme_request *req;
+ struct task task;
+ struct mtx mtx;
struct nvme_completion cpl;
uint32_t log_page_id;
uint32_t log_page_size;
@@ -307,8 +309,6 @@ struct nvme_controller {
bool isr_warned;
bool is_initialized;
- STAILQ_HEAD(, nvme_request) fail_req;
-
/* Host Memory Buffer */
int hmb_nchunks;
size_t hmb_chunk;
diff --git a/sys/dev/nvmf/host/nvmf.c b/sys/dev/nvmf/host/nvmf.c
index dbdd4568bdf1..1ac0d142443b 100644
--- a/sys/dev/nvmf/host/nvmf.c
+++ b/sys/dev/nvmf/host/nvmf.c
@@ -27,6 +27,7 @@
#include <dev/nvmf/host/nvmf_var.h>
static struct cdevsw nvmf_cdevsw;
+static struct taskqueue *nvmf_tq;
bool nvmf_fail_disconnect = false;
SYSCTL_BOOL(_kern_nvmf, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN,
@@ -34,7 +35,10 @@ SYSCTL_BOOL(_kern_nvmf, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN,
MALLOC_DEFINE(M_NVMF, "nvmf", "NVMe over Fabrics host");
+static void nvmf_controller_loss_task(void *arg, int pending);
static void nvmf_disconnect_task(void *arg, int pending);
+static void nvmf_request_reconnect(struct nvmf_softc *sc);
+static void nvmf_request_reconnect_task(void *arg, int pending);
static void nvmf_shutdown_pre_sync(void *arg, int howto);
static void nvmf_shutdown_post_sync(void *arg, int howto);
@@ -294,6 +298,9 @@ nvmf_establish_connection(struct nvmf_softc *sc, nvlist_t *nvl)
admin = nvlist_get_nvlist(nvl, "admin");
io = nvlist_get_nvlist_array(nvl, "io", &num_io_queues);
kato = dnvlist_get_number(nvl, "kato", 0);
+ sc->reconnect_delay = dnvlist_get_number(nvl, "reconnect_delay", 0);
+ sc->controller_loss_timeout = dnvlist_get_number(nvl,
+ "controller_loss_timeout", 0);
/* Setup the admin queue. */
sc->admin = nvmf_init_qp(sc, trtype, admin, "admin queue", 0);
@@ -504,6 +511,10 @@ nvmf_attach(device_t dev)
callout_init(&sc->ka_tx_timer, 1);
sx_init(&sc->connection_lock, "nvmf connection");
TASK_INIT(&sc->disconnect_task, 0, nvmf_disconnect_task, sc);
+ TIMEOUT_TASK_INIT(nvmf_tq, &sc->controller_loss_task, 0,
+ nvmf_controller_loss_task, sc);
+ TIMEOUT_TASK_INIT(nvmf_tq, &sc->request_reconnect_task, 0,
+ nvmf_request_reconnect_task, sc);
oid = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "ioq",
@@ -603,7 +614,9 @@ out:
nvmf_destroy_aer(sc);
- taskqueue_drain(taskqueue_thread, &sc->disconnect_task);
+ taskqueue_drain_timeout(nvmf_tq, &sc->request_reconnect_task);
+ taskqueue_drain_timeout(nvmf_tq, &sc->controller_loss_task);
+ taskqueue_drain(nvmf_tq, &sc->disconnect_task);
sx_destroy(&sc->connection_lock);
nvlist_destroy(sc->rparams);
free(sc->cdata, M_NVMF);
@@ -613,7 +626,7 @@ out:
void
nvmf_disconnect(struct nvmf_softc *sc)
{
- taskqueue_enqueue(taskqueue_thread, &sc->disconnect_task);
+ taskqueue_enqueue(nvmf_tq, &sc->disconnect_task);
}
static void
@@ -676,6 +689,74 @@ nvmf_disconnect_task(void *arg, int pending __unused)
nvmf_destroy_qp(sc->admin);
sc->admin = NULL;
+ if (sc->reconnect_delay != 0)
+ nvmf_request_reconnect(sc);
+ if (sc->controller_loss_timeout != 0)
+ taskqueue_enqueue_timeout(nvmf_tq,
+ &sc->controller_loss_task, sc->controller_loss_timeout *
+ hz);
+
+ sx_xunlock(&sc->connection_lock);
+}
+
+static void
+nvmf_controller_loss_task(void *arg, int pending)
+{
+ struct nvmf_softc *sc = arg;
+ device_t dev;
+ int error;
+
+ bus_topo_lock();
+ sx_xlock(&sc->connection_lock);
+ if (sc->admin != NULL || sc->detaching) {
+ /* Reconnected or already detaching. */
+ sx_xunlock(&sc->connection_lock);
+ bus_topo_unlock();
+ return;
+ }
+
+ sc->controller_timedout = true;
+ sx_xunlock(&sc->connection_lock);
+
+ /*
+ * XXX: Doing this from here is a bit ugly. We don't have an
+ * extra reference on `dev` but bus_topo_lock should block any
+ * concurrent device_delete_child invocations.
+ */
+ dev = sc->dev;
+ error = device_delete_child(root_bus, dev);
+ if (error != 0)
+ device_printf(dev,
+ "failed to detach after controller loss: %d\n", error);
+ bus_topo_unlock();
+}
+
+static void
+nvmf_request_reconnect(struct nvmf_softc *sc)
+{
+ char buf[64];
+
+ sx_assert(&sc->connection_lock, SX_LOCKED);
+
+ snprintf(buf, sizeof(buf), "name=\"%s\"", device_get_nameunit(sc->dev));
+ devctl_notify("nvme", "controller", "RECONNECT", buf);
+ taskqueue_enqueue_timeout(nvmf_tq, &sc->request_reconnect_task,
+ sc->reconnect_delay * hz);
+}
+
+static void
+nvmf_request_reconnect_task(void *arg, int pending)
+{
+ struct nvmf_softc *sc = arg;
+
+ sx_xlock(&sc->connection_lock);
+ if (sc->admin != NULL || sc->detaching || sc->controller_timedout) {
+ /* Reconnected or already detaching. */
+ sx_xunlock(&sc->connection_lock);
+ return;
+ }
+
+ nvmf_request_reconnect(sc);
sx_xunlock(&sc->connection_lock);
}
@@ -699,7 +780,7 @@ nvmf_reconnect_host(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv)
}
sx_xlock(&sc->connection_lock);
- if (sc->admin != NULL || sc->detaching) {
+ if (sc->admin != NULL || sc->detaching || sc->controller_timedout) {
error = EBUSY;
goto out;
}
@@ -745,6 +826,9 @@ nvmf_reconnect_host(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv)
nvmf_reconnect_sim(sc);
nvmf_rescan_all_ns(sc);
+
+ taskqueue_cancel_timeout(nvmf_tq, &sc->request_reconnect_task, NULL);
+ taskqueue_cancel_timeout(nvmf_tq, &sc->controller_loss_task, NULL);
out:
sx_xunlock(&sc->connection_lock);
nvlist_destroy(nvl);
@@ -852,7 +936,21 @@ nvmf_detach(device_t dev)
}
free(sc->io, M_NVMF);
- taskqueue_drain(taskqueue_thread, &sc->disconnect_task);
+ taskqueue_drain(nvmf_tq, &sc->disconnect_task);
+ if (taskqueue_cancel_timeout(nvmf_tq, &sc->request_reconnect_task,
+ NULL) != 0)
+ taskqueue_drain_timeout(nvmf_tq, &sc->request_reconnect_task);
+
+ /*
+ * Don't cancel/drain the controller loss task if that task
+ * has fired and is triggering the detach.
+ */
+ if (!sc->controller_timedout) {
+ if (taskqueue_cancel_timeout(nvmf_tq, &sc->controller_loss_task,
+ NULL) != 0)
+ taskqueue_drain_timeout(nvmf_tq,
+ &sc->controller_loss_task);
+ }
if (sc->admin != NULL)
nvmf_destroy_qp(sc->admin);
@@ -1154,14 +1252,25 @@ static struct cdevsw nvmf_cdevsw = {
static int
nvmf_modevent(module_t mod, int what, void *arg)
{
+ int error;
+
switch (what) {
case MOD_LOAD:
- return (nvmf_ctl_load());
+ error = nvmf_ctl_load();
+ if (error != 0)
+ return (error);
+
+ nvmf_tq = taskqueue_create("nvmf", M_WAITOK | M_ZERO,
+ taskqueue_thread_enqueue, &nvmf_tq);
+ taskqueue_start_threads(&nvmf_tq, 1, PWAIT, "nvmf taskq");
+ return (0);
case MOD_QUIESCE:
return (0);
case MOD_UNLOAD:
nvmf_ctl_unload();
destroy_dev_drain(&nvmf_cdevsw);
+ if (nvmf_tq != NULL)
+ taskqueue_free(nvmf_tq);
return (0);
default:
return (EOPNOTSUPP);
diff --git a/sys/dev/nvmf/host/nvmf_var.h b/sys/dev/nvmf/host/nvmf_var.h
index e45a31f413a4..606245b3969c 100644
--- a/sys/dev/nvmf/host/nvmf_var.h
+++ b/sys/dev/nvmf/host/nvmf_var.h
@@ -75,9 +75,15 @@ struct nvmf_softc {
struct callout ka_rx_timer;
sbintime_t ka_rx_sbt;
+ struct timeout_task request_reconnect_task;
+ struct timeout_task controller_loss_task;
+ uint32_t reconnect_delay;
+ uint32_t controller_loss_timeout;
+
struct sx connection_lock;
struct task disconnect_task;
bool detaching;
+ bool controller_timedout;
u_int num_aer;
struct nvmf_aer *aer;
diff --git a/sys/dev/nvmf/nvmf.h b/sys/dev/nvmf/nvmf.h
index d4e7b1511e9d..9b2b4c1dea40 100644
--- a/sys/dev/nvmf/nvmf.h
+++ b/sys/dev/nvmf/nvmf.h
@@ -27,6 +27,13 @@
#define NVMF_NN (1024)
/*
+ * Default timeouts for Fabrics hosts. These match values used by
+ * Linux.
+ */
+#define NVMF_DEFAULT_RECONNECT_DELAY 10
+#define NVMF_DEFAULT_CONTROLLER_LOSS 600
+
+/*
* (data, size) is the userspace buffer for a packed nvlist.
*
* For requests that copyout an nvlist, len is the amount of data
@@ -68,6 +75,8 @@ struct nvmf_ioc_nv {
*
* number trtype
* number kato (optional)
+ * number reconnect_delay (optional)
+ * number controller_loss_timeout (optional)
* qpair handoff nvlist admin
* qpair handoff nvlist array io
* binary cdata struct nvme_controller_data
@@ -81,6 +90,8 @@ struct nvmf_ioc_nv {
* string hostnqn
* number num_io_queues
* number kato (optional)
+ * number reconnect_delay (optional)
+ * number controller_loss_timeout (optional)
* number io_qsize
* bool sq_flow_control
*
diff --git a/sys/dev/ofw/ofw_bus_subr.c b/sys/dev/ofw/ofw_bus_subr.c
index 4d0479dfb957..b99d784929bc 100644
--- a/sys/dev/ofw/ofw_bus_subr.c
+++ b/sys/dev/ofw/ofw_bus_subr.c
@@ -634,11 +634,89 @@ ofw_bus_find_iparent(phandle_t node)
return (iparent);
}
+static phandle_t
+ofw_bus_search_iparent(phandle_t node)
+{
+ phandle_t iparent;
+
+ do {
+ if (OF_getencprop(node, "interrupt-parent", &iparent,
+ sizeof(iparent)) > 0) {
+ node = OF_node_from_xref(iparent);
+ } else {
+ node = OF_parent(node);
+ }
+ if (node == 0)
+ return (0);
+ } while (!OF_hasprop(node, "#interrupt-cells"));
+
+ return (OF_xref_from_node(node));
+}
+
+static int
+ofw_bus_traverse_imap(phandle_t inode, phandle_t node, uint32_t *intr,
+ int intrsz, pcell_t *res, int ressz, phandle_t *iparentp)
+{
+ struct ofw_bus_iinfo ii;
+ void *reg;
+ uint32_t *intrp;
+ phandle_t iparent;
+ int rv = 0;
+
+ /* We already have an interrupt controller */
+ if (OF_hasprop(node, "interrupt-controller"))
+ return (0);
+
+ intrp = malloc(intrsz, M_OFWPROP, M_WAITOK);
+ memcpy(intrp, intr, intrsz);
+
+ while (true) {
+ /* There is no interrupt-map to follow */
+ if (!OF_hasprop(inode, "interrupt-map")) {
+ free(intrp, M_OFWPROP);
+ return (0);
+ }
+
+ memset(&ii, 0, sizeof(ii));
+ ofw_bus_setup_iinfo(inode, &ii, sizeof(cell_t));
+
+ reg = NULL;
+ if (ii.opi_addrc > 0)
+ reg = malloc(ii.opi_addrc, M_OFWPROP, M_WAITOK);
+
+ rv = ofw_bus_lookup_imap(node, &ii, reg, ii.opi_addrc, intrp,
+ intrsz, res, ressz, &iparent);
+
+ free(reg, M_OFWPROP);
+ free(ii.opi_imap, M_OFWPROP);
+ free(ii.opi_imapmsk, M_OFWPROP);
+ free(intrp, M_OFWPROP);
+
+ if (rv == 0)
+ return (0);
+
+ node = inode;
+ inode = OF_node_from_xref(iparent);
+
+ /* Stop when we have an interrupt controller */
+ if (OF_hasprop(inode, "interrupt-controller")) {
+ *iparentp = iparent;
+ return (rv);
+ }
+
+ intrsz = rv * sizeof(pcell_t);
+ intrp = malloc(intrsz, M_OFWPROP, M_WAITOK);
+ memcpy(intrp, res, intrsz);
+ }
+}
+
int
ofw_bus_intr_to_rl(device_t dev, phandle_t node,
struct resource_list *rl, int *rlen)
{
- phandle_t iparent;
+ phandle_t iparent, iparent_node;
+ uint32_t result[16];
+ uint32_t intrpcells, *intrp;
uint32_t icells, *intr;
int err, i, irqnum, nintr, rid;
bool extended;
@@ -646,15 +724,16 @@ ofw_bus_intr_to_rl(device_t dev, phandle_t node,
nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr),
(void **)&intr);
if (nintr > 0) {
- iparent = ofw_bus_find_iparent(node);
+ iparent = ofw_bus_search_iparent(node);
if (iparent == 0) {
device_printf(dev, "No interrupt-parent found, "
"assuming direct parent\n");
iparent = OF_parent(node);
iparent = OF_xref_from_node(iparent);
}
- if (OF_searchencprop(OF_node_from_xref(iparent),
- "#interrupt-cells", &icells, sizeof(icells)) == -1) {
+ iparent_node = OF_node_from_xref(iparent);
+ if (OF_searchencprop(iparent_node, "#interrupt-cells", &icells,
+ sizeof(icells)) == -1) {
device_printf(dev, "Missing #interrupt-cells "
"property, assuming <1>\n");
icells = 1;
@@ -677,7 +756,8 @@ ofw_bus_intr_to_rl(device_t dev, phandle_t node,
for (i = 0; i < nintr; i += icells) {
if (extended) {
iparent = intr[i++];
- if (OF_searchencprop(OF_node_from_xref(iparent),
+ iparent_node = OF_node_from_xref(iparent);
+ if (OF_searchencprop(iparent_node,
"#interrupt-cells", &icells, sizeof(icells)) == -1) {
device_printf(dev, "Missing #interrupt-cells "
"property\n");
@@ -691,7 +771,16 @@ ofw_bus_intr_to_rl(device_t dev, phandle_t node,
break;
}
}
- irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]);
+
+ intrp = &intr[i];
+ intrpcells = ofw_bus_traverse_imap(iparent_node, node, intrp,
+ icells * sizeof(intr[0]), result, sizeof(result), &iparent);
+ if (intrpcells > 0)
+ intrp = result;
+ else
+ intrpcells = icells;
+
+ irqnum = ofw_bus_map_intr(dev, iparent, intrpcells, intrp);
resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1);
}
if (rlen != NULL)
diff --git a/sys/dev/qlnx/qlnxe/qlnx_os.c b/sys/dev/qlnx/qlnxe/qlnx_os.c
index 05ec69a70dfe..4ad190374f87 100644
--- a/sys/dev/qlnx/qlnxe/qlnx_os.c
+++ b/sys/dev/qlnx/qlnxe/qlnx_os.c
@@ -30,6 +30,8 @@
* Author : David C Somayajulu, Cavium, Inc., San Jose, CA 95131.
*/
+#include "opt_inet.h"
+
#include <sys/cdefs.h>
#include "qlnx_os.h"
#include "bcm_osal.h"
@@ -2306,8 +2308,6 @@ qlnx_init_ifnet(device_t dev, qlnx_host_t *ha)
else if (device_id == QLOGIC_PCI_DEVICE_ID_1644)
if_setbaudrate(ifp, IF_Gbps(100));
- if_setcapabilities(ifp, IFCAP_LINKSTATE);
-
if_setinitfn(ifp, qlnx_init);
if_setsoftc(ifp, ha);
if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
@@ -2341,7 +2341,6 @@ qlnx_init_ifnet(device_t dev, qlnx_host_t *ha)
if_setcapabilities(ifp, IFCAP_HWCSUM);
if_setcapabilitiesbit(ifp, IFCAP_JUMBO_MTU, 0);
-
if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING, 0);
if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWFILTER, 0);
@@ -2350,6 +2349,8 @@ qlnx_init_ifnet(device_t dev, qlnx_host_t *ha)
if_setcapabilitiesbit(ifp, IFCAP_TSO4, 0);
if_setcapabilitiesbit(ifp, IFCAP_TSO6, 0);
if_setcapabilitiesbit(ifp, IFCAP_LRO, 0);
+ if_setcapabilitiesbit(ifp, IFCAP_LINKSTATE, 0);
+ if_setcapabilitiesbit(ifp, IFCAP_HWSTATS, 0);
if_sethwtsomax(ifp, QLNX_MAX_TSO_FRAME_SIZE -
(ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
@@ -2778,7 +2779,7 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data)
if (!p_ptt) {
QL_DPRINT1(ha, "ecore_ptt_acquire failed\n");
- ret = -1;
+ ret = ERESTART;
break;
}
@@ -2789,7 +2790,7 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data)
ecore_ptt_release(p_hwfn, p_ptt);
if (ret) {
- ret = -1;
+ ret = ENODEV;
break;
}
diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c
index c4282c723a44..8363de99a60a 100644
--- a/sys/dev/random/fortuna.c
+++ b/sys/dev/random/fortuna.c
@@ -341,6 +341,13 @@ random_fortuna_process_event(struct harvest_event *event)
u_int pl;
RANDOM_RESEED_LOCK();
+ /*
+ * Run SP 800-90B health tests on the source if so configured.
+ */
+ if (!random_harvest_healthtest(event)) {
+ RANDOM_RESEED_UNLOCK();
+ return;
+ }
/*-
* FS&K - P_i = P_i|<harvested stuff>
* Accumulate the event into the appropriate pool
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index ee37bda36496..c7762967c4fb 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -88,6 +88,8 @@ static void random_sources_feed(void);
static __read_mostly bool epoch_inited;
static __read_mostly epoch_t rs_epoch;
+static const char *random_source_descr[ENTROPYSOURCE];
+
/*
* How many events to queue up. We create this many items in
* an 'empty' queue, then transfer them to the 'harvest' queue with
@@ -131,30 +133,14 @@ static struct harvest_context {
/* The context of the kernel thread processing harvested entropy */
struct proc *hc_kthread_proc;
/*
- * Lockless ring buffer holding entropy events
- * If ring.in == ring.out,
- * the buffer is empty.
- * If ring.in != ring.out,
- * the buffer contains harvested entropy.
- * If (ring.in + 1) == ring.out (mod RANDOM_RING_MAX),
- * the buffer is full.
- *
- * NOTE: ring.in points to the last added element,
- * and ring.out points to the last consumed element.
- *
- * The ring.in variable needs locking as there are multiple
- * sources to the ring. Only the sources may change ring.in,
- * but the consumer may examine it.
- *
- * The ring.out variable does not need locking as there is
- * only one consumer. Only the consumer may change ring.out,
- * but the sources may examine it.
+ * A pair of buffers for queued events. New events are added to the
+ * active queue while the kthread processes the other one in parallel.
*/
- struct entropy_ring {
+ struct entropy_buffer {
struct harvest_event ring[RANDOM_RING_MAX];
- volatile u_int in;
- volatile u_int out;
- } hc_entropy_ring;
+ u_int pos;
+ } hc_entropy_buf[2];
+ u_int hc_active_buf;
struct fast_entropy_accumulator {
volatile u_int pos;
uint32_t buf[RANDOM_ACCUM_MAX];
@@ -183,37 +169,41 @@ random_harvestq_fast_process_event(struct harvest_event *event)
static void
random_kthread(void)
{
- u_int maxloop, ring_out, i;
+ struct harvest_context *hc;
- /*
- * Locking is not needed as this is the only place we modify ring.out, and
- * we only examine ring.in without changing it. Both of these are volatile,
- * and this is a unique thread.
- */
+ hc = &harvest_context;
for (random_kthread_control = 1; random_kthread_control;) {
- /* Deal with events, if any. Restrict the number we do in one go. */
- maxloop = RANDOM_RING_MAX;
- while (harvest_context.hc_entropy_ring.out != harvest_context.hc_entropy_ring.in) {
- ring_out = (harvest_context.hc_entropy_ring.out + 1)%RANDOM_RING_MAX;
- random_harvestq_fast_process_event(harvest_context.hc_entropy_ring.ring + ring_out);
- harvest_context.hc_entropy_ring.out = ring_out;
- if (!--maxloop)
- break;
- }
+ struct entropy_buffer *buf;
+ u_int entries;
+
+ /* Deal with queued events. */
+ RANDOM_HARVEST_LOCK();
+ buf = &hc->hc_entropy_buf[hc->hc_active_buf];
+ entries = buf->pos;
+ buf->pos = 0;
+ hc->hc_active_buf = (hc->hc_active_buf + 1) %
+ nitems(hc->hc_entropy_buf);
+ RANDOM_HARVEST_UNLOCK();
+ for (u_int i = 0; i < entries; i++)
+ random_harvestq_fast_process_event(&buf->ring[i]);
+
+ /* Poll sources of noise. */
random_sources_feed();
+
/* XXX: FIX!! Increase the high-performance data rate? Need some measurements first. */
- for (i = 0; i < RANDOM_ACCUM_MAX; i++) {
- if (harvest_context.hc_entropy_fast_accumulator.buf[i]) {
- random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), RANDOM_UMA);
- harvest_context.hc_entropy_fast_accumulator.buf[i] = 0;
+ for (u_int i = 0; i < RANDOM_ACCUM_MAX; i++) {
+ if (hc->hc_entropy_fast_accumulator.buf[i]) {
+ random_harvest_direct(&hc->hc_entropy_fast_accumulator.buf[i],
+ sizeof(hc->hc_entropy_fast_accumulator.buf[0]), RANDOM_UMA);
+ hc->hc_entropy_fast_accumulator.buf[i] = 0;
}
}
/* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */
- tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-",
+ tsleep_sbt(&hc->hc_kthread_proc, 0, "-",
SBT_1S/RANDOM_KTHREAD_HZ, 0, C_PREL(1));
}
random_kthread_control = -1;
- wakeup(&harvest_context.hc_kthread_proc);
+ wakeup(&hc->hc_kthread_proc);
kproc_exit(0);
/* NOTREACHED */
}
@@ -311,6 +301,230 @@ random_sources_feed(void)
explicit_bzero(entropy, sizeof(entropy));
}
+/*
+ * State used for conducting NIST SP 800-90B health tests on entropy sources.
+ */
+static struct health_test_softc {
+ uint32_t ht_rct_value[HARVESTSIZE + 1];
+ u_int ht_rct_count; /* number of samples with the same value */
+ u_int ht_rct_limit; /* constant after init */
+
+ uint32_t ht_apt_value[HARVESTSIZE + 1];
+ u_int ht_apt_count; /* number of samples with the same value */
+ u_int ht_apt_seq; /* sequence number of the last sample */
+ u_int ht_apt_cutoff; /* constant after init */
+
+ uint64_t ht_total_samples;
+ bool ondemand; /* Set to true to restart the state machine */
+ enum {
+ INIT = 0, /* initial state */
+ DISABLED, /* health checking is disabled */
+ STARTUP, /* doing startup tests, samples are discarded */
+ STEADY, /* steady-state operation */
+ FAILED, /* health check failed, discard samples */
+ } ht_state;
+} healthtest[ENTROPYSOURCE];
+
+#define RANDOM_SELFTEST_STARTUP_SAMPLES 1024 /* 4.3, requirement 4 */
+#define RANDOM_SELFTEST_APT_WINDOW 512 /* 4.4.2 */
+
+static void
+copy_event(uint32_t dst[static HARVESTSIZE + 1],
+ const struct harvest_event *event)
+{
+ memset(dst, 0, sizeof(uint32_t) * (HARVESTSIZE + 1));
+ memcpy(dst, event->he_entropy, event->he_size);
+ dst[HARVESTSIZE] = event->he_somecounter;
+}
+
+static void
+random_healthtest_rct_init(struct health_test_softc *ht,
+ const struct harvest_event *event)
+{
+ ht->ht_rct_count = 1;
+ copy_event(ht->ht_rct_value, event);
+}
+
+/*
+ * Apply the repitition count test to a sample.
+ *
+ * Return false if the test failed, i.e., we observed >= C consecutive samples
+ * with the same value, and true otherwise.
+ */
+static bool
+random_healthtest_rct_next(struct health_test_softc *ht,
+ const struct harvest_event *event)
+{
+ uint32_t val[HARVESTSIZE + 1];
+
+ copy_event(val, event);
+ if (memcmp(val, ht->ht_rct_value, sizeof(ht->ht_rct_value)) != 0) {
+ ht->ht_rct_count = 1;
+ memcpy(ht->ht_rct_value, val, sizeof(ht->ht_rct_value));
+ return (true);
+ } else {
+ ht->ht_rct_count++;
+ return (ht->ht_rct_count < ht->ht_rct_limit);
+ }
+}
+
+static void
+random_healthtest_apt_init(struct health_test_softc *ht,
+ const struct harvest_event *event)
+{
+ ht->ht_apt_count = 1;
+ ht->ht_apt_seq = 1;
+ copy_event(ht->ht_apt_value, event);
+}
+
+static bool
+random_healthtest_apt_next(struct health_test_softc *ht,
+ const struct harvest_event *event)
+{
+ uint32_t val[HARVESTSIZE + 1];
+
+ if (ht->ht_apt_seq == 0) {
+ random_healthtest_apt_init(ht, event);
+ return (true);
+ }
+
+ copy_event(val, event);
+ if (memcmp(val, ht->ht_apt_value, sizeof(ht->ht_apt_value)) == 0) {
+ ht->ht_apt_count++;
+ if (ht->ht_apt_count >= ht->ht_apt_cutoff)
+ return (false);
+ }
+
+ ht->ht_apt_seq++;
+ if (ht->ht_apt_seq == RANDOM_SELFTEST_APT_WINDOW)
+ ht->ht_apt_seq = 0;
+
+ return (true);
+}
+
+/*
+ * Run the health tests for the given event. This is assumed to be called from
+ * a serialized context.
+ */
+bool
+random_harvest_healthtest(const struct harvest_event *event)
+{
+ struct health_test_softc *ht;
+
+ ht = &healthtest[event->he_source];
+
+ /*
+ * Was on-demand testing requested? Restart the state machine if so,
+ * restarting the startup tests.
+ */
+ if (atomic_load_bool(&ht->ondemand)) {
+ atomic_store_bool(&ht->ondemand, false);
+ ht->ht_state = INIT;
+ }
+
+ switch (ht->ht_state) {
+ case __predict_false(INIT):
+ /* Store the first sample and initialize test state. */
+ random_healthtest_rct_init(ht, event);
+ random_healthtest_apt_init(ht, event);
+ ht->ht_total_samples = 0;
+ ht->ht_state = STARTUP;
+ return (false);
+ case DISABLED:
+ /* No health testing for this source. */
+ return (true);
+ case STEADY:
+ case STARTUP:
+ ht->ht_total_samples++;
+ if (random_healthtest_rct_next(ht, event) &&
+ random_healthtest_apt_next(ht, event)) {
+ if (ht->ht_state == STARTUP &&
+ ht->ht_total_samples >=
+ RANDOM_SELFTEST_STARTUP_SAMPLES) {
+ printf(
+ "random: health test passed for source %s\n",
+ random_source_descr[event->he_source]);
+ ht->ht_state = STEADY;
+ }
+ return (ht->ht_state == STEADY);
+ }
+ ht->ht_state = FAILED;
+ printf(
+ "random: health test failed for source %s, discarding samples\n",
+ random_source_descr[event->he_source]);
+ /* FALLTHROUGH */
+ case FAILED:
+ return (false);
+ }
+}
+
+static bool nist_healthtest_enabled = false;
+SYSCTL_BOOL(_kern_random, OID_AUTO, nist_healthtest_enabled,
+ CTLFLAG_RDTUN, &nist_healthtest_enabled, 0,
+ "Enable NIST SP 800-90B health tests for noise sources");
+
+static void
+random_healthtest_init(enum random_entropy_source source)
+{
+ struct health_test_softc *ht;
+
+ ht = &healthtest[source];
+ KASSERT(ht->ht_state == INIT,
+ ("%s: health test state is %d for source %d",
+ __func__, ht->ht_state, source));
+
+ /*
+ * If health-testing is enabled, validate all sources except CACHED and
+ * VMGENID: they are deterministic sources used only a small, fixed
+ * number of times, so statistical testing is not applicable.
+ */
+ if (!nist_healthtest_enabled ||
+ source == RANDOM_CACHED || source == RANDOM_PURE_VMGENID) {
+ ht->ht_state = DISABLED;
+ return;
+ }
+
+ /*
+ * Set cutoff values for the two tests, assuming that each sample has
+ * min-entropy of 1 bit and allowing for an error rate of 1 in 2^{34}.
+ * With a sample rate of RANDOM_KTHREAD_HZ, we expect to see an false
+ * positive once in ~54.5 years.
+ *
+ * The RCT limit comes from the formula in section 4.4.1.
+ *
+ * The APT cutoff is calculated using the formula in section 4.4.2
+ * footnote 10 with the window size changed from 512 to 511, since the
+ * test as written counts the number of samples equal to the first
+ * sample in the window, and thus tests W-1 samples.
+ */
+ ht->ht_rct_limit = 35;
+ ht->ht_apt_cutoff = 330;
+}
+
+static int
+random_healthtest_ondemand(SYSCTL_HANDLER_ARGS)
+{
+ u_int mask, source;
+ int error;
+
+ mask = 0;
+ error = sysctl_handle_int(oidp, &mask, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ while (mask != 0) {
+ source = ffs(mask) - 1;
+ if (source < nitems(healthtest))
+ atomic_store_bool(&healthtest[source].ondemand, true);
+ mask &= ~(1u << source);
+ }
+ return (0);
+}
+SYSCTL_PROC(_kern_random, OID_AUTO, nist_healthtest_ondemand,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0,
+ random_healthtest_ondemand, "I",
+ "Re-run NIST SP 800-90B startup health tests for a noise source");
+
static int
random_check_uint_harvestmask(SYSCTL_HANDLER_ARGS)
{
@@ -374,7 +588,8 @@ static const char *random_source_descr[ENTROPYSOURCE] = {
[RANDOM_SWI] = "SWI",
[RANDOM_FS_ATIME] = "FS_ATIME",
[RANDOM_UMA] = "UMA",
- [RANDOM_CALLOUT] = "CALLOUT", /* ENVIRONMENTAL_END */
+ [RANDOM_CALLOUT] = "CALLOUT",
+ [RANDOM_RANDOMDEV] = "RANDOMDEV", /* ENVIRONMENTAL_END */
[RANDOM_PURE_OCTEON] = "PURE_OCTEON", /* PURE_START */
[RANDOM_PURE_SAFE] = "PURE_SAFE",
[RANDOM_PURE_GLXSB] = "PURE_GLXSB",
@@ -435,7 +650,10 @@ random_harvestq_init(void *unused __unused)
hc_source_mask = almost_everything_mask;
RANDOM_HARVEST_INIT_LOCK();
- harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0;
+ harvest_context.hc_active_buf = 0;
+
+ for (int i = 0; i < ENTROPYSOURCE; i++)
+ random_healthtest_init(i);
}
SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_init, NULL);
@@ -540,9 +758,9 @@ SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_d
* This is supposed to be fast; do not do anything slow in here!
* It is also illegal (and morally reprehensible) to insert any
* high-rate data here. "High-rate" is defined as a data source
- * that will usually cause lots of failures of the "Lockless read"
- * check a few lines below. This includes the "always-on" sources
- * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources.
+ * that is likely to fill up the buffer in much less than 100ms.
+ * This includes the "always-on" sources like the Intel "rdrand"
+ * or the VIA Nehamiah "xstore" sources.
*/
/* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle
* counters are built in, but on older hardware it will do a real time clock
@@ -551,28 +769,29 @@ SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_d
void
random_harvest_queue_(const void *entropy, u_int size, enum random_entropy_source origin)
{
+ struct harvest_context *hc;
+ struct entropy_buffer *buf;
struct harvest_event *event;
- u_int ring_in;
- KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin));
+ KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE,
+ ("%s: origin %d invalid", __func__, origin));
+
+ hc = &harvest_context;
RANDOM_HARVEST_LOCK();
- ring_in = (harvest_context.hc_entropy_ring.in + 1)%RANDOM_RING_MAX;
- if (ring_in != harvest_context.hc_entropy_ring.out) {
- /* The ring is not full */
- event = harvest_context.hc_entropy_ring.ring + ring_in;
+ buf = &hc->hc_entropy_buf[hc->hc_active_buf];
+ if (buf->pos < RANDOM_RING_MAX) {
+ event = &buf->ring[buf->pos++];
event->he_somecounter = random_get_cyclecount();
event->he_source = origin;
- event->he_destination = harvest_context.hc_destination[origin]++;
+ event->he_destination = hc->hc_destination[origin]++;
if (size <= sizeof(event->he_entropy)) {
event->he_size = size;
memcpy(event->he_entropy, entropy, size);
- }
- else {
+ } else {
/* Big event, so squash it */
event->he_size = sizeof(event->he_entropy[0]);
event->he_entropy[0] = jenkins_hash(entropy, size, (uint32_t)(uintptr_t)event);
}
- harvest_context.hc_entropy_ring.in = ring_in;
}
RANDOM_HARVEST_UNLOCK();
}
diff --git a/sys/dev/random/random_harvestq.h b/sys/dev/random/random_harvestq.h
index 7804bf52aa4f..1d462500df85 100644
--- a/sys/dev/random/random_harvestq.h
+++ b/sys/dev/random/random_harvestq.h
@@ -49,4 +49,6 @@ random_get_cyclecount(void)
return ((uint32_t)get_cyclecount());
}
+bool random_harvest_healthtest(const struct harvest_event *event);
+
#endif /* SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED */
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index 9d1c7b1167c8..ced4dd8067d9 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -312,7 +312,7 @@ randomdev_accumulate(uint8_t *buf, u_int count)
for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
event.he_somecounter = random_get_cyclecount();
event.he_size = sizeof(event.he_entropy);
- event.he_source = RANDOM_CACHED;
+ event.he_source = RANDOM_RANDOMDEV;
event.he_destination = destination++; /* Harmless cheating */
memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy));
p_random_alg_context->ra_event_processor(&event);
diff --git a/sys/dev/regulator/regulator_fixed.c b/sys/dev/regulator/regulator_fixed.c
index 0a76da7140a0..55cdb5e4aeae 100644
--- a/sys/dev/regulator/regulator_fixed.c
+++ b/sys/dev/regulator/regulator_fixed.c
@@ -100,12 +100,8 @@ static struct gpio_entry *
regnode_get_gpio_entry(struct gpiobus_pin *gpio_pin)
{
struct gpio_entry *entry, *tmp;
- device_t busdev;
int rv;
- busdev = GPIO_GET_BUS(gpio_pin->dev);
- if (busdev == NULL)
- return (NULL);
entry = malloc(sizeof(struct gpio_entry), M_FIXEDREGULATOR,
M_WAITOK | M_ZERO);
@@ -122,8 +118,8 @@ regnode_get_gpio_entry(struct gpiobus_pin *gpio_pin)
}
/* Reserve pin. */
- /* XXX Can we call gpiobus_acquire_pin() with gpio_list_mtx held? */
- rv = gpiobus_acquire_pin(busdev, gpio_pin->pin);
+ /* XXX Can we call gpio_pin_acquire() with gpio_list_mtx held? */
+ rv = gpio_pin_acquire(gpio_pin);
if (rv != 0) {
mtx_unlock(&gpio_list_mtx);
free(entry, M_FIXEDREGULATOR);
diff --git a/sys/dev/sound/midi/midi.c b/sys/dev/sound/midi/midi.c
index fbfb69de2913..6753f864ba9c 100644
--- a/sys/dev/sound/midi/midi.c
+++ b/sys/dev/sound/midi/midi.c
@@ -30,12 +30,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
- /*
- * Parts of this file started out as NetBSD: midi.c 1.31
- * They are mostly gone. Still the most obvious will be the state
- * machine midi_in
- */
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
@@ -66,7 +60,6 @@
#include "mpu_if.h"
#include <dev/sound/midi/midiq.h>
-#include "synth_if.h"
MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
#ifndef KOBJMETHOD_END
@@ -79,17 +72,6 @@ enum midi_states {
MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
};
-/*
- * The MPU interface current has init() uninit() inqsize() outqsize()
- * callback() : fiddle with the tx|rx status.
- */
-
-#include "mpu_if.h"
-
-/*
- * /dev/rmidi Structure definitions
- */
-
#define MIDI_NAMELEN 16
struct snd_midi {
KOBJ_FIELDS;
@@ -115,95 +97,13 @@ struct snd_midi {
* complete command packets. */
struct proc *async;
struct cdev *dev;
- struct synth_midi *synth;
- int synth_flags;
TAILQ_ENTRY(snd_midi) link;
};
-struct synth_midi {
- KOBJ_FIELDS;
- struct snd_midi *m;
-};
-
-static synth_open_t midisynth_open;
-static synth_close_t midisynth_close;
-static synth_writeraw_t midisynth_writeraw;
-static synth_killnote_t midisynth_killnote;
-static synth_startnote_t midisynth_startnote;
-static synth_setinstr_t midisynth_setinstr;
-static synth_alloc_t midisynth_alloc;
-static synth_controller_t midisynth_controller;
-static synth_bender_t midisynth_bender;
-
-static kobj_method_t midisynth_methods[] = {
- KOBJMETHOD(synth_open, midisynth_open),
- KOBJMETHOD(synth_close, midisynth_close),
- KOBJMETHOD(synth_writeraw, midisynth_writeraw),
- KOBJMETHOD(synth_setinstr, midisynth_setinstr),
- KOBJMETHOD(synth_startnote, midisynth_startnote),
- KOBJMETHOD(synth_killnote, midisynth_killnote),
- KOBJMETHOD(synth_alloc, midisynth_alloc),
- KOBJMETHOD(synth_controller, midisynth_controller),
- KOBJMETHOD(synth_bender, midisynth_bender),
- KOBJMETHOD_END
-};
-
-DEFINE_CLASS(midisynth, midisynth_methods, 0);
-
-/*
- * Module Exports & Interface
- *
- * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan,
- * void *cookie)
- * int midi_uninit(struct snd_midi *)
- *
- * 0 == no error
- * EBUSY or other error
- *
- * int midi_in(struct snd_midi *, char *buf, int count)
- * int midi_out(struct snd_midi *, char *buf, int count)
- *
- * midi_{in,out} return actual size transfered
- *
- */
-
-/*
- * midi_devs tailq, holder of all rmidi instances protected by midistat_lock
- */
-
TAILQ_HEAD(, snd_midi) midi_devs;
-/*
- * /dev/midistat variables and declarations, protected by midistat_lock
- */
-
struct sx mstat_lock;
-static int midistat_isopen = 0;
-static struct sbuf midistat_sbuf;
-static struct cdev *midistat_dev;
-
-/*
- * /dev/midistat dev_t declarations
- */
-
-static d_open_t midistat_open;
-static d_close_t midistat_close;
-static d_read_t midistat_read;
-
-static struct cdevsw midistat_cdevsw = {
- .d_version = D_VERSION,
- .d_open = midistat_open,
- .d_close = midistat_close,
- .d_read = midistat_read,
- .d_name = "midistat",
-};
-
-/*
- * /dev/rmidi dev_t declarations, struct variable access is protected by
- * locks contained within the structure.
- */
-
static d_open_t midi_open;
static d_close_t midi_close;
static d_ioctl_t midi_ioctl;
@@ -222,41 +122,18 @@ static struct cdevsw midi_cdevsw = {
.d_name = "rmidi",
};
-/*
- * Prototypes of library functions
- */
-
static int midi_destroy(struct snd_midi *, int);
-static int midistat_prepare(struct sbuf * s);
static int midi_load(void);
static int midi_unload(void);
-/*
- * Misc declr.
- */
SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
"Midi driver");
-static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
- "Status device");
int midi_debug;
/* XXX: should this be moved into debug.midi? */
SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
-int midi_dumpraw;
-SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, "");
-
-int midi_instroff;
-SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, "");
-
-int midistat_verbose;
-SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW,
- &midistat_verbose, 0, "");
-
#define MIDI_DEBUG(l,a) if(midi_debug>=l) a
-/*
- * CODE START
- */
void
midistat_lock(void)
@@ -285,9 +162,6 @@ midistat_lockassert(void)
* what unit number is used.
*
* It is an error to call midi_init with an already used unit/channel combo.
- *
- * Returns NULL on error
- *
*/
struct snd_midi *
midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
@@ -326,9 +200,6 @@ midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
m = malloc(sizeof(*m), M_MIDI, M_WAITOK | M_ZERO);
- m->synth = malloc(sizeof(*m->synth), M_MIDI, M_WAITOK | M_ZERO);
- kobj_init((kobj_t)m->synth, &midisynth_class);
- m->synth->m = m;
kobj_init((kobj_t)m, cls);
inqsize = MPU_INQSIZE(m, cookie);
outqsize = MPU_OUTQSIZE(m, cookie);
@@ -393,7 +264,6 @@ err2:
if (MIDIQ_BUF(m->outq))
free(MIDIQ_BUF(m->outq), M_MIDI);
err1:
- free(m->synth, M_MIDI);
free(m, M_MIDI);
err0:
midistat_unlock();
@@ -405,9 +275,7 @@ err0:
* midi_uninit does not call MIDI_UNINIT, as since this is the implementors
* entry point. midi_uninit if fact, does not send any methods. A call to
* midi_uninit is a defacto promise that you won't manipulate ch anymore
- *
*/
-
int
midi_uninit(struct snd_midi *m)
{
@@ -440,13 +308,6 @@ exit:
return err;
}
-/*
- * midi_in: process all data until the queue is full, then discards the rest.
- * Since midi_in is a state machine, data discards can cause it to get out of
- * whack. Process as much as possible. It calls, wakeup, selnotify and
- * psignal at most once.
- */
-
#ifdef notdef
static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
@@ -460,6 +321,12 @@ static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
#define MIDI_SYSEX_START 0xF0
#define MIDI_SYSEX_END 0xF7
+/*
+ * midi_in: process all data until the queue is full, then discards the rest.
+ * Since midi_in is a state machine, data discards can cause it to get out of
+ * whack. Process as much as possible. It calls, wakeup, selnotify and
+ * psignal at most once.
+ */
int
midi_in(struct snd_midi *m, uint8_t *buf, int size)
{
@@ -627,9 +494,6 @@ midi_out(struct snd_midi *m, uint8_t *buf, int size)
return used;
}
-/*
- * /dev/rmidi#.# device access functions
- */
int
midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
{
@@ -934,434 +798,6 @@ midi_poll(struct cdev *i_dev, int events, struct thread *td)
}
/*
- * /dev/midistat device functions
- *
- */
-static int
-midistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
-{
- int error;
-
- MIDI_DEBUG(1, printf("midistat_open\n"));
-
- midistat_lock();
- if (midistat_isopen) {
- midistat_unlock();
- return EBUSY;
- }
- midistat_isopen = 1;
- sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND);
- error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM;
- if (error)
- midistat_isopen = 0;
- midistat_unlock();
- return error;
-}
-
-static int
-midistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
-{
- MIDI_DEBUG(1, printf("midistat_close\n"));
- midistat_lock();
- if (!midistat_isopen) {
- midistat_unlock();
- return EBADF;
- }
- sbuf_delete(&midistat_sbuf);
- midistat_isopen = 0;
- midistat_unlock();
- return 0;
-}
-
-static int
-midistat_read(struct cdev *i_dev, struct uio *uio, int flag)
-{
- long l;
- int err;
-
- MIDI_DEBUG(4, printf("midistat_read\n"));
- midistat_lock();
- if (!midistat_isopen) {
- midistat_unlock();
- return EBADF;
- }
- if (uio->uio_offset < 0 || uio->uio_offset > sbuf_len(&midistat_sbuf)) {
- midistat_unlock();
- return EINVAL;
- }
- err = 0;
- l = lmin(uio->uio_resid, sbuf_len(&midistat_sbuf) - uio->uio_offset);
- if (l > 0) {
- err = uiomove(sbuf_data(&midistat_sbuf) + uio->uio_offset, l,
- uio);
- }
- midistat_unlock();
- return err;
-}
-
-/*
- * Module library functions
- */
-
-static int
-midistat_prepare(struct sbuf *s)
-{
- struct snd_midi *m;
-
- midistat_lockassert();
-
- sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n");
- if (TAILQ_EMPTY(&midi_devs)) {
- sbuf_printf(s, "No devices installed.\n");
- sbuf_finish(s);
- return sbuf_len(s);
- }
- sbuf_printf(s, "Installed devices:\n");
-
- TAILQ_FOREACH(m, &midi_devs, link) {
- mtx_lock(&m->lock);
- sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel,
- MPU_PROVIDER(m, m->cookie));
- sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose));
- sbuf_printf(s, "\n");
- mtx_unlock(&m->lock);
- }
-
- sbuf_finish(s);
- return sbuf_len(s);
-}
-
-#ifdef notdef
-/*
- * Convert IOCTL command to string for debugging
- */
-
-static char *
-midi_cmdname(int cmd)
-{
- static struct {
- int cmd;
- char *name;
- } *tab, cmdtab_midiioctl[] = {
-#define A(x) {x, ## x}
- /*
- * Once we have some real IOCTLs define, the following will
- * be relavant.
- *
- * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE),
- * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO),
- * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL),
- * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE),
- * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE),
- * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT),
- * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC),
- * A(AIOGCAP),
- */
-#undef A
- {
- -1, "unknown"
- },
- };
-
- for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++);
- return tab->name;
-}
-
-#endif /* notdef */
-
-/*
- * midisynth
- */
-
-int
-midisynth_open(void *n, void *arg, int flags)
-{
- struct snd_midi *m = ((struct synth_midi *)n)->m;
- int retval;
-
- MIDI_DEBUG(1, printf("midisynth_open %s %s\n",
- flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
-
- if (m == NULL)
- return ENXIO;
-
- mtx_lock(&m->lock);
- mtx_lock(&m->qlock);
-
- retval = 0;
-
- if (flags & FREAD) {
- if (MIDIQ_SIZE(m->inq) == 0)
- retval = ENXIO;
- else if (m->flags & M_RX)
- retval = EBUSY;
- if (retval)
- goto err;
- }
- if (flags & FWRITE) {
- if (MIDIQ_SIZE(m->outq) == 0)
- retval = ENXIO;
- else if (m->flags & M_TX)
- retval = EBUSY;
- if (retval)
- goto err;
- }
- m->busy++;
-
- /*
- * TODO: Consider m->async = 0;
- */
-
- if (flags & FREAD) {
- m->flags |= M_RX | M_RXEN;
- /*
- * Only clear the inq, the outq might still have data to drain
- * from a previous session
- */
- MIDIQ_CLEAR(m->inq);
- m->rchan = 0;
- }
-
- if (flags & FWRITE) {
- m->flags |= M_TX;
- m->wchan = 0;
- }
- m->synth_flags = flags & (FREAD | FWRITE);
-
- MPU_CALLBACK(m, m->cookie, m->flags);
-
-err: mtx_unlock(&m->qlock);
- mtx_unlock(&m->lock);
- MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval));
- return retval;
-}
-
-int
-midisynth_close(void *n)
-{
- struct snd_midi *m = ((struct synth_midi *)n)->m;
- int retval;
- int oldflags;
-
- MIDI_DEBUG(1, printf("midisynth_close %s %s\n",
- m->synth_flags & FREAD ? "M_RX" : "",
- m->synth_flags & FWRITE ? "M_TX" : ""));
-
- if (m == NULL)
- return ENXIO;
-
- mtx_lock(&m->lock);
- mtx_lock(&m->qlock);
-
- if ((m->synth_flags & FREAD && !(m->flags & M_RX)) ||
- (m->synth_flags & FWRITE && !(m->flags & M_TX))) {
- retval = ENXIO;
- goto err;
- }
- m->busy--;
-
- oldflags = m->flags;
-
- if (m->synth_flags & FREAD)
- m->flags &= ~(M_RX | M_RXEN);
- if (m->synth_flags & FWRITE)
- m->flags &= ~M_TX;
-
- if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
- MPU_CALLBACK(m, m->cookie, m->flags);
-
- MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
-
- mtx_unlock(&m->qlock);
- mtx_unlock(&m->lock);
- retval = 0;
-err: return retval;
-}
-
-/*
- * Always blocking.
- */
-
-int
-midisynth_writeraw(void *n, uint8_t *buf, size_t len)
-{
- struct snd_midi *m = ((struct synth_midi *)n)->m;
- int retval;
- int used;
- int i;
-
- MIDI_DEBUG(4, printf("midisynth_writeraw\n"));
-
- retval = 0;
-
- if (m == NULL)
- return ENXIO;
-
- mtx_lock(&m->lock);
- mtx_lock(&m->qlock);
-
- if (!(m->flags & M_TX))
- goto err1;
-
- if (midi_dumpraw)
- printf("midi dump: ");
-
- while (len > 0) {
- while (MIDIQ_AVAIL(m->outq) == 0) {
- if (!(m->flags & M_TXEN)) {
- m->flags |= M_TXEN;
- MPU_CALLBACK(m, m->cookie, m->flags);
- }
- mtx_unlock(&m->lock);
- m->wchan = 1;
- MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n"));
- retval = msleep(&m->wchan, &m->qlock,
- PCATCH | PDROP, "midi TX", 0);
- /*
- * We slept, maybe things have changed since last
- * dying check
- */
- if (retval == EINTR)
- goto err0;
-
- if (retval)
- goto err0;
- mtx_lock(&m->lock);
- mtx_lock(&m->qlock);
- m->wchan = 0;
- if (!m->busy)
- goto err1;
- }
-
- /*
- * We are certain than data can be placed on the queue
- */
-
- used = MIN(MIDIQ_AVAIL(m->outq), len);
- used = MIN(used, MIDI_WSIZE);
- MIDI_DEBUG(5,
- printf("midi_synth: resid %zu len %jd avail %jd\n",
- len, (intmax_t)MIDIQ_LEN(m->outq),
- (intmax_t)MIDIQ_AVAIL(m->outq)));
-
- if (midi_dumpraw)
- for (i = 0; i < used; i++)
- printf("%x ", buf[i]);
-
- MIDIQ_ENQ(m->outq, buf, used);
- len -= used;
-
- /*
- * Inform the bottom half that data can be written
- */
- if (!(m->flags & M_TXEN)) {
- m->flags |= M_TXEN;
- MPU_CALLBACK(m, m->cookie, m->flags);
- }
- }
- /*
- * If we Made it here then transfer is good
- */
- if (midi_dumpraw)
- printf("\n");
-
- retval = 0;
-err1: mtx_unlock(&m->qlock);
- mtx_unlock(&m->lock);
-err0: return retval;
-}
-
-static int
-midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
-{
- u_char c[3];
-
- if (note > 127 || chn > 15)
- return (EINVAL);
-
- if (vel > 127)
- vel = 127;
-
- if (vel == 64) {
- c[0] = 0x90 | (chn & 0x0f); /* Note on. */
- c[1] = (u_char)note;
- c[2] = 0;
- } else {
- c[0] = 0x80 | (chn & 0x0f); /* Note off. */
- c[1] = (u_char)note;
- c[2] = (u_char)vel;
- }
-
- return midisynth_writeraw(n, c, 3);
-}
-
-static int
-midisynth_setinstr(void *n, uint8_t chn, uint16_t instr)
-{
- u_char c[2];
-
- if (instr > 127 || chn > 15)
- return EINVAL;
-
- c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */
- c[1] = instr + midi_instroff;
-
- return midisynth_writeraw(n, c, 2);
-}
-
-static int
-midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
-{
- u_char c[3];
-
- if (note > 127 || chn > 15)
- return EINVAL;
-
- if (vel > 127)
- vel = 127;
-
- c[0] = 0x90 | (chn & 0x0f); /* Note on. */
- c[1] = (u_char)note;
- c[2] = (u_char)vel;
-
- return midisynth_writeraw(n, c, 3);
-}
-static int
-midisynth_alloc(void *n, uint8_t chan, uint8_t note)
-{
- return chan;
-}
-
-static int
-midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val)
-{
- u_char c[3];
-
- if (ctrlnum > 127 || chn > 15)
- return EINVAL;
-
- c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */
- c[1] = ctrlnum;
- c[2] = val;
- return midisynth_writeraw(n, c, 3);
-}
-
-static int
-midisynth_bender(void *n, uint8_t chn, uint16_t val)
-{
- u_char c[3];
-
- if (val > 16383 || chn > 15)
- return EINVAL;
-
- c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */
- c[1] = (u_char)val & 0x7f;
- c[2] = (u_char)(val >> 7) & 0x7f;
-
- return midisynth_writeraw(n, c, 3);
-}
-
-/*
* Single point of midi destructions.
*/
static int
@@ -1381,24 +817,16 @@ midi_destroy(struct snd_midi *m, int midiuninit)
free(MIDIQ_BUF(m->outq), M_MIDI);
mtx_destroy(&m->qlock);
mtx_destroy(&m->lock);
- free(m->synth, M_MIDI);
free(m, M_MIDI);
return 0;
}
-/*
- * Load and unload functions, creates the /dev/midistat device
- */
-
static int
midi_load(void)
{
sx_init(&mstat_lock, "midistat lock");
TAILQ_INIT(&midi_devs);
- midistat_dev = make_dev(&midistat_cdevsw, MIDI_DEV_MIDICTL, UID_ROOT,
- GID_WHEEL, 0666, "midistat");
-
return 0;
}
@@ -1411,9 +839,6 @@ midi_unload(void)
MIDI_DEBUG(1, printf("midi_unload()\n"));
retval = EBUSY;
midistat_lock();
- if (midistat_isopen)
- goto exit0;
-
TAILQ_FOREACH_SAFE(m, &midi_devs, link, tmp) {
mtx_lock(&m->lock);
if (m->busy)
@@ -1421,28 +846,21 @@ midi_unload(void)
else
retval = midi_destroy(m, 1);
if (retval)
- goto exit1;
+ goto exit;
}
midistat_unlock();
- destroy_dev(midistat_dev);
- /*
- * Made it here then unload is complete
- */
sx_destroy(&mstat_lock);
return 0;
-exit1:
+exit:
mtx_unlock(&m->lock);
-exit0:
midistat_unlock();
if (retval)
MIDI_DEBUG(2, printf("midi_unload: failed\n"));
return retval;
}
-extern int seq_modevent(module_t mod, int type, void *data);
-
static int
midi_modevent(module_t mod, int type, void *data)
{
@@ -1453,14 +871,10 @@ midi_modevent(module_t mod, int type, void *data)
switch (type) {
case MOD_LOAD:
retval = midi_load();
- if (retval == 0)
- retval = seq_modevent(mod, type, data);
break;
case MOD_UNLOAD:
retval = midi_unload();
- if (retval == 0)
- retval = seq_modevent(mod, type, data);
break;
default:
@@ -1470,73 +884,5 @@ midi_modevent(module_t mod, int type, void *data)
return retval;
}
-kobj_t
-midimapper_addseq(void *arg1, int *unit, void **cookie)
-{
- unit = NULL;
-
- return (kobj_t)arg1;
-}
-
-int
-midimapper_open_locked(void *arg1, void **cookie)
-{
- int retval = 0;
- struct snd_midi *m;
-
- midistat_lockassert();
- TAILQ_FOREACH(m, &midi_devs, link) {
- retval++;
- }
-
- return retval;
-}
-
-int
-midimapper_open(void *arg1, void **cookie)
-{
- int retval;
-
- midistat_lock();
- retval = midimapper_open_locked(arg1, cookie);
- midistat_unlock();
-
- return retval;
-}
-
-int
-midimapper_close(void *arg1, void *cookie)
-{
- return 0;
-}
-
-kobj_t
-midimapper_fetch_synth_locked(void *arg, void *cookie, int unit)
-{
- struct snd_midi *m;
- int retval = 0;
-
- midistat_lockassert();
- TAILQ_FOREACH(m, &midi_devs, link) {
- if (unit == retval)
- return (kobj_t)m->synth;
- retval++;
- }
-
- return NULL;
-}
-
-kobj_t
-midimapper_fetch_synth(void *arg, void *cookie, int unit)
-{
- kobj_t synth;
-
- midistat_lock();
- synth = midimapper_fetch_synth_locked(arg, cookie, unit);
- midistat_unlock();
-
- return synth;
-}
-
DEV_MODULE(midi, midi_modevent, NULL);
MODULE_VERSION(midi, 1);
diff --git a/sys/dev/sound/midi/midi.h b/sys/dev/sound/midi/midi.h
index 2254fab690e9..286e84264ef3 100644
--- a/sys/dev/sound/midi/midi.h
+++ b/sys/dev/sound/midi/midi.h
@@ -51,11 +51,4 @@ int midi_uninit(struct snd_midi *_m);
int midi_out(struct snd_midi *_m, uint8_t *_buf, int _size);
int midi_in(struct snd_midi *_m, uint8_t *_buf, int _size);
-kobj_t midimapper_addseq(void *arg1, int *unit, void **cookie);
-int midimapper_open_locked(void *arg1, void **cookie);
-int midimapper_open(void *arg1, void **cookie);
-int midimapper_close(void *arg1, void *cookie);
-kobj_t midimapper_fetch_synth_locked(void *arg, void *cookie, int unit);
-kobj_t midimapper_fetch_synth(void *arg, void *cookie, int unit);
-
#endif
diff --git a/sys/dev/sound/midi/mpu401.c b/sys/dev/sound/midi/mpu401.c
index 2be285bc0040..224ebb1b01f4 100644
--- a/sys/dev/sound/midi/mpu401.c
+++ b/sys/dev/sound/midi/mpu401.c
@@ -88,8 +88,6 @@ static int mpu401_minqsize(struct snd_midi *, void *);
static int mpu401_moutqsize(struct snd_midi *, void *);
static void mpu401_mcallback(struct snd_midi *, void *, int);
static void mpu401_mcallbackp(struct snd_midi *, void *, int);
-static const char *mpu401_mdescr(struct snd_midi *, void *, int);
-static const char *mpu401_mprovider(struct snd_midi *, void *);
static kobj_method_t mpu401_methods[] = {
KOBJMETHOD(mpu_init, mpu401_minit),
@@ -98,8 +96,6 @@ static kobj_method_t mpu401_methods[] = {
KOBJMETHOD(mpu_outqsize, mpu401_moutqsize),
KOBJMETHOD(mpu_callback, mpu401_mcallback),
KOBJMETHOD(mpu_callbackp, mpu401_mcallbackp),
- KOBJMETHOD(mpu_descr, mpu401_mdescr),
- KOBJMETHOD(mpu_provider, mpu401_mprovider),
KOBJMETHOD_END
};
@@ -122,24 +118,12 @@ mpu401_intr(struct mpu401 *m)
int i;
int s;
-/*
- printf("mpu401_intr\n");
-*/
#define RXRDY(m) ( (STATUS(m) & MPU_INPUTBUSY) == 0)
#define TXRDY(m) ( (STATUS(m) & MPU_OUTPUTBUSY) == 0)
-#if 0
-#define D(x,l) printf("mpu401_intr %d %x %s %s\n",l, x, x&MPU_INPUTBUSY?"RX":"", x&MPU_OUTPUTBUSY?"TX":"")
-#else
-#define D(x,l)
-#endif
i = 0;
s = STATUS(m);
- D(s, 1);
while ((s & MPU_INPUTBUSY) == 0 && i < MPU_INTR_BUF) {
b[i] = READ(m);
-/*
- printf("mpu401_intr in i %d d %d\n", i, b[i]);
-*/
i++;
s = STATUS(m);
}
@@ -148,15 +132,9 @@ mpu401_intr(struct mpu401 *m)
i = 0;
while (!(s & MPU_OUTPUTBUSY) && i < MPU_INTR_BUF) {
if (midi_out(m->mid, b, 1)) {
-/*
- printf("mpu401_intr out i %d d %d\n", i, b[0]);
-*/
WRITE(m, *b);
} else {
-/*
- printf("mpu401_intr write: no output\n");
-*/
return 0;
}
i++;
@@ -262,13 +240,7 @@ static void
mpu401_mcallback(struct snd_midi *sm, void *arg, int flags)
{
struct mpu401 *m = arg;
-#if 0
- printf("mpu401_callback %s %s %s %s\n",
- flags & M_RX ? "M_RX" : "",
- flags & M_TX ? "M_TX" : "",
- flags & M_RXEN ? "M_RXEN" : "",
- flags & M_TXEN ? "M_TXEN" : "");
-#endif
+
if (flags & M_TXEN && m->si) {
callout_reset(&m->timer, 1, mpu401_timeout, m);
}
@@ -278,19 +250,5 @@ mpu401_mcallback(struct snd_midi *sm, void *arg, int flags)
static void
mpu401_mcallbackp(struct snd_midi *sm, void *arg, int flags)
{
-/* printf("mpu401_callbackp\n"); */
mpu401_mcallback(sm, arg, flags);
}
-
-static const char *
-mpu401_mdescr(struct snd_midi *sm, void *arg, int verbosity)
-{
-
- return "descr mpu401";
-}
-
-static const char *
-mpu401_mprovider(struct snd_midi *m, void *arg)
-{
- return "provider mpu401";
-}
diff --git a/sys/dev/sound/midi/mpu_if.m b/sys/dev/sound/midi/mpu_if.m
index b7cb586c5dd0..835d887f703a 100644
--- a/sys/dev/sound/midi/mpu_if.m
+++ b/sys/dev/sound/midi/mpu_if.m
@@ -56,17 +56,6 @@ METHOD void callback {
int _flags;
};
-METHOD const char * provider {
- struct snd_midi *_kobj;
- void *_cookie;
-};
-
-METHOD const char * descr {
- struct snd_midi *_kobj;
- void *_cookie;
- int _verbosity;
-};
-
METHOD int uninit {
struct snd_midi *_kobj;
void *_cookie;
diff --git a/sys/dev/sound/midi/sequencer.c b/sys/dev/sound/midi/sequencer.c
deleted file mode 100644
index 03b71688175c..000000000000
--- a/sys/dev/sound/midi/sequencer.c
+++ /dev/null
@@ -1,2107 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2003 Mathew Kanner
- * Copyright (c) 1993 Hannu Savolainen
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * The sequencer personality manager.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/ioccom.h>
-
-#include <sys/filio.h>
-#include <sys/lock.h>
-#include <sys/sockio.h>
-#include <sys/fcntl.h>
-#include <sys/proc.h>
-#include <sys/sysctl.h>
-
-#include <sys/kernel.h> /* for DATA_SET */
-
-#include <sys/module.h>
-#include <sys/conf.h>
-#include <sys/file.h>
-#include <sys/uio.h>
-#include <sys/syslog.h>
-#include <sys/errno.h>
-#include <sys/malloc.h>
-#include <sys/bus.h>
-#include <machine/resource.h>
-#include <machine/bus.h>
-#include <machine/clock.h> /* for DELAY */
-#include <sys/soundcard.h>
-#include <sys/rman.h>
-#include <sys/mman.h>
-#include <sys/poll.h>
-#include <sys/mutex.h>
-#include <sys/condvar.h>
-#include <sys/kthread.h>
-#include <sys/unistd.h>
-#include <sys/selinfo.h>
-#include <sys/sx.h>
-
-#ifdef HAVE_KERNEL_OPTION_HEADERS
-#include "opt_snd.h"
-#endif
-
-#include <dev/sound/midi/midi.h>
-#include <dev/sound/midi/midiq.h>
-#include "synth_if.h"
-
-#include <dev/sound/midi/sequencer.h>
-
-#define TMR_TIMERBASE 13
-
-#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
- * synthesizer and MIDI output) */
-#define SND_DEV_MUSIC 8 /* /dev/music, level 2 interface */
-
-/* Length of a sequencer event. */
-#define EV_SZ 8
-#define IEV_SZ 8
-
-/* Lookup modes */
-#define LOOKUP_EXIST (0)
-#define LOOKUP_OPEN (1)
-#define LOOKUP_CLOSE (2)
-
-#define MIDIDEV(y) (dev2unit(y) & 0x0f)
-
-/* These are the entries to the sequencer driver. */
-static d_open_t mseq_open;
-static d_close_t mseq_close;
-static d_ioctl_t mseq_ioctl;
-static d_read_t mseq_read;
-static d_write_t mseq_write;
-static d_poll_t mseq_poll;
-
-static struct cdevsw seq_cdevsw = {
- .d_version = D_VERSION,
- .d_open = mseq_open,
- .d_close = mseq_close,
- .d_read = mseq_read,
- .d_write = mseq_write,
- .d_ioctl = mseq_ioctl,
- .d_poll = mseq_poll,
- .d_name = "sequencer",
-};
-
-struct seq_softc {
- KOBJ_FIELDS;
-
- struct mtx seq_lock, q_lock;
- struct cv empty_cv, reset_cv, in_cv, out_cv, state_cv, th_cv;
-
- MIDIQ_HEAD(, u_char) in_q, out_q;
-
- u_long flags;
- /* Flags (protected by flag_mtx of mididev_info) */
- int fflags; /* Access mode */
- int music;
-
- int out_water; /* Sequence output threshould */
- snd_sync_parm sync_parm; /* AIOSYNC parameter set */
- struct thread *sync_thread; /* AIOSYNCing thread */
- struct selinfo in_sel, out_sel;
- int midi_number;
- struct cdev *seqdev, *musicdev;
- int unit;
- int maxunits;
- kobj_t *midis;
- int *midi_flags;
- kobj_t mapper;
- void *mapper_cookie;
- struct timeval timerstop, timersub;
- int timerbase, tempo;
- int timerrun;
- int done;
- int playing;
- int recording;
- int busy;
- int pre_event_timeout;
- int waiting;
-};
-
-/*
- * Module specific stuff, including how many sequecers
- * we currently own.
- */
-
-SYSCTL_NODE(_hw_midi, OID_AUTO, seq, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
- "Midi sequencer");
-
-int seq_debug;
-/* XXX: should this be moved into debug.midi? */
-SYSCTL_INT(_hw_midi_seq, OID_AUTO, debug, CTLFLAG_RW, &seq_debug, 0, "");
-
-midi_cmdtab cmdtab_seqevent[] = {
- {SEQ_NOTEOFF, "SEQ_NOTEOFF"},
- {SEQ_NOTEON, "SEQ_NOTEON"},
- {SEQ_WAIT, "SEQ_WAIT"},
- {SEQ_PGMCHANGE, "SEQ_PGMCHANGE"},
- {SEQ_SYNCTIMER, "SEQ_SYNCTIMER"},
- {SEQ_MIDIPUTC, "SEQ_MIDIPUTC"},
- {SEQ_DRUMON, "SEQ_DRUMON"},
- {SEQ_DRUMOFF, "SEQ_DRUMOFF"},
- {SEQ_ECHO, "SEQ_ECHO"},
- {SEQ_AFTERTOUCH, "SEQ_AFTERTOUCH"},
- {SEQ_CONTROLLER, "SEQ_CONTROLLER"},
- {SEQ_BALANCE, "SEQ_BALANCE"},
- {SEQ_VOLMODE, "SEQ_VOLMODE"},
- {SEQ_FULLSIZE, "SEQ_FULLSIZE"},
- {SEQ_PRIVATE, "SEQ_PRIVATE"},
- {SEQ_EXTENDED, "SEQ_EXTENDED"},
- {EV_SEQ_LOCAL, "EV_SEQ_LOCAL"},
- {EV_TIMING, "EV_TIMING"},
- {EV_CHN_COMMON, "EV_CHN_COMMON"},
- {EV_CHN_VOICE, "EV_CHN_VOICE"},
- {EV_SYSEX, "EV_SYSEX"},
- {-1, NULL},
-};
-
-midi_cmdtab cmdtab_seqioctl[] = {
- {SNDCTL_SEQ_RESET, "SNDCTL_SEQ_RESET"},
- {SNDCTL_SEQ_SYNC, "SNDCTL_SEQ_SYNC"},
- {SNDCTL_SYNTH_INFO, "SNDCTL_SYNTH_INFO"},
- {SNDCTL_SEQ_CTRLRATE, "SNDCTL_SEQ_CTRLRATE"},
- {SNDCTL_SEQ_GETOUTCOUNT, "SNDCTL_SEQ_GETOUTCOUNT"},
- {SNDCTL_SEQ_GETINCOUNT, "SNDCTL_SEQ_GETINCOUNT"},
- {SNDCTL_SEQ_PERCMODE, "SNDCTL_SEQ_PERCMODE"},
- {SNDCTL_FM_LOAD_INSTR, "SNDCTL_FM_LOAD_INSTR"},
- {SNDCTL_SEQ_TESTMIDI, "SNDCTL_SEQ_TESTMIDI"},
- {SNDCTL_SEQ_RESETSAMPLES, "SNDCTL_SEQ_RESETSAMPLES"},
- {SNDCTL_SEQ_NRSYNTHS, "SNDCTL_SEQ_NRSYNTHS"},
- {SNDCTL_SEQ_NRMIDIS, "SNDCTL_SEQ_NRMIDIS"},
- {SNDCTL_SEQ_GETTIME, "SNDCTL_SEQ_GETTIME"},
- {SNDCTL_MIDI_INFO, "SNDCTL_MIDI_INFO"},
- {SNDCTL_SEQ_THRESHOLD, "SNDCTL_SEQ_THRESHOLD"},
- {SNDCTL_SYNTH_MEMAVL, "SNDCTL_SYNTH_MEMAVL"},
- {SNDCTL_FM_4OP_ENABLE, "SNDCTL_FM_4OP_ENABLE"},
- {SNDCTL_PMGR_ACCESS, "SNDCTL_PMGR_ACCESS"},
- {SNDCTL_SEQ_PANIC, "SNDCTL_SEQ_PANIC"},
- {SNDCTL_SEQ_OUTOFBAND, "SNDCTL_SEQ_OUTOFBAND"},
- {SNDCTL_TMR_TIMEBASE, "SNDCTL_TMR_TIMEBASE"},
- {SNDCTL_TMR_START, "SNDCTL_TMR_START"},
- {SNDCTL_TMR_STOP, "SNDCTL_TMR_STOP"},
- {SNDCTL_TMR_CONTINUE, "SNDCTL_TMR_CONTINUE"},
- {SNDCTL_TMR_TEMPO, "SNDCTL_TMR_TEMPO"},
- {SNDCTL_TMR_SOURCE, "SNDCTL_TMR_SOURCE"},
- {SNDCTL_TMR_METRONOME, "SNDCTL_TMR_METRONOME"},
- {SNDCTL_TMR_SELECT, "SNDCTL_TMR_SELECT"},
- {SNDCTL_MIDI_PRETIME, "SNDCTL_MIDI_PRETIME"},
- {AIONWRITE, "AIONWRITE"},
- {AIOGSIZE, "AIOGSIZE"},
- {AIOSSIZE, "AIOSSIZE"},
- {AIOGFMT, "AIOGFMT"},
- {AIOSFMT, "AIOSFMT"},
- {AIOGMIX, "AIOGMIX"},
- {AIOSMIX, "AIOSMIX"},
- {AIOSTOP, "AIOSTOP"},
- {AIOSYNC, "AIOSYNC"},
- {AIOGCAP, "AIOGCAP"},
- {-1, NULL},
-};
-
-midi_cmdtab cmdtab_timer[] = {
- {TMR_WAIT_REL, "TMR_WAIT_REL"},
- {TMR_WAIT_ABS, "TMR_WAIT_ABS"},
- {TMR_STOP, "TMR_STOP"},
- {TMR_START, "TMR_START"},
- {TMR_CONTINUE, "TMR_CONTINUE"},
- {TMR_TEMPO, "TMR_TEMPO"},
- {TMR_ECHO, "TMR_ECHO"},
- {TMR_CLOCK, "TMR_CLOCK"},
- {TMR_SPP, "TMR_SPP"},
- {TMR_TIMESIG, "TMR_TIMESIG"},
- {-1, NULL},
-};
-
-midi_cmdtab cmdtab_seqcv[] = {
- {MIDI_NOTEOFF, "MIDI_NOTEOFF"},
- {MIDI_NOTEON, "MIDI_NOTEON"},
- {MIDI_KEY_PRESSURE, "MIDI_KEY_PRESSURE"},
- {-1, NULL},
-};
-
-midi_cmdtab cmdtab_seqccmn[] = {
- {MIDI_CTL_CHANGE, "MIDI_CTL_CHANGE"},
- {MIDI_PGM_CHANGE, "MIDI_PGM_CHANGE"},
- {MIDI_CHN_PRESSURE, "MIDI_CHN_PRESSURE"},
- {MIDI_PITCH_BEND, "MIDI_PITCH_BEND"},
- {MIDI_SYSTEM_PREFIX, "MIDI_SYSTEM_PREFIX"},
- {-1, NULL},
-};
-
-#ifndef KOBJMETHOD_END
-#define KOBJMETHOD_END { NULL, NULL }
-#endif
-
-/*
- * static const char *mpu401_mprovider(kobj_t obj, struct mpu401 *m);
- */
-
-static kobj_method_t seq_methods[] = {
- /* KOBJMETHOD(mpu_provider,mpu401_mprovider), */
- KOBJMETHOD_END
-};
-
-DEFINE_CLASS(sequencer, seq_methods, 0);
-
-/* The followings are the local function. */
-static int seq_convertold(u_char *event, u_char *out);
-
-/*
- * static void seq_midiinput(struct seq_softc * scp, void *md);
- */
-static void seq_reset(struct seq_softc *scp);
-static int seq_sync(struct seq_softc *scp);
-
-static int seq_processevent(struct seq_softc *scp, u_char *event);
-
-static int seq_timing(struct seq_softc *scp, u_char *event);
-static int seq_local(struct seq_softc *scp, u_char *event);
-
-static int seq_chnvoice(struct seq_softc *scp, kobj_t md, u_char *event);
-static int seq_chncommon(struct seq_softc *scp, kobj_t md, u_char *event);
-static int seq_sysex(struct seq_softc *scp, kobj_t md, u_char *event);
-
-static int seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md);
-void seq_copytoinput(struct seq_softc *scp, u_char *event, int len);
-int seq_modevent(module_t mod, int type, void *data);
-struct seq_softc *seqs[10];
-static struct mtx seqinfo_mtx;
-static u_long nseq = 0;
-
-static void timer_start(struct seq_softc *t);
-static void timer_stop(struct seq_softc *t);
-static void timer_setvals(struct seq_softc *t, int tempo, int timerbase);
-static void timer_wait(struct seq_softc *t, int ticks, int wait_abs);
-static int timer_now(struct seq_softc *t);
-
-static void
-timer_start(struct seq_softc *t)
-{
- t->timerrun = 1;
- getmicrotime(&t->timersub);
-}
-
-static void
-timer_continue(struct seq_softc *t)
-{
- struct timeval now;
-
- if (t->timerrun == 1)
- return;
- t->timerrun = 1;
- getmicrotime(&now);
- timevalsub(&now, &t->timerstop);
- timevaladd(&t->timersub, &now);
-}
-
-static void
-timer_stop(struct seq_softc *t)
-{
- t->timerrun = 0;
- getmicrotime(&t->timerstop);
-}
-
-static void
-timer_setvals(struct seq_softc *t, int tempo, int timerbase)
-{
- t->tempo = tempo;
- t->timerbase = timerbase;
-}
-
-static void
-timer_wait(struct seq_softc *t, int ticks, int wait_abs)
-{
- struct timeval now, when;
- int ret;
- unsigned long long i;
-
- while (t->timerrun == 0) {
- SEQ_DEBUG(2, printf("Timer wait when timer isn't running\n"));
- /*
- * The old sequencer used timeouts that only increased
- * the timer when the timer was running.
- * Hence the sequencer would stick (?) if the
- * timer was disabled.
- */
- cv_wait(&t->reset_cv, &t->seq_lock);
- if (t->playing == 0)
- return;
- }
-
- i = ticks * 60ull * 1000000ull / (t->tempo * t->timerbase);
-
- when.tv_sec = i / 1000000;
- when.tv_usec = i % 1000000;
-
-#if 0
- printf("timer_wait tempo %d timerbase %d ticks %d abs %d u_sec %llu\n",
- t->tempo, t->timerbase, ticks, wait_abs, i);
-#endif
-
- if (wait_abs != 0) {
- getmicrotime(&now);
- timevalsub(&now, &t->timersub);
- timevalsub(&when, &now);
- }
- if (when.tv_sec < 0 || when.tv_usec < 0) {
- SEQ_DEBUG(3,
- printf("seq_timer error negative time %lds.%06lds\n",
- (long)when.tv_sec, (long)when.tv_usec));
- return;
- }
- i = when.tv_sec * 1000000ull;
- i += when.tv_usec;
- i *= hz;
- i /= 1000000ull;
-#if 0
- printf("seq_timer usec %llu ticks %llu\n",
- when.tv_sec * 1000000ull + when.tv_usec, i);
-#endif
- t->waiting = 1;
- ret = cv_timedwait(&t->reset_cv, &t->seq_lock, i + 1);
- t->waiting = 0;
-
- if (ret != EWOULDBLOCK)
- SEQ_DEBUG(3, printf("seq_timer didn't timeout\n"));
-
-}
-
-static int
-timer_now(struct seq_softc *t)
-{
- struct timeval now;
- unsigned long long i;
- int ret;
-
- if (t->timerrun == 0)
- now = t->timerstop;
- else
- getmicrotime(&now);
-
- timevalsub(&now, &t->timersub);
-
- i = now.tv_sec * 1000000ull;
- i += now.tv_usec;
- i *= t->timerbase;
-/* i /= t->tempo; */
- i /= 1000000ull;
-
- ret = i;
- /*
- * printf("timer_now: %llu %d\n", i, ret);
- */
-
- return ret;
-}
-
-static void
-seq_eventthread(void *arg)
-{
- struct seq_softc *scp = arg;
- u_char event[EV_SZ];
-
- mtx_lock(&scp->seq_lock);
- SEQ_DEBUG(2, printf("seq_eventthread started\n"));
- while (scp->done == 0) {
-restart:
- while (scp->playing == 0) {
- cv_wait(&scp->state_cv, &scp->seq_lock);
- if (scp->done)
- goto done;
- }
-
- while (MIDIQ_EMPTY(scp->out_q)) {
- cv_broadcast(&scp->empty_cv);
- cv_wait(&scp->out_cv, &scp->seq_lock);
- if (scp->playing == 0)
- goto restart;
- if (scp->done)
- goto done;
- }
-
- MIDIQ_DEQ(scp->out_q, event, EV_SZ);
-
- if (MIDIQ_AVAIL(scp->out_q) < scp->out_water) {
- cv_broadcast(&scp->out_cv);
- selwakeup(&scp->out_sel);
- }
- seq_processevent(scp, event);
- }
-
-done:
- cv_broadcast(&scp->th_cv);
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(2, printf("seq_eventthread finished\n"));
- kproc_exit(0);
-}
-
-/*
- * seq_processevent: This maybe called by the event thread or the IOCTL
- * handler for queued and out of band events respectively.
- */
-static int
-seq_processevent(struct seq_softc *scp, u_char *event)
-{
- int ret;
- kobj_t m;
-
- ret = 0;
-
- if (event[0] == EV_SEQ_LOCAL)
- ret = seq_local(scp, event);
- else if (event[0] == EV_TIMING)
- ret = seq_timing(scp, event);
- else if (event[0] != EV_CHN_VOICE &&
- event[0] != EV_CHN_COMMON &&
- event[0] != EV_SYSEX &&
- event[0] != SEQ_MIDIPUTC) {
- ret = 1;
- SEQ_DEBUG(2, printf("seq_processevent not known %d\n",
- event[0]));
- } else if (seq_fetch_mid(scp, event[1], &m) != 0) {
- ret = 1;
- SEQ_DEBUG(2, printf("seq_processevent midi unit not found %d\n",
- event[1]));
- } else
- switch (event[0]) {
- case EV_CHN_VOICE:
- ret = seq_chnvoice(scp, m, event);
- break;
- case EV_CHN_COMMON:
- ret = seq_chncommon(scp, m, event);
- break;
- case EV_SYSEX:
- ret = seq_sysex(scp, m, event);
- break;
- case SEQ_MIDIPUTC:
- mtx_unlock(&scp->seq_lock);
- ret = SYNTH_WRITERAW(m, &event[2], 1);
- mtx_lock(&scp->seq_lock);
- break;
- }
- return ret;
-}
-
-static int
-seq_addunit(void)
-{
- struct seq_softc *scp;
- int ret;
- u_char *buf;
-
- gone_in(15, "Warning! MIDI sequencer to be removed soon: no longer "
- "needed or used\n");
-
- /* Allocate the softc. */
- ret = ENOMEM;
- scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT | M_ZERO);
- if (scp == NULL) {
- SEQ_DEBUG(1, printf("seq_addunit: softc allocation failed.\n"));
- goto err;
- }
- kobj_init((kobj_t)scp, &sequencer_class);
-
- buf = malloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_NOWAIT | M_ZERO);
- if (buf == NULL)
- goto err;
- MIDIQ_INIT(scp->in_q, buf, EV_SZ * 1024);
- buf = malloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_NOWAIT | M_ZERO);
- if (buf == NULL)
- goto err;
- MIDIQ_INIT(scp->out_q, buf, EV_SZ * 1024);
- ret = EINVAL;
-
- scp->midis = malloc(sizeof(kobj_t) * 32, M_TEMP, M_NOWAIT | M_ZERO);
- scp->midi_flags = malloc(sizeof(*scp->midi_flags) * 32, M_TEMP,
- M_NOWAIT | M_ZERO);
-
- if (scp->midis == NULL || scp->midi_flags == NULL)
- goto err;
-
- scp->flags = 0;
-
- mtx_init(&scp->seq_lock, "seqflq", NULL, 0);
- cv_init(&scp->state_cv, "seqstate");
- cv_init(&scp->empty_cv, "seqempty");
- cv_init(&scp->reset_cv, "seqtimer");
- cv_init(&scp->out_cv, "seqqout");
- cv_init(&scp->in_cv, "seqqin");
- cv_init(&scp->th_cv, "seqstart");
-
- /*
- * Init the damn timer
- */
-
- scp->mapper = midimapper_addseq(scp, &scp->unit, &scp->mapper_cookie);
- if (scp->mapper == NULL)
- goto err;
-
- scp->seqdev = make_dev(&seq_cdevsw, SND_DEV_SEQ, UID_ROOT, GID_WHEEL,
- 0666, "sequencer%d", scp->unit);
-
- scp->musicdev = make_dev(&seq_cdevsw, SND_DEV_MUSIC, UID_ROOT,
- GID_WHEEL, 0666, "music%d", scp->unit);
-
- if (scp->seqdev == NULL || scp->musicdev == NULL)
- goto err;
- /*
- * TODO: Add to list of sequencers this module provides
- */
-
- ret =
- kproc_create
- (seq_eventthread, scp, NULL, RFHIGHPID, 0,
- "sequencer %02d", scp->unit);
-
- if (ret)
- goto err;
-
- scp->seqdev->si_drv1 = scp->musicdev->si_drv1 = scp;
-
- SEQ_DEBUG(2, printf("sequencer %d created scp %p\n", scp->unit, scp));
-
- ret = 0;
-
- mtx_lock(&seqinfo_mtx);
- seqs[nseq++] = scp;
- mtx_unlock(&seqinfo_mtx);
-
- goto ok;
-
-err:
- if (scp != NULL) {
- if (scp->seqdev != NULL)
- destroy_dev(scp->seqdev);
- if (scp->musicdev != NULL)
- destroy_dev(scp->musicdev);
- /*
- * TODO: Destroy mutex and cv
- */
- if (scp->midis != NULL)
- free(scp->midis, M_TEMP);
- if (scp->midi_flags != NULL)
- free(scp->midi_flags, M_TEMP);
- if (scp->out_q.b)
- free(scp->out_q.b, M_TEMP);
- if (scp->in_q.b)
- free(scp->in_q.b, M_TEMP);
- free(scp, M_DEVBUF);
- }
-ok:
- return ret;
-}
-
-static int
-seq_delunit(int unit)
-{
- struct seq_softc *scp = seqs[unit];
- int i;
-
- //SEQ_DEBUG(4, printf("seq_delunit: %d\n", unit));
- SEQ_DEBUG(1, printf("seq_delunit: 1 \n"));
- mtx_lock(&scp->seq_lock);
-
- scp->playing = 0;
- scp->done = 1;
- cv_broadcast(&scp->out_cv);
- cv_broadcast(&scp->state_cv);
- cv_broadcast(&scp->reset_cv);
- SEQ_DEBUG(1, printf("seq_delunit: 2 \n"));
- cv_wait(&scp->th_cv, &scp->seq_lock);
- SEQ_DEBUG(1, printf("seq_delunit: 3.0 \n"));
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(1, printf("seq_delunit: 3.1 \n"));
-
- cv_destroy(&scp->state_cv);
- SEQ_DEBUG(1, printf("seq_delunit: 4 \n"));
- cv_destroy(&scp->empty_cv);
- SEQ_DEBUG(1, printf("seq_delunit: 5 \n"));
- cv_destroy(&scp->reset_cv);
- SEQ_DEBUG(1, printf("seq_delunit: 6 \n"));
- cv_destroy(&scp->out_cv);
- SEQ_DEBUG(1, printf("seq_delunit: 7 \n"));
- cv_destroy(&scp->in_cv);
- SEQ_DEBUG(1, printf("seq_delunit: 8 \n"));
- cv_destroy(&scp->th_cv);
-
- SEQ_DEBUG(1, printf("seq_delunit: 10 \n"));
- if (scp->seqdev)
- destroy_dev(scp->seqdev);
- SEQ_DEBUG(1, printf("seq_delunit: 11 \n"));
- if (scp->musicdev)
- destroy_dev(scp->musicdev);
- SEQ_DEBUG(1, printf("seq_delunit: 12 \n"));
- scp->seqdev = scp->musicdev = NULL;
- if (scp->midis != NULL)
- free(scp->midis, M_TEMP);
- SEQ_DEBUG(1, printf("seq_delunit: 13 \n"));
- if (scp->midi_flags != NULL)
- free(scp->midi_flags, M_TEMP);
- SEQ_DEBUG(1, printf("seq_delunit: 14 \n"));
- free(scp->out_q.b, M_TEMP);
- SEQ_DEBUG(1, printf("seq_delunit: 15 \n"));
- free(scp->in_q.b, M_TEMP);
-
- SEQ_DEBUG(1, printf("seq_delunit: 16 \n"));
-
- mtx_destroy(&scp->seq_lock);
- SEQ_DEBUG(1, printf("seq_delunit: 17 \n"));
- free(scp, M_DEVBUF);
-
- mtx_lock(&seqinfo_mtx);
- for (i = unit; i < (nseq - 1); i++)
- seqs[i] = seqs[i + 1];
- nseq--;
- mtx_unlock(&seqinfo_mtx);
-
- return 0;
-}
-
-int
-seq_modevent(module_t mod, int type, void *data)
-{
- int retval, r;
-
- retval = 0;
-
- switch (type) {
- case MOD_LOAD:
- mtx_init(&seqinfo_mtx, "seqmod", NULL, 0);
- retval = seq_addunit();
- break;
-
- case MOD_UNLOAD:
- while (nseq) {
- r = seq_delunit(nseq - 1);
- if (r) {
- retval = r;
- break;
- }
- }
- if (nseq == 0) {
- retval = 0;
- mtx_destroy(&seqinfo_mtx);
- }
- break;
-
- default:
- break;
- }
-
- return retval;
-}
-
-static int
-seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md)
-{
-
- if (unit >= scp->midi_number || unit < 0)
- return EINVAL;
-
- *md = scp->midis[unit];
-
- return 0;
-}
-
-int
-mseq_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
-{
- struct seq_softc *scp = i_dev->si_drv1;
- int i;
-
- gone_in(15, "Warning! MIDI sequencer to be removed soon: no longer "
- "needed or used\n");
-
- if (scp == NULL)
- return ENXIO;
-
- SEQ_DEBUG(3, printf("seq_open: scp %p unit %d, flags 0x%x.\n",
- scp, scp->unit, flags));
-
- /*
- * Mark this device busy.
- */
-
- midistat_lock();
- mtx_lock(&scp->seq_lock);
- if (scp->busy) {
- mtx_unlock(&scp->seq_lock);
- midistat_unlock();
- SEQ_DEBUG(2, printf("seq_open: unit %d is busy.\n", scp->unit));
- return EBUSY;
- }
- scp->fflags = flags;
- /*
- if ((scp->fflags & O_NONBLOCK) != 0)
- scp->flags |= SEQ_F_NBIO;
- */
- scp->music = MIDIDEV(i_dev) == SND_DEV_MUSIC;
-
- /*
- * Enumerate the available midi devices
- */
- scp->midi_number = 0;
- scp->maxunits = midimapper_open_locked(scp->mapper, &scp->mapper_cookie);
-
- if (scp->maxunits == 0)
- SEQ_DEBUG(2, printf("seq_open: no midi devices\n"));
-
- for (i = 0; i < scp->maxunits; i++) {
- scp->midis[scp->midi_number] =
- midimapper_fetch_synth_locked(scp->mapper,
- scp->mapper_cookie, i);
- if (scp->midis[scp->midi_number]) {
- if (SYNTH_OPEN(scp->midis[scp->midi_number], scp,
- scp->fflags) != 0)
- scp->midis[scp->midi_number] = NULL;
- else {
- scp->midi_flags[scp->midi_number] =
- SYNTH_QUERY(scp->midis[scp->midi_number]);
- scp->midi_number++;
- }
- }
- }
- midistat_unlock();
-
- timer_setvals(scp, 60, 100);
-
- timer_start(scp);
- timer_stop(scp);
- /*
- * actually, if we're in rdonly mode, we should start the timer
- */
- /*
- * TODO: Handle recording now
- */
-
- scp->out_water = MIDIQ_SIZE(scp->out_q) / 2;
-
- scp->busy = 1;
- mtx_unlock(&scp->seq_lock);
-
- SEQ_DEBUG(2, printf("seq_open: opened, mode %s.\n",
- scp->music ? "music" : "sequencer"));
- SEQ_DEBUG(2,
- printf("Sequencer %d %p opened maxunits %d midi_number %d:\n",
- scp->unit, scp, scp->maxunits, scp->midi_number));
- for (i = 0; i < scp->midi_number; i++)
- SEQ_DEBUG(3, printf(" midi %d %p\n", i, scp->midis[i]));
-
- return 0;
-}
-
-/*
- * mseq_close
- */
-int
-mseq_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
-{
- int i;
- struct seq_softc *scp = i_dev->si_drv1;
- int ret;
-
- if (scp == NULL)
- return ENXIO;
-
- SEQ_DEBUG(2, printf("seq_close: unit %d.\n", scp->unit));
-
- mtx_lock(&scp->seq_lock);
-
- ret = ENXIO;
- if (scp->busy == 0)
- goto err;
-
- seq_reset(scp);
- seq_sync(scp);
-
- for (i = 0; i < scp->midi_number; i++)
- if (scp->midis[i])
- SYNTH_CLOSE(scp->midis[i]);
-
- midimapper_close(scp->mapper, scp->mapper_cookie);
-
- timer_stop(scp);
-
- scp->busy = 0;
- ret = 0;
-
-err:
- SEQ_DEBUG(3, printf("seq_close: closed ret = %d.\n", ret));
- mtx_unlock(&scp->seq_lock);
- return ret;
-}
-
-int
-mseq_read(struct cdev *i_dev, struct uio *uio, int ioflag)
-{
- int retval, used;
- struct seq_softc *scp = i_dev->si_drv1;
-
-#define SEQ_RSIZE 32
- u_char buf[SEQ_RSIZE];
-
- if (scp == NULL)
- return ENXIO;
-
- SEQ_DEBUG(7, printf("mseq_read: unit %d, resid %zd.\n",
- scp->unit, uio->uio_resid));
-
- mtx_lock(&scp->seq_lock);
- if ((scp->fflags & FREAD) == 0) {
- SEQ_DEBUG(2, printf("mseq_read: unit %d is not for reading.\n",
- scp->unit));
- retval = EIO;
- goto err1;
- }
- /*
- * Begin recording.
- */
- /*
- * if ((scp->flags & SEQ_F_READING) == 0)
- */
- /*
- * TODO, start recording if not alread
- */
-
- /*
- * I think the semantics are to return as soon
- * as possible.
- * Second thought, it doesn't seem like midimoutain
- * expects that at all.
- * TODO: Look up in some sort of spec
- */
-
- while (uio->uio_resid > 0) {
- while (MIDIQ_EMPTY(scp->in_q)) {
- retval = EWOULDBLOCK;
- /*
- * I wish I knew which one to care about
- */
-
- if (scp->fflags & O_NONBLOCK)
- goto err1;
- if (ioflag & O_NONBLOCK)
- goto err1;
-
- retval = cv_wait_sig(&scp->in_cv, &scp->seq_lock);
- if (retval != 0)
- goto err1;
- }
-
- used = MIN(MIDIQ_LEN(scp->in_q), uio->uio_resid);
- used = MIN(used, SEQ_RSIZE);
-
- SEQ_DEBUG(8, printf("midiread: uiomove cc=%d\n", used));
- MIDIQ_DEQ(scp->in_q, buf, used);
- mtx_unlock(&scp->seq_lock);
- retval = uiomove(buf, used, uio);
- mtx_lock(&scp->seq_lock);
- if (retval)
- goto err1;
- }
-
- retval = 0;
-err1:
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(6, printf("mseq_read: ret %d, resid %zd.\n",
- retval, uio->uio_resid));
-
- return retval;
-}
-
-int
-mseq_write(struct cdev *i_dev, struct uio *uio, int ioflag)
-{
- u_char event[EV_SZ], newevent[EV_SZ], ev_code;
- struct seq_softc *scp = i_dev->si_drv1;
- int retval;
- int used;
-
- SEQ_DEBUG(7, printf("seq_write: unit %d, resid %zd.\n",
- scp->unit, uio->uio_resid));
-
- if (scp == NULL)
- return ENXIO;
-
- mtx_lock(&scp->seq_lock);
-
- if ((scp->fflags & FWRITE) == 0) {
- SEQ_DEBUG(2, printf("seq_write: unit %d is not for writing.\n",
- scp->unit));
- retval = EIO;
- goto err0;
- }
- while (uio->uio_resid > 0) {
- while (MIDIQ_AVAIL(scp->out_q) == 0) {
- retval = EWOULDBLOCK;
- if (scp->fflags & O_NONBLOCK)
- goto err0;
- if (ioflag & O_NONBLOCK)
- goto err0;
- SEQ_DEBUG(8, printf("seq_write cvwait\n"));
-
- scp->playing = 1;
- cv_broadcast(&scp->out_cv);
- cv_broadcast(&scp->state_cv);
-
- retval = cv_wait_sig(&scp->out_cv, &scp->seq_lock);
- /*
- * We slept, maybe things have changed since last
- * dying check
- */
- if (retval != 0)
- goto err0;
-#if 0
- /*
- * Useless test
- */
- if (scp != i_dev->si_drv1)
- retval = ENXIO;
-#endif
- }
-
- used = MIN(uio->uio_resid, 4);
-
- SEQ_DEBUG(8, printf("seqout: resid %zd len %jd avail %jd\n",
- uio->uio_resid, (intmax_t)MIDIQ_LEN(scp->out_q),
- (intmax_t)MIDIQ_AVAIL(scp->out_q)));
-
- if (used != 4) {
- retval = ENXIO;
- goto err0;
- }
- mtx_unlock(&scp->seq_lock);
- retval = uiomove(event, used, uio);
- mtx_lock(&scp->seq_lock);
- if (retval)
- goto err0;
-
- ev_code = event[0];
- SEQ_DEBUG(8, printf("seq_write: unit %d, event %s.\n",
- scp->unit, midi_cmdname(ev_code, cmdtab_seqevent)));
-
- /* Have a look at the event code. */
- if (ev_code == SEQ_FULLSIZE) {
- /*
- * TODO: restore code for SEQ_FULLSIZE
- */
-#if 0
- /*
- * A long event, these are the patches/samples for a
- * synthesizer.
- */
- midiunit = *(u_short *)&event[2];
- mtx_lock(&sd->seq_lock);
- ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md);
- mtx_unlock(&sd->seq_lock);
- if (ret != 0)
- return (ret);
-
- SEQ_DEBUG(printf("seq_write: loading a patch to the unit %d.\n", midiunit));
-
- ret = md->synth.loadpatch(md, *(short *)&event[0], buf,
- p + 4, count, 0);
- return (ret);
-#else
- /*
- * For now, just flush the darn buffer
- */
- SEQ_DEBUG(2,
- printf("seq_write: SEQ_FULLSIZE flusing buffer.\n"));
- while (uio->uio_resid > 0) {
- mtx_unlock(&scp->seq_lock);
- retval = uiomove(event, MIN(EV_SZ, uio->uio_resid), uio);
- mtx_lock(&scp->seq_lock);
- if (retval)
- goto err0;
- }
- retval = 0;
- goto err0;
-#endif
- }
- retval = EINVAL;
- if (ev_code >= 128) {
- int error;
-
- /*
- * Some sort of an extended event. The size is eight
- * bytes. scoop extra info.
- */
- if (scp->music && ev_code == SEQ_EXTENDED) {
- SEQ_DEBUG(2, printf("seq_write: invalid level two event %x.\n", ev_code));
- goto err0;
- }
- mtx_unlock(&scp->seq_lock);
- if (uio->uio_resid < 4)
- error = EINVAL;
- else
- error = uiomove((caddr_t)&event[4], 4, uio);
- mtx_lock(&scp->seq_lock);
- if (error) {
- SEQ_DEBUG(2,
- printf("seq_write: user memory mangled?\n"));
- goto err0;
- }
- } else {
- /*
- * Size four event.
- */
- if (scp->music) {
- SEQ_DEBUG(2, printf("seq_write: four byte event in music mode.\n"));
- goto err0;
- }
- }
- if (ev_code == SEQ_MIDIPUTC) {
- /*
- * TODO: event[2] is unit number to receive char.
- * Range check it.
- */
- }
- if (scp->music) {
-#ifdef not_ever_ever
- if (event[0] == EV_TIMING &&
- (event[1] == TMR_START || event[1] == TMR_STOP)) {
- /*
- * For now, try to make midimoutain work by
- * forcing these events to be processed
- * immediately.
- */
- seq_processevent(scp, event);
- } else
- MIDIQ_ENQ(scp->out_q, event, EV_SZ);
-#else
- MIDIQ_ENQ(scp->out_q, event, EV_SZ);
-#endif
- } else {
- if (seq_convertold(event, newevent) > 0)
- MIDIQ_ENQ(scp->out_q, newevent, EV_SZ);
-#if 0
- else
- goto err0;
-#endif
- }
- }
-
- scp->playing = 1;
- cv_broadcast(&scp->state_cv);
- cv_broadcast(&scp->out_cv);
-
- retval = 0;
-
-err0:
- SEQ_DEBUG(6,
- printf("seq_write done: leftover buffer length %zd retval %d\n",
- uio->uio_resid, retval));
- mtx_unlock(&scp->seq_lock);
- return retval;
-}
-
-int
-mseq_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
- struct thread *td)
-{
- int midiunit, ret, tmp;
- struct seq_softc *scp = i_dev->si_drv1;
- struct synth_info *synthinfo;
- struct midi_info *midiinfo;
- u_char event[EV_SZ];
- u_char newevent[EV_SZ];
-
- kobj_t md;
-
- /*
- * struct snd_size *sndsize;
- */
-
- if (scp == NULL)
- return ENXIO;
-
- SEQ_DEBUG(6, printf("seq_ioctl: unit %d, cmd %s.\n",
- scp->unit, midi_cmdname(cmd, cmdtab_seqioctl)));
-
- ret = 0;
-
- switch (cmd) {
- case SNDCTL_SEQ_GETTIME:
- /*
- * ioctl needed by libtse
- */
- mtx_lock(&scp->seq_lock);
- *(int *)arg = timer_now(scp);
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(6, printf("seq_ioctl: gettime %d.\n", *(int *)arg));
- ret = 0;
- break;
- case SNDCTL_TMR_METRONOME:
- /* fallthrough */
- case SNDCTL_TMR_SOURCE:
- /*
- * Not implemented
- */
- ret = 0;
- break;
- case SNDCTL_TMR_TEMPO:
- event[1] = TMR_TEMPO;
- event[4] = *(int *)arg & 0xFF;
- event[5] = (*(int *)arg >> 8) & 0xFF;
- event[6] = (*(int *)arg >> 16) & 0xFF;
- event[7] = (*(int *)arg >> 24) & 0xFF;
- goto timerevent;
- case SNDCTL_TMR_TIMEBASE:
- event[1] = TMR_TIMERBASE;
- event[4] = *(int *)arg & 0xFF;
- event[5] = (*(int *)arg >> 8) & 0xFF;
- event[6] = (*(int *)arg >> 16) & 0xFF;
- event[7] = (*(int *)arg >> 24) & 0xFF;
- goto timerevent;
- case SNDCTL_TMR_START:
- event[1] = TMR_START;
- goto timerevent;
- case SNDCTL_TMR_STOP:
- event[1] = TMR_STOP;
- goto timerevent;
- case SNDCTL_TMR_CONTINUE:
- event[1] = TMR_CONTINUE;
-timerevent:
- event[0] = EV_TIMING;
- mtx_lock(&scp->seq_lock);
- if (!scp->music) {
- ret = EINVAL;
- mtx_unlock(&scp->seq_lock);
- break;
- }
- seq_processevent(scp, event);
- mtx_unlock(&scp->seq_lock);
- break;
- case SNDCTL_TMR_SELECT:
- SEQ_DEBUG(2,
- printf("seq_ioctl: SNDCTL_TMR_SELECT not supported\n"));
- ret = EINVAL;
- break;
- case SNDCTL_SEQ_SYNC:
- if (mode == O_RDONLY) {
- ret = 0;
- break;
- }
- mtx_lock(&scp->seq_lock);
- ret = seq_sync(scp);
- mtx_unlock(&scp->seq_lock);
- break;
- case SNDCTL_SEQ_PANIC:
- /* fallthrough */
- case SNDCTL_SEQ_RESET:
- /*
- * SNDCTL_SEQ_PANIC == SNDCTL_SEQ_RESET
- */
- mtx_lock(&scp->seq_lock);
- seq_reset(scp);
- mtx_unlock(&scp->seq_lock);
- ret = 0;
- break;
- case SNDCTL_SEQ_TESTMIDI:
- mtx_lock(&scp->seq_lock);
- /*
- * TODO: SNDCTL_SEQ_TESTMIDI now means "can I write to the
- * device?".
- */
- mtx_unlock(&scp->seq_lock);
- break;
-#if 0
- case SNDCTL_SEQ_GETINCOUNT:
- if (mode == O_WRONLY)
- *(int *)arg = 0;
- else {
- mtx_lock(&scp->seq_lock);
- *(int *)arg = scp->in_q.rl;
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(printf("seq_ioctl: incount %d.\n",
- *(int *)arg));
- }
- ret = 0;
- break;
- case SNDCTL_SEQ_GETOUTCOUNT:
- if (mode == O_RDONLY)
- *(int *)arg = 0;
- else {
- mtx_lock(&scp->seq_lock);
- *(int *)arg = scp->out_q.fl;
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(printf("seq_ioctl: outcount %d.\n",
- *(int *)arg));
- }
- ret = 0;
- break;
-#endif
- case SNDCTL_SEQ_CTRLRATE:
- if (*(int *)arg != 0) {
- ret = EINVAL;
- break;
- }
- mtx_lock(&scp->seq_lock);
- *(int *)arg = scp->timerbase;
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(3, printf("seq_ioctl: ctrlrate %d.\n", *(int *)arg));
- ret = 0;
- break;
- /*
- * TODO: ioctl SNDCTL_SEQ_RESETSAMPLES
- */
-#if 0
- case SNDCTL_SEQ_RESETSAMPLES:
- mtx_lock(&scp->seq_lock);
- ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md);
- mtx_unlock(&scp->seq_lock);
- if (ret != 0)
- break;
- ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg,
- SND_DEV_MIDIN), cmd, arg, mode, td);
- break;
-#endif
- case SNDCTL_SEQ_NRSYNTHS:
- mtx_lock(&scp->seq_lock);
- *(int *)arg = scp->midi_number;
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(3, printf("seq_ioctl: synths %d.\n", *(int *)arg));
- ret = 0;
- break;
- case SNDCTL_SEQ_NRMIDIS:
- mtx_lock(&scp->seq_lock);
- if (scp->music)
- *(int *)arg = 0;
- else {
- /*
- * TODO: count the numbder of devices that can WRITERAW
- */
- *(int *)arg = scp->midi_number;
- }
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(3, printf("seq_ioctl: midis %d.\n", *(int *)arg));
- ret = 0;
- break;
- /*
- * TODO: ioctl SNDCTL_SYNTH_MEMAVL
- */
-#if 0
- case SNDCTL_SYNTH_MEMAVL:
- mtx_lock(&scp->seq_lock);
- ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md);
- mtx_unlock(&scp->seq_lock);
- if (ret != 0)
- break;
- ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg,
- SND_DEV_MIDIN), cmd, arg, mode, td);
- break;
-#endif
- case SNDCTL_SEQ_OUTOFBAND:
- for (ret = 0; ret < EV_SZ; ret++)
- event[ret] = (u_char)arg[0];
-
- mtx_lock(&scp->seq_lock);
- if (scp->music)
- ret = seq_processevent(scp, event);
- else {
- if (seq_convertold(event, newevent) > 0)
- ret = seq_processevent(scp, newevent);
- else
- ret = EINVAL;
- }
- mtx_unlock(&scp->seq_lock);
- break;
- case SNDCTL_SYNTH_INFO:
- synthinfo = (struct synth_info *)arg;
- midiunit = synthinfo->device;
- mtx_lock(&scp->seq_lock);
- if (seq_fetch_mid(scp, midiunit, &md) == 0) {
- bzero(synthinfo, sizeof(*synthinfo));
- synthinfo->name[0] = 'f';
- synthinfo->name[1] = 'a';
- synthinfo->name[2] = 'k';
- synthinfo->name[3] = 'e';
- synthinfo->name[4] = 's';
- synthinfo->name[5] = 'y';
- synthinfo->name[6] = 'n';
- synthinfo->name[7] = 't';
- synthinfo->name[8] = 'h';
- synthinfo->device = midiunit;
- synthinfo->synth_type = SYNTH_TYPE_MIDI;
- synthinfo->capabilities = scp->midi_flags[midiunit];
- ret = 0;
- } else
- ret = EINVAL;
- mtx_unlock(&scp->seq_lock);
- break;
- case SNDCTL_MIDI_INFO:
- midiinfo = (struct midi_info *)arg;
- midiunit = midiinfo->device;
- mtx_lock(&scp->seq_lock);
- if (seq_fetch_mid(scp, midiunit, &md) == 0) {
- bzero(midiinfo, sizeof(*midiinfo));
- midiinfo->name[0] = 'f';
- midiinfo->name[1] = 'a';
- midiinfo->name[2] = 'k';
- midiinfo->name[3] = 'e';
- midiinfo->name[4] = 'm';
- midiinfo->name[5] = 'i';
- midiinfo->name[6] = 'd';
- midiinfo->name[7] = 'i';
- midiinfo->device = midiunit;
- midiinfo->capabilities = scp->midi_flags[midiunit];
- /*
- * TODO: What devtype?
- */
- midiinfo->dev_type = 0x01;
- ret = 0;
- } else
- ret = EINVAL;
- mtx_unlock(&scp->seq_lock);
- break;
- case SNDCTL_SEQ_THRESHOLD:
- mtx_lock(&scp->seq_lock);
- RANGE(*(int *)arg, 1, MIDIQ_SIZE(scp->out_q) - 1);
- scp->out_water = *(int *)arg;
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(3, printf("seq_ioctl: water %d.\n", *(int *)arg));
- ret = 0;
- break;
- case SNDCTL_MIDI_PRETIME:
- tmp = *(int *)arg;
- if (tmp < 0)
- tmp = 0;
- mtx_lock(&scp->seq_lock);
- scp->pre_event_timeout = (hz * tmp) / 10;
- *(int *)arg = scp->pre_event_timeout;
- mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(3, printf("seq_ioctl: pretime %d.\n", *(int *)arg));
- ret = 0;
- break;
- case SNDCTL_FM_4OP_ENABLE:
- case SNDCTL_PMGR_IFACE:
- case SNDCTL_PMGR_ACCESS:
- /*
- * Patch manager and fm are ded, ded, ded.
- */
- /* fallthrough */
- default:
- /*
- * TODO: Consider ioctl default case.
- * Old code used to
- * if ((scp->fflags & O_ACCMODE) == FREAD) {
- * ret = EIO;
- * break;
- * }
- * Then pass on the ioctl to device 0
- */
- SEQ_DEBUG(2,
- printf("seq_ioctl: unsupported IOCTL %ld.\n", cmd));
- ret = EINVAL;
- break;
- }
-
- return ret;
-}
-
-int
-mseq_poll(struct cdev *i_dev, int events, struct thread *td)
-{
- int ret, lim;
- struct seq_softc *scp = i_dev->si_drv1;
-
- SEQ_DEBUG(3, printf("seq_poll: unit %d.\n", scp->unit));
- SEQ_DEBUG(1, printf("seq_poll: unit %d.\n", scp->unit));
-
- mtx_lock(&scp->seq_lock);
-
- ret = 0;
-
- /* Look up the appropriate queue and select it. */
- if ((events & (POLLOUT | POLLWRNORM)) != 0) {
- /* Start playing. */
- scp->playing = 1;
- cv_broadcast(&scp->state_cv);
- cv_broadcast(&scp->out_cv);
-
- lim = scp->out_water;
-
- if (MIDIQ_AVAIL(scp->out_q) < lim)
- /* No enough space, record select. */
- selrecord(td, &scp->out_sel);
- else
- /* We can write now. */
- ret |= events & (POLLOUT | POLLWRNORM);
- }
- if ((events & (POLLIN | POLLRDNORM)) != 0) {
- /* TODO: Start recording. */
-
- /* Find out the boundary. */
- lim = 1;
- if (MIDIQ_LEN(scp->in_q) < lim)
- /* No data ready, record select. */
- selrecord(td, &scp->in_sel);
- else
- /* We can read now. */
- ret |= events & (POLLIN | POLLRDNORM);
- }
- mtx_unlock(&scp->seq_lock);
-
- return (ret);
-}
-
-#if 0
-static void
-sein_qtr(void *p, void /* mididev_info */ *md)
-{
- struct seq_softc *scp;
-
- scp = (struct seq_softc *)p;
-
- mtx_lock(&scp->seq_lock);
-
- /* Restart playing if we have the data to output. */
- if (scp->queueout_pending)
- seq_callback(scp, SEQ_CB_START | SEQ_CB_WR);
- /* Check the midi device if we are reading. */
- if ((scp->flags & SEQ_F_READING) != 0)
- seq_midiinput(scp, md);
-
- mtx_unlock(&scp->seq_lock);
-}
-
-#endif
-/*
- * seq_convertold
- * Was the old playevent. Use this to convert and old
- * style /dev/sequencer event to a /dev/music event
- */
-static int
-seq_convertold(u_char *event, u_char *out)
-{
- int used;
- u_char dev, chn, note, vel;
-
- out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] =
- out[7] = 0;
-
- dev = 0;
- chn = event[1];
- note = event[2];
- vel = event[3];
-
- used = 0;
-
-restart:
- /*
- * TODO: Debug statement
- */
- switch (event[0]) {
- case EV_TIMING:
- case EV_CHN_VOICE:
- case EV_CHN_COMMON:
- case EV_SYSEX:
- case EV_SEQ_LOCAL:
- out[0] = event[0];
- out[1] = event[1];
- out[2] = event[2];
- out[3] = event[3];
- out[4] = event[4];
- out[5] = event[5];
- out[6] = event[6];
- out[7] = event[7];
- used += 8;
- break;
- case SEQ_NOTEOFF:
- out[0] = EV_CHN_VOICE;
- out[1] = dev;
- out[2] = MIDI_NOTEOFF;
- out[3] = chn;
- out[4] = note;
- out[5] = 255;
- used += 4;
- break;
-
- case SEQ_NOTEON:
- out[0] = EV_CHN_VOICE;
- out[1] = dev;
- out[2] = MIDI_NOTEON;
- out[3] = chn;
- out[4] = note;
- out[5] = vel;
- used += 4;
- break;
-
- /*
- * wait delay = (event[2] << 16) + (event[3] << 8) + event[4]
- */
-
- case SEQ_PGMCHANGE:
- out[0] = EV_CHN_COMMON;
- out[1] = dev;
- out[2] = MIDI_PGM_CHANGE;
- out[3] = chn;
- out[4] = note;
- out[5] = vel;
- used += 4;
- break;
-/*
- out[0] = EV_TIMING;
- out[1] = dev;
- out[2] = MIDI_PGM_CHANGE;
- out[3] = chn;
- out[4] = note;
- out[5] = vel;
- SEQ_DEBUG(4,printf("seq_playevent: synctimer\n"));
- break;
-*/
-
- case SEQ_MIDIPUTC:
- SEQ_DEBUG(4,
- printf("seq_playevent: put data 0x%02x, unit %d.\n",
- event[1], event[2]));
- /*
- * Pass through to the midi device.
- * device = event[2]
- * data = event[1]
- */
- out[0] = SEQ_MIDIPUTC;
- out[1] = dev;
- out[2] = chn;
- used += 4;
- break;
-#ifdef notyet
- case SEQ_ECHO:
- /*
- * This isn't handled here yet because I don't know if I can
- * just use four bytes events. There might be consequences
- * in the _read routing
- */
- if (seq_copytoinput(scp, event, 4) == EAGAIN) {
- ret = QUEUEFULL;
- break;
- }
- ret = MORE;
- break;
-#endif
- case SEQ_EXTENDED:
- switch (event[1]) {
- case SEQ_NOTEOFF:
- case SEQ_NOTEON:
- case SEQ_PGMCHANGE:
- event++;
- used = 4;
- goto restart;
- break;
- case SEQ_AFTERTOUCH:
- /*
- * SYNTH_AFTERTOUCH(md, event[3], event[4])
- */
- case SEQ_BALANCE:
- /*
- * SYNTH_PANNING(md, event[3], (char)event[4])
- */
- case SEQ_CONTROLLER:
- /*
- * SYNTH_CONTROLLER(md, event[3], event[4], *(short *)&event[5])
- */
- case SEQ_VOLMODE:
- /*
- * SYNTH_VOLUMEMETHOD(md, event[3])
- */
- default:
- SEQ_DEBUG(2,
- printf("seq_convertold: SEQ_EXTENDED type %d"
- "not handled\n", event[1]));
- break;
- }
- break;
- case SEQ_WAIT:
- out[0] = EV_TIMING;
- out[1] = TMR_WAIT_REL;
- out[4] = event[2];
- out[5] = event[3];
- out[6] = event[4];
-
- SEQ_DEBUG(5, printf("SEQ_WAIT %d",
- event[2] + (event[3] << 8) + (event[4] << 24)));
-
- used += 4;
- break;
-
- case SEQ_ECHO:
- case SEQ_SYNCTIMER:
- case SEQ_PRIVATE:
- default:
- SEQ_DEBUG(2,
- printf("seq_convertold: event type %d not handled %d %d %d\n",
- event[0], event[1], event[2], event[3]));
- break;
- }
- return used;
-}
-
-/*
- * Writting to the sequencer buffer never blocks and drops
- * input which cannot be queued
- */
-void
-seq_copytoinput(struct seq_softc *scp, u_char *event, int len)
-{
-
- mtx_assert(&scp->seq_lock, MA_OWNED);
-
- if (MIDIQ_AVAIL(scp->in_q) < len) {
- /*
- * ENOROOM? EINPUTDROPPED? ETOUGHLUCK?
- */
- SEQ_DEBUG(2, printf("seq_copytoinput: queue full\n"));
- } else {
- MIDIQ_ENQ(scp->in_q, event, len);
- selwakeup(&scp->in_sel);
- cv_broadcast(&scp->in_cv);
- }
-
-}
-
-static int
-seq_chnvoice(struct seq_softc *scp, kobj_t md, u_char *event)
-{
- int ret, voice;
- u_char cmd, chn, note, parm;
-
- ret = 0;
- cmd = event[2];
- chn = event[3];
- note = event[4];
- parm = event[5];
-
- mtx_assert(&scp->seq_lock, MA_OWNED);
-
- SEQ_DEBUG(5, printf("seq_chnvoice: unit %d, dev %d, cmd %s,"
- " chn %d, note %d, parm %d.\n", scp->unit, event[1],
- midi_cmdname(cmd, cmdtab_seqcv), chn, note, parm));
-
- voice = SYNTH_ALLOC(md, chn, note);
-
- mtx_unlock(&scp->seq_lock);
-
- switch (cmd) {
- case MIDI_NOTEON:
- if (note < 128 || note == 255) {
-#if 0
- if (scp->music && chn == 9) {
- /*
- * This channel is a percussion. The note
- * number is the patch number.
- */
- /*
- mtx_unlock(&scp->seq_lock);
- if (SYNTH_SETINSTR(md, voice, 128 + note)
- == EAGAIN) {
- mtx_lock(&scp->seq_lock);
- return (QUEUEFULL);
- }
- mtx_lock(&scp->seq_lock);
- */
- note = 60; /* Middle C. */
- }
-#endif
- if (scp->music) {
- /*
- mtx_unlock(&scp->seq_lock);
- if (SYNTH_SETUPVOICE(md, voice, chn)
- == EAGAIN) {
- mtx_lock(&scp->seq_lock);
- return (QUEUEFULL);
- }
- mtx_lock(&scp->seq_lock);
- */
- }
- SYNTH_STARTNOTE(md, voice, note, parm);
- }
- break;
- case MIDI_NOTEOFF:
- SYNTH_KILLNOTE(md, voice, note, parm);
- break;
- case MIDI_KEY_PRESSURE:
- SYNTH_AFTERTOUCH(md, voice, parm);
- break;
- default:
- ret = 1;
- SEQ_DEBUG(2, printf("seq_chnvoice event type %d not handled\n",
- event[1]));
- break;
- }
-
- mtx_lock(&scp->seq_lock);
- return ret;
-}
-
-static int
-seq_chncommon(struct seq_softc *scp, kobj_t md, u_char *event)
-{
- int ret;
- u_short w14;
- u_char cmd, chn, p1;
-
- ret = 0;
- cmd = event[2];
- chn = event[3];
- p1 = event[4];
- w14 = *(u_short *)&event[6];
-
- SEQ_DEBUG(5, printf("seq_chncommon: unit %d, dev %d, cmd %s, chn %d,"
- " p1 %d, w14 %d.\n", scp->unit, event[1],
- midi_cmdname(cmd, cmdtab_seqccmn), chn, p1, w14));
- mtx_unlock(&scp->seq_lock);
- switch (cmd) {
- case MIDI_PGM_CHANGE:
- SEQ_DEBUG(4, printf("seq_chncommon pgmchn chn %d pg %d\n",
- chn, p1));
- SYNTH_SETINSTR(md, chn, p1);
- break;
- case MIDI_CTL_CHANGE:
- SEQ_DEBUG(4, printf("seq_chncommon ctlch chn %d pg %d %d\n",
- chn, p1, w14));
- SYNTH_CONTROLLER(md, chn, p1, w14);
- break;
- case MIDI_PITCH_BEND:
- if (scp->music) {
- /*
- * TODO: MIDI_PITCH_BEND
- */
-#if 0
- mtx_lock(&md->synth.vc_mtx);
- md->synth.chn_info[chn].bender_value = w14;
- if (md->midiunit >= 0) {
- /*
- * Handle all of the notes playing on this
- * channel.
- */
- key = ((int)chn << 8);
- for (i = 0; i < md->synth.alloc.max_voice; i++)
- if ((md->synth.alloc.map[i] & 0xff00) == key) {
- mtx_unlock(&md->synth.vc_mtx);
- mtx_unlock(&scp->seq_lock);
- if (md->synth.bender(md, i, w14) == EAGAIN) {
- mtx_lock(&scp->seq_lock);
- return (QUEUEFULL);
- }
- mtx_lock(&scp->seq_lock);
- }
- } else {
- mtx_unlock(&md->synth.vc_mtx);
- mtx_unlock(&scp->seq_lock);
- if (md->synth.bender(md, chn, w14) == EAGAIN) {
- mtx_lock(&scp->seq_lock);
- return (QUEUEFULL);
- }
- mtx_lock(&scp->seq_lock);
- }
-#endif
- } else
- SYNTH_BENDER(md, chn, w14);
- break;
- default:
- ret = 1;
- SEQ_DEBUG(2,
- printf("seq_chncommon event type %d not handled.\n",
- event[1]));
- break;
- }
- mtx_lock(&scp->seq_lock);
- return ret;
-}
-
-static int
-seq_timing(struct seq_softc *scp, u_char *event)
-{
- int param;
- int ret;
-
- ret = 0;
- param = event[4] + (event[5] << 8) +
- (event[6] << 16) + (event[7] << 24);
-
- SEQ_DEBUG(5, printf("seq_timing: unit %d, cmd %d, param %d.\n",
- scp->unit, event[1], param));
- switch (event[1]) {
- case TMR_WAIT_REL:
- timer_wait(scp, param, 0);
- break;
- case TMR_WAIT_ABS:
- timer_wait(scp, param, 1);
- break;
- case TMR_START:
- timer_start(scp);
- cv_broadcast(&scp->reset_cv);
- break;
- case TMR_STOP:
- timer_stop(scp);
- /*
- * The following cv_broadcast isn't needed since we only
- * wait for 0->1 transitions. It probably won't hurt
- */
- cv_broadcast(&scp->reset_cv);
- break;
- case TMR_CONTINUE:
- timer_continue(scp);
- cv_broadcast(&scp->reset_cv);
- break;
- case TMR_TEMPO:
- if (param < 8)
- param = 8;
- if (param > 360)
- param = 360;
- SEQ_DEBUG(4, printf("Timer set tempo %d\n", param));
- timer_setvals(scp, param, scp->timerbase);
- break;
- case TMR_TIMERBASE:
- if (param < 1)
- param = 1;
- if (param > 1000)
- param = 1000;
- SEQ_DEBUG(4, printf("Timer set timerbase %d\n", param));
- timer_setvals(scp, scp->tempo, param);
- break;
- case TMR_ECHO:
- /*
- * TODO: Consider making 4-byte events for /dev/sequencer
- * PRO: Maybe needed by legacy apps
- * CON: soundcard.h has been warning for a while many years
- * to expect 8 byte events.
- */
-#if 0
- if (scp->music)
- seq_copytoinput(scp, event, 8);
- else {
- param = (param << 8 | SEQ_ECHO);
- seq_copytoinput(scp, (u_char *)&param, 4);
- }
-#else
- seq_copytoinput(scp, event, 8);
-#endif
- break;
- default:
- SEQ_DEBUG(2, printf("seq_timing event type %d not handled.\n",
- event[1]));
- ret = 1;
- break;
- }
- return ret;
-}
-
-static int
-seq_local(struct seq_softc *scp, u_char *event)
-{
- int ret;
-
- ret = 0;
- mtx_assert(&scp->seq_lock, MA_OWNED);
-
- SEQ_DEBUG(5, printf("seq_local: unit %d, cmd %d\n", scp->unit,
- event[1]));
- switch (event[1]) {
- default:
- SEQ_DEBUG(1, printf("seq_local event type %d not handled\n",
- event[1]));
- ret = 1;
- break;
- }
- return ret;
-}
-
-static int
-seq_sysex(struct seq_softc *scp, kobj_t md, u_char *event)
-{
- int i, l;
-
- mtx_assert(&scp->seq_lock, MA_OWNED);
- SEQ_DEBUG(5, printf("seq_sysex: unit %d device %d\n", scp->unit,
- event[1]));
- l = 0;
- for (i = 0; i < 6 && event[i + 2] != 0xff; i++)
- l = i + 1;
- if (l > 0) {
- mtx_unlock(&scp->seq_lock);
- if (SYNTH_SENDSYSEX(md, &event[2], l) == EAGAIN) {
- mtx_lock(&scp->seq_lock);
- return 1;
- }
- mtx_lock(&scp->seq_lock);
- }
- return 0;
-}
-
-/*
- * Reset no longer closes the raw devices nor seq_sync's
- * Callers are IOCTL and seq_close
- */
-static void
-seq_reset(struct seq_softc *scp)
-{
- int chn, i;
- kobj_t m;
-
- mtx_assert(&scp->seq_lock, MA_OWNED);
-
- SEQ_DEBUG(5, printf("seq_reset: unit %d.\n", scp->unit));
-
- /*
- * Stop reading and writing.
- */
-
- /* scp->recording = 0; */
- scp->playing = 0;
- cv_broadcast(&scp->state_cv);
- cv_broadcast(&scp->out_cv);
- cv_broadcast(&scp->reset_cv);
-
- /*
- * For now, don't reset the timers.
- */
- MIDIQ_CLEAR(scp->in_q);
- MIDIQ_CLEAR(scp->out_q);
-
- for (i = 0; i < scp->midi_number; i++) {
- m = scp->midis[i];
- mtx_unlock(&scp->seq_lock);
- SYNTH_RESET(m);
- for (chn = 0; chn < 16; chn++) {
- SYNTH_CONTROLLER(m, chn, 123, 0);
- SYNTH_CONTROLLER(m, chn, 121, 0);
- SYNTH_BENDER(m, chn, 1 << 13);
- }
- mtx_lock(&scp->seq_lock);
- }
-}
-
-/*
- * seq_sync
- * *really* flush the output queue
- * flush the event queue, then flush the synthsisers.
- * Callers are IOCTL and close
- */
-
-#define SEQ_SYNC_TIMEOUT 8
-static int
-seq_sync(struct seq_softc *scp)
-{
- int i, rl, sync[16], done;
-
- mtx_assert(&scp->seq_lock, MA_OWNED);
-
- SEQ_DEBUG(4, printf("seq_sync: unit %d.\n", scp->unit));
-
- /*
- * Wait until output queue is empty. Check every so often to see if
- * the queue is moving along. If it isn't just abort.
- */
- while (!MIDIQ_EMPTY(scp->out_q)) {
- if (!scp->playing) {
- scp->playing = 1;
- cv_broadcast(&scp->state_cv);
- cv_broadcast(&scp->out_cv);
- }
- rl = MIDIQ_LEN(scp->out_q);
-
- i = cv_timedwait_sig(&scp->out_cv,
- &scp->seq_lock, SEQ_SYNC_TIMEOUT * hz);
-
- if (i == EINTR || i == ERESTART) {
- if (i == EINTR) {
- /*
- * XXX: I don't know why we stop playing
- */
- scp->playing = 0;
- cv_broadcast(&scp->out_cv);
- }
- return i;
- }
- if (i == EWOULDBLOCK && rl == MIDIQ_LEN(scp->out_q) &&
- scp->waiting == 0) {
- /*
- * A queue seems to be stuck up. Give up and clear
- * queues.
- */
- MIDIQ_CLEAR(scp->out_q);
- scp->playing = 0;
- cv_broadcast(&scp->state_cv);
- cv_broadcast(&scp->out_cv);
- cv_broadcast(&scp->reset_cv);
-
- /*
- * TODO: Consider if the raw devices need to be flushed
- */
-
- SEQ_DEBUG(1, printf("seq_sync queue stuck, aborting\n"));
-
- return i;
- }
- }
-
- scp->playing = 0;
- /*
- * Since syncing a midi device might block, unlock scp->seq_lock.
- */
-
- mtx_unlock(&scp->seq_lock);
- for (i = 0; i < scp->midi_number; i++)
- sync[i] = 1;
-
- do {
- done = 1;
- for (i = 0; i < scp->midi_number; i++)
- if (sync[i]) {
- if (SYNTH_INSYNC(scp->midis[i]) == 0)
- sync[i] = 0;
- else
- done = 0;
- }
- if (!done)
- DELAY(5000);
-
- } while (!done);
-
- mtx_lock(&scp->seq_lock);
- return 0;
-}
-
-char *
-midi_cmdname(int cmd, midi_cmdtab *tab)
-{
- while (tab->name != NULL) {
- if (cmd == tab->cmd)
- return (tab->name);
- tab++;
- }
-
- return ("unknown");
-}
diff --git a/sys/dev/sound/midi/synth_if.m b/sys/dev/sound/midi/synth_if.m
deleted file mode 100644
index a763b3422bc6..000000000000
--- a/sys/dev/sound/midi/synth_if.m
+++ /dev/null
@@ -1,312 +0,0 @@
-#-
-# Copyright (c) 2003 Mathew Kanner
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-#
-
-INTERFACE synth;
-
-#include <sys/systm.h>
-
-CODE {
-
-synth_killnote_t nokillnote;
-synth_startnote_t nostartnote;
-synth_setinstr_t nosetinstr;
-synth_hwcontrol_t nohwcontrol;
-synth_aftertouch_t noaftertouch;
-synth_panning_t nopanning;
-synth_controller_t nocontroller;
-synth_volumemethod_t novolumemethod;
-synth_bender_t nobender;
-synth_setupvoice_t nosetupvoice;
-synth_sendsysex_t nosendsysex;
-synth_allocvoice_t noallocvoice;
-synth_writeraw_t nowriteraw;
-synth_reset_t noreset;
-synth_shortname_t noshortname;
-synth_open_t noopen;
-synth_close_t noclose;
-synth_query_t noquery;
-synth_insync_t noinsync;
-synth_alloc_t noalloc;
-
- int
- nokillnote(void *_kobj, uint8_t _chn, uint8_t _note, uint8_t _vel)
- {
- printf("nokillnote\n");
- return 0;
- }
-
- int
- noopen(void *_kobj, void *_arg, int mode)
- {
- printf("noopen\n");
- return 0;
- }
-
- int
- noquery(void *_kboj)
- {
- printf("noquery\n");
- return 0;
- }
-
- int
- nostartnote(void *_kb, uint8_t _voice, uint8_t _note, uint8_t _parm)
- {
- printf("nostartnote\n");
- return 0;
- }
-
- int
- nosetinstr(void *_kb, uint8_t _chn, uint16_t _patchno)
- {
- printf("nosetinstr\n");
- return 0;
- }
-
- int
- nohwcontrol(void *_kb, uint8_t *_event)
- {
- printf("nohwcontrol\n");
- return 0;
- }
-
- int
- noaftertouch ( void /* X */ * _kobj, uint8_t _x1, uint8_t _x2)
- {
- printf("noaftertouch\n");
- return 0;
- }
-
- int
- nopanning ( void /* X */ * _kobj, uint8_t _x1, uint8_t _x2)
- {
- printf("nopanning\n");
- return 0;
- }
-
- int
- nocontroller ( void /* X */ * _kobj, uint8_t _x1, uint8_t _x2, uint16_t _x3)
- {
- printf("nocontroller\n");
- return 0;
- }
-
- int
- novolumemethod (
- void /* X */ * _kobj,
- uint8_t _x1)
- {
- printf("novolumemethod\n");
- return 0;
- }
-
- int
- nobender ( void /* X */ * _kobj, uint8_t _voice, uint16_t _bend)
- {
- printf("nobender\n");
- return 0;
- }
-
- int
- nosetupvoice ( void /* X */ * _kobj, uint8_t _voice, uint8_t _chn)
- {
-
- printf("nosetupvoice\n");
- return 0;
- }
-
- int
- nosendsysex ( void /* X */ * _kobj, void * _buf, size_t _len)
- {
- printf("nosendsysex\n");
- return 0;
- }
-
- int
- noallocvoice ( void /* X */ * _kobj, uint8_t _chn, uint8_t _note, void *_x)
- {
- printf("noallocvoice\n");
- return 0;
- }
-
- int
- nowriteraw ( void /* X */ * _kobjt, uint8_t * _buf, size_t _len)
- {
- printf("nowriteraw\n");
- return 1;
- }
-
- int
- noreset ( void /* X */ * _kobjt)
- {
-
- printf("noreset\n");
- return 0;
- }
-
- char *
- noshortname (void /* X */ * _kobjt)
- {
- printf("noshortname\n");
- return "noshortname";
- }
-
- int
- noclose ( void /* X */ * _kobjt)
- {
-
- printf("noclose\n");
- return 0;
- }
-
- int
- noinsync (void /* X */ * _kobjt)
- {
-
- printf("noinsync\n");
- return 0;
- }
-
- int
- noalloc ( void /* x */ * _kbojt, uint8_t _chn, uint8_t _note)
- {
- printf("noalloc\n");
- return 0;
- }
-}
-
-METHOD int killnote {
- void /* X */ *_kobj;
- uint8_t _chan;
- uint8_t _note;
- uint8_t _vel;
-} DEFAULT nokillnote;
-
-METHOD int startnote {
- void /* X */ *_kobj;
- uint8_t _voice;
- uint8_t _note;
- uint8_t _parm;
-} DEFAULT nostartnote;
-
-METHOD int setinstr {
- void /* X */ *_kobj;
- uint8_t _chn;
- uint16_t _patchno;
-} DEFAULT nosetinstr;
-
-METHOD int hwcontrol {
- void /* X */ *_kobj;
- uint8_t *_event;
-} DEFAULT nohwcontrol;
-
-METHOD int aftertouch {
- void /* X */ *_kobj;
- uint8_t _x1;
- uint8_t _x2;
-} DEFAULT noaftertouch;
-
-METHOD int panning {
- void /* X */ *_kobj;
- uint8_t _x1;
- uint8_t _x2;
-} DEFAULT nopanning;
-
-METHOD int controller {
- void /* X */ *_kobj;
- uint8_t _x1;
- uint8_t _x2;
- uint16_t _x3;
-} DEFAULT nocontroller;
-
-METHOD int volumemethod {
- void /* X */ *_kobj;
- uint8_t _x1;
-} DEFAULT novolumemethod;
-
-METHOD int bender {
- void /* X */ *_kobj;
- uint8_t _voice;
- uint16_t _bend;
-} DEFAULT nobender;
-
-METHOD int setupvoice {
- void /* X */ *_kobj;
- uint8_t _voice;
- uint8_t _chn;
-} DEFAULT nosetupvoice;
-
-METHOD int sendsysex {
- void /* X */ *_kobj;
- void *_buf;
- size_t _len;
-} DEFAULT nosendsysex;
-
-METHOD int allocvoice {
- void /* X */ *_kobj;
- uint8_t _chn;
- uint8_t _note;
- void *_x;
-} DEFAULT noallocvoice;
-
-METHOD int writeraw {
- void /* X */ *_kobjt;
- uint8_t *_buf;
- size_t _len;
-} DEFAULT nowriteraw;
-
-METHOD int reset {
- void /* X */ *_kobjt;
-} DEFAULT noreset;
-
-METHOD char * shortname {
- void /* X */ *_kobjt;
-} DEFAULT noshortname;
-
-METHOD int open {
- void /* X */ *_kobjt;
- void *_sythn;
- int _mode;
-} DEFAULT noopen;
-
-METHOD int close {
- void /* X */ *_kobjt;
-} DEFAULT noclose;
-
-METHOD int query {
- void /* X */ *_kobjt;
-} DEFAULT noquery;
-
-METHOD int insync {
- void /* X */ *_kobjt;
-} DEFAULT noinsync;
-
-METHOD int alloc {
- void /* x */ *_kbojt;
- uint8_t _chn;
- uint8_t _note;
-} DEFAULT noalloc;
diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c
index 092af3298f0e..f281dff36248 100644
--- a/sys/dev/sound/pcm/mixer.c
+++ b/sys/dev/sound/pcm/mixer.c
@@ -750,8 +750,8 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
mixer_setrecsrc(m, 0); /* Set default input. */
- pdev = make_dev(&mixer_cdevsw, SND_DEV_CTL, UID_ROOT, GID_WHEEL, 0666,
- "mixer%d", unit);
+ pdev = make_dev(&mixer_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, "mixer%d",
+ unit);
pdev->si_drv1 = m;
snddev->mixer_dev = pdev;
diff --git a/sys/dev/sound/pcm/sndstat.c b/sys/dev/sound/pcm/sndstat.c
index 509a35c5a038..51d0fb3bb686 100644
--- a/sys/dev/sound/pcm/sndstat.c
+++ b/sys/dev/sound/pcm/sndstat.c
@@ -52,7 +52,6 @@
#define SS_TYPE_PCM 1
#define SS_TYPE_MIDI 2
-#define SS_TYPE_SEQUENCER 3
static d_open_t sndstat_open;
static void sndstat_close(void *);
@@ -1165,8 +1164,6 @@ sndstat_register(device_t dev, char *str)
type = SS_TYPE_PCM;
else if (!strcmp(devtype, "midi"))
type = SS_TYPE_MIDI;
- else if (!strcmp(devtype, "sequencer"))
- type = SS_TYPE_SEQUENCER;
else
return (EINVAL);
@@ -1441,8 +1438,8 @@ static void
sndstat_sysinit(void *p)
{
sx_init(&sndstat_lock, "sndstat lock");
- sndstat_dev = make_dev(&sndstat_cdevsw, SND_DEV_STATUS,
- UID_ROOT, GID_WHEEL, 0644, "sndstat");
+ sndstat_dev = make_dev(&sndstat_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644,
+ "sndstat");
}
SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysinit, NULL);
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index 315452e294d1..6bd435d0ea25 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -148,14 +148,6 @@ struct snd_mixer;
#define RANGE(var, low, high) (var) = \
(((var)<(low))? (low) : ((var)>(high))? (high) : (var))
-enum {
- SND_DEV_CTL = 0, /* Control port /dev/mixer */
- SND_DEV_SEQ, /* Sequencer /dev/sequencer */
- SND_DEV_MIDIN, /* Raw midi access */
- SND_DEV_DSP, /* Digitized voice /dev/dsp */
- SND_DEV_STATUS, /* /dev/sndstat */
-};
-
#define DSP_DEFAULT_SPEED 8000
extern int snd_unit;
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index cac743884ee6..ac58d44102a0 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -149,6 +149,8 @@ struct ufshci_hw_queue {
bus_dmamap_t queuemem_map;
bus_addr_t req_queue_addr;
+ bus_addr_t *ucd_bus_addr;
+
uint32_t num_entries;
uint32_t num_trackers;
@@ -198,8 +200,6 @@ struct ufshci_req_queue {
bus_dma_tag_t dma_tag_payload;
bus_dmamap_t ucdmem_map;
-
- bus_addr_t ucd_addr;
};
struct ufshci_device {
diff --git a/sys/dev/ufshci/ufshci_req_sdb.c b/sys/dev/ufshci/ufshci_req_sdb.c
index 4670281d367a..b1f303afaef5 100644
--- a/sys/dev/ufshci/ufshci_req_sdb.c
+++ b/sys/dev/ufshci/ufshci_req_sdb.c
@@ -48,6 +48,29 @@ ufshci_req_sdb_cmd_desc_destroy(struct ufshci_req_queue *req_queue)
}
}
+static void
+ufshci_ucd_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
+{
+ struct ufshci_hw_queue *hwq = arg;
+ int i;
+
+ if (error != 0) {
+ printf("ufshci: Failed to map UCD, error = %d\n", error);
+ return;
+ }
+
+ if (hwq->num_trackers != nseg) {
+ printf(
+ "ufshci: Failed to map UCD, num_trackers = %d, nseg = %d\n",
+ hwq->num_trackers, nseg);
+ return;
+ }
+
+ for (i = 0; i < nseg; i++) {
+ hwq->ucd_bus_addr[i] = seg[i].ds_addr;
+ }
+}
+
static int
ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
uint32_t num_entries, struct ufshci_controller *ctrlr)
@@ -55,7 +78,6 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
struct ufshci_hw_queue *hwq = &req_queue->hwq[UFSHCI_SDB_Q];
struct ufshci_tracker *tr;
size_t ucd_allocsz, payload_allocsz;
- uint64_t ucdmem_phys;
uint8_t *ucdmem;
int i, error;
@@ -71,10 +93,11 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
* Allocate physical memory for UTP Command Descriptor (UCD)
* Note: UFSHCI UCD format is restricted to 128-byte alignment.
*/
- error = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev), 128,
- ctrlr->page_size, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
- ucd_allocsz, howmany(ucd_allocsz, ctrlr->page_size),
- ctrlr->page_size, 0, NULL, NULL, &req_queue->dma_tag_ucd);
+ error = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev), 128, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, ucd_allocsz,
+ howmany(ucd_allocsz, sizeof(struct ufshci_utp_cmd_desc)),
+ sizeof(struct ufshci_utp_cmd_desc), 0, NULL, NULL,
+ &req_queue->dma_tag_ucd);
if (error != 0) {
ufshci_printf(ctrlr, "request cmd desc tag create failed %d\n",
error);
@@ -88,7 +111,7 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
}
if (bus_dmamap_load(req_queue->dma_tag_ucd, req_queue->ucdmem_map,
- ucdmem, ucd_allocsz, ufshci_single_map, &ucdmem_phys, 0) != 0) {
+ ucdmem, ucd_allocsz, ufshci_ucd_map, hwq, 0) != 0) {
ufshci_printf(ctrlr, "failed to load cmd desc memory\n");
bus_dmamem_free(req_queue->dma_tag_ucd, req_queue->ucd,
req_queue->ucdmem_map);
@@ -96,7 +119,6 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
}
req_queue->ucd = (struct ufshci_utp_cmd_desc *)ucdmem;
- req_queue->ucd_addr = ucdmem_phys;
/*
* Allocate physical memory for PRDT
@@ -128,10 +150,9 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
tr->slot_state = UFSHCI_SLOT_STATE_FREE;
tr->ucd = (struct ufshci_utp_cmd_desc *)ucdmem;
- tr->ucd_bus_addr = ucdmem_phys;
+ tr->ucd_bus_addr = hwq->ucd_bus_addr[i];
ucdmem += sizeof(struct ufshci_utp_cmd_desc);
- ucdmem_phys += sizeof(struct ufshci_utp_cmd_desc);
hwq->act_tr[i] = tr;
}
@@ -175,6 +196,11 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr,
req_queue->hwq = malloc(sizeof(struct ufshci_hw_queue), M_UFSHCI,
M_ZERO | M_NOWAIT);
hwq = &req_queue->hwq[UFSHCI_SDB_Q];
+ hwq->num_entries = req_queue->num_entries;
+ hwq->num_trackers = req_queue->num_trackers;
+ req_queue->hwq->ucd_bus_addr = malloc(sizeof(bus_addr_t) *
+ req_queue->num_trackers,
+ M_UFSHCI, M_ZERO | M_NOWAIT);
mtx_init(&hwq->qlock, "ufshci req_queue lock", NULL, MTX_DEF);
@@ -277,6 +303,7 @@ ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr,
if (mtx_initialized(&hwq->qlock))
mtx_destroy(&hwq->qlock);
+ free(req_queue->hwq->ucd_bus_addr, M_UFSHCI);
free(req_queue->hwq, M_UFSHCI);
}
diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c
index b50e33ea36ce..d5cfd228a429 100644
--- a/sys/dev/usb/controller/xhci_pci.c
+++ b/sys/dev/usb/controller/xhci_pci.c
@@ -99,6 +99,11 @@ xhci_pci_match(device_t self)
return ("AMD Starship USB 3.0 controller");
case 0x149c1022:
return ("AMD Matisse USB 3.0 controller");
+ case 0x15b61022:
+ case 0x15b71022:
+ return ("AMD Raphael/Granite Ridge USB 3.1 controller");
+ case 0x15b81022:
+ return ("AMD Raphael/Granite Ridge USB 2.0 controller");
case 0x15e01022:
case 0x15e11022:
return ("AMD Raven USB 3.1 controller");
@@ -109,6 +114,8 @@ xhci_pci_match(device_t self)
return ("AMD 300 Series USB 3.1 controller");
case 0x43d51022:
return ("AMD 400 Series USB 3.1 controller");
+ case 0x43f71022:
+ return ("AMD 600 Series USB 3.2 controller");
case 0x78121022:
case 0x78141022:
case 0x79141022:
diff --git a/sys/dev/vt/hw/vga/vt_vga.c b/sys/dev/vt/hw/vga/vt_vga.c
index 64039575c0ad..675c0573bd7e 100644
--- a/sys/dev/vt/hw/vga/vt_vga.c
+++ b/sys/dev/vt/hw/vga/vt_vga.c
@@ -1347,7 +1347,7 @@ vga_postswitch(struct vt_device *vd)
/* Reinit VGA mode, to restore view after app which change mode. */
vga_initialize(vd, (vd->vd_flags & VDF_TEXTMODE));
- /* Ask vt(9) to update chars on visible area. */
+ /* Ask vt(4) to update chars on visible area. */
vd->vd_flags |= VDF_INVALID;
}
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index b0f58b38a6f1..b51ef6766de4 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -125,10 +125,10 @@ static const struct terminal_class vt_termclass = {
(vw)->vw_number)
static SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
- "vt(9) parameters");
+ "vt(4) parameters");
static VT_SYSCTL_INT(enable_altgr, 1, "Enable AltGr key (Do not assume R.Alt as Alt)");
static VT_SYSCTL_INT(enable_bell, 0, "Enable bell");
-static VT_SYSCTL_INT(debug, 0, "vt(9) debug level");
+static VT_SYSCTL_INT(debug, 0, "vt(4) debug level");
static VT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode");
static VT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend");
diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c
index 676ea5de12b8..58a22b8bdc50 100644
--- a/sys/fs/fdescfs/fdesc_vnops.c
+++ b/sys/fs/fdescfs/fdesc_vnops.c
@@ -547,6 +547,8 @@ fdesc_readdir(struct vop_readdir_args *ap)
fmp = VFSTOFDESC(ap->a_vp->v_mount);
if (ap->a_ncookies != NULL)
*ap->a_ncookies = 0;
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 0;
off = (int)uio->uio_offset;
if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 ||
@@ -559,7 +561,12 @@ fdesc_readdir(struct vop_readdir_args *ap)
fcnt = i - 2; /* The first two nodes are `.' and `..' */
FILEDESC_SLOCK(fdp);
- while (i < fdp->fd_nfiles + 2 && uio->uio_resid >= UIO_MX) {
+ while (uio->uio_resid >= UIO_MX) {
+ if (i >= fdp->fd_nfiles + 2) {
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 1;
+ break;
+ }
bzero((caddr_t)dp, UIO_MX);
switch (i) {
case 0: /* `.' */
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index f3a9d80208b7..ae28617537fd 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -89,6 +89,8 @@
#include <sys/buf.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
+#define EXTERR_CATEGORY EXTERR_CAT_FUSE
+#include <sys/exterrvar.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
@@ -439,7 +441,8 @@ fuse_vnop_access(struct vop_access_args *ap)
if (vnode_isvroot(vp)) {
return 0;
}
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (!(data->dataflags & FSESS_INITED)) {
if (vnode_isvroot(vp)) {
@@ -448,7 +451,8 @@ fuse_vnop_access(struct vop_access_args *ap)
return 0;
}
}
- return EBADF;
+ return (EXTERROR(EBADF, "Access denied until FUSE session "
+ "is initialized"));
}
if (vnode_islnk(vp)) {
return 0;
@@ -489,7 +493,8 @@ fuse_vnop_advlock(struct vop_advlock_args *ap)
dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
switch(ap->a_op) {
@@ -506,7 +511,7 @@ fuse_vnop_advlock(struct vop_advlock_args *ap)
op = FUSE_SETLK;
break;
default:
- return EINVAL;
+ return (EXTERROR(EINVAL, "Unsupported lock flags"));
}
if (!(dataflags & FSESS_POSIX_LOCKS))
@@ -534,14 +539,14 @@ fuse_vnop_advlock(struct vop_advlock_args *ap)
size = vattr.va_size;
if (size > OFF_MAX ||
(fl->l_start > 0 && size > OFF_MAX - fl->l_start)) {
- err = EOVERFLOW;
+ err = EXTERROR(EOVERFLOW, "Offset is too large");
goto out;
}
start = size + fl->l_start;
break;
default:
- return (EINVAL);
+ return (EXTERROR(EINVAL, "Unsupported offset type"));
}
err = fuse_filehandle_get_anyflags(vp, &fufh, cred, pid);
@@ -603,7 +608,8 @@ fuse_vnop_allocate(struct vop_allocate_args *ap)
int err;
if (fuse_isdeadfs(vp))
- return (ENXIO);
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
switch (vp->v_type) {
case VFIFO:
@@ -619,7 +625,8 @@ fuse_vnop_allocate(struct vop_allocate_args *ap)
return (EROFS);
if (fsess_not_impl(mp, FUSE_FALLOCATE))
- return (EINVAL);
+ return (EXTERROR(EINVAL, "This server does not implement "
+ "FUSE_FALLOCATE"));
io.uio_offset = *offset;
io.uio_resid = *len;
@@ -649,13 +656,14 @@ fuse_vnop_allocate(struct vop_allocate_args *ap)
if (err == ENOSYS) {
fsess_set_notimpl(mp, FUSE_FALLOCATE);
- err = EINVAL;
+ err = EXTERROR(EINVAL, "This server does not implement "
+ "FUSE_ALLOCATE");
} else if (err == EOPNOTSUPP) {
/*
* The file system server does not support FUSE_FALLOCATE with
* the supplied mode for this particular file.
*/
- err = EINVAL;
+ err = EXTERROR(EINVAL, "This file can't be pre-allocated");
} else if (!err) {
*offset += *len;
*len = 0;
@@ -701,7 +709,8 @@ fuse_vnop_bmap(struct vop_bmap_args *ap)
int maxrun;
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
mp = vnode_mount(vp);
@@ -868,19 +877,21 @@ fuse_vnop_copy_file_range(struct vop_copy_file_range_args *ap)
pid_t pid;
int err;
- err = ENOSYS;
if (mp == NULL || mp != vnode_mount(outvp))
- goto fallback;
+ return (EXTERROR(ENOSYS, "Mount points do not match"));
if (incred->cr_uid != outcred->cr_uid)
- goto fallback;
+ return (EXTERROR(ENOSYS, "FUSE_COPY_FILE_RANGE does not "
+ "support different credentials for infd and outfd"));
if (incred->cr_groups[0] != outcred->cr_groups[0])
- goto fallback;
+ return (EXTERROR(ENOSYS, "FUSE_COPY_FILE_RANGE does not "
+ "support different credentials for infd and outfd"));
/* Caller busied mp, mnt_data can be safely accessed. */
if (fsess_not_impl(mp, FUSE_COPY_FILE_RANGE))
- goto fallback;
+ return (EXTERROR(ENOSYS, "This daemon does not "
+ "implement COPY_FILE_RANGE"));
if (ap->a_fsizetd == NULL)
td = curthread;
@@ -890,7 +901,7 @@ fuse_vnop_copy_file_range(struct vop_copy_file_range_args *ap)
vn_lock_pair(invp, false, LK_SHARED, outvp, false, LK_EXCLUSIVE);
if (invp->v_data == NULL || outvp->v_data == NULL) {
- err = EBADF;
+ err = EXTERROR(EBADF, "vnode got reclaimed");
goto unlock;
}
@@ -954,7 +965,6 @@ unlock:
if (err == ENOSYS)
fsess_set_notimpl(mp, FUSE_COPY_FILE_RANGE);
-fallback:
/*
* No need to call vn_rlimit_fsizex_res before return, since the uio is
@@ -1022,7 +1032,8 @@ fuse_vnop_create(struct vop_create_args *ap)
int flags;
if (fuse_isdeadfs(dvp))
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
/* FUSE expects sockets to be created with FUSE_MKNOD */
if (vap->va_type == VSOCK)
@@ -1038,7 +1049,7 @@ fuse_vnop_create(struct vop_create_args *ap)
bzero(&fdi, sizeof(fdi));
if (vap->va_type != VREG)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "Only regular files can be created"));
if (fsess_not_impl(mp, FUSE_CREATE) || vap->va_type == VSOCK) {
/* Fallback to FUSE_MKNOD/FUSE_OPEN */
@@ -1219,8 +1230,8 @@ fuse_vnop_getattr(struct vop_getattr_args *ap)
if (!(dataflags & FSESS_INITED)) {
if (!vnode_isvroot(vp)) {
fdata_set_dead(fuse_get_mpdata(vnode_mount(vp)));
- err = ENOTCONN;
- return err;
+ return (EXTERROR(ENOTCONN, "FUSE daemon is not "
+ "initialized"));
} else {
goto fake;
}
@@ -1349,10 +1360,11 @@ fuse_vnop_link(struct vop_link_args *ap)
int err;
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (vnode_mount(tdvp) != vnode_mount(vp)) {
- return EXDEV;
+ return (EXDEV);
}
/*
@@ -1362,7 +1374,7 @@ fuse_vnop_link(struct vop_link_args *ap)
* validating that nlink does not overflow.
*/
if (vap != NULL && vap->va_nlink >= FUSE_LINK_MAX)
- return EMLINK;
+ return (EMLINK);
fli.oldnodeid = VTOI(vp);
fdisp_init(&fdi, 0);
@@ -1374,12 +1386,13 @@ fuse_vnop_link(struct vop_link_args *ap)
feo = fdi.answ;
if (fli.oldnodeid != feo->nodeid) {
+ static const char exterr[] = "Server assigned wrong inode "
+ "for a hard link.";
struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
- fuse_warn(data, FSESS_WARN_ILLEGAL_INODE,
- "Assigned wrong inode for a hard link.");
+ fuse_warn(data, FSESS_WARN_ILLEGAL_INODE, exterr);
fuse_vnode_clear_attr_cache(vp);
fuse_vnode_clear_attr_cache(tdvp);
- err = EIO;
+ err = EXTERROR(EIO, exterr);
goto out;
}
@@ -1456,7 +1469,8 @@ fuse_vnop_lookup(struct vop_lookup_args *ap)
if (fuse_isdeadfs(dvp)) {
*vpp = NULL;
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (!vnode_isdir(dvp))
return ENOTDIR;
@@ -1476,7 +1490,8 @@ fuse_vnop_lookup(struct vop_lookup_args *ap)
* Since the file system doesn't support ".." lookups,
* we have no way to find this entry.
*/
- return ESTALE;
+ return (EXTERROR(ESTALE, "This server does not support "
+ "'..' lookups"));
}
nid = VTOFUD(dvp)->parent_nid;
if (nid == 0)
@@ -1599,11 +1614,11 @@ fuse_vnop_lookup(struct vop_lookup_args *ap)
vref(dvp);
*vpp = dvp;
} else {
+ static const char exterr[] = "Server assigned "
+ "same inode to both parent and child.";
fuse_warn(fuse_get_mpdata(mp),
- FSESS_WARN_ILLEGAL_INODE,
- "Assigned same inode to both parent and "
- "child.");
- err = EIO;
+ FSESS_WARN_ILLEGAL_INODE, exterr);
+ err = EXTERROR(EIO, exterr);
}
} else {
@@ -1691,7 +1706,8 @@ fuse_vnop_mkdir(struct vop_mkdir_args *ap)
struct fuse_mkdir_in fmdi;
if (fuse_isdeadfs(dvp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
fmdi.umask = curthread->td_proc->p_pd->pd_cmask;
@@ -1718,7 +1734,8 @@ fuse_vnop_mknod(struct vop_mknod_args *ap)
struct vattr *vap = ap->a_vap;
if (fuse_isdeadfs(dvp))
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
return fuse_internal_mknod(dvp, vpp, cnp, vap);
}
@@ -1742,11 +1759,13 @@ fuse_vnop_open(struct vop_open_args *ap)
pid_t pid = td->td_proc->p_pid;
if (fuse_isdeadfs(vp))
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO)
- return (EOPNOTSUPP);
+ return (EXTERROR(EOPNOTSUPP, "Unsupported vnode type",
+ vp->v_type));
if ((a_mode & (FREAD | FWRITE | FEXEC)) == 0)
- return EINVAL;
+ return (EXTERROR(EINVAL, "Illegal mode", a_mode));
if (fuse_filehandle_validrw(vp, a_mode, cred, pid)) {
fuse_vnode_open(vp, 0, td);
@@ -1828,7 +1847,8 @@ fuse_vnop_pathconf(struct vop_pathconf_args *ap)
return (0);
} else if (fsess_not_impl(mp, FUSE_LSEEK)) {
/* FUSE_LSEEK is not implemented */
- return (EINVAL);
+ return (EXTERROR(EINVAL, "This server does not "
+ "implement FUSE_LSEEK"));
} else {
return (err);
}
@@ -1862,7 +1882,8 @@ fuse_vnop_read(struct vop_read_args *ap)
MPASS(vp->v_type == VREG || vp->v_type == VDIR);
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (VTOFUD(vp)->flag & FN_DIRECTIO) {
@@ -1939,10 +1960,11 @@ fuse_vnop_readdir(struct vop_readdir_args *ap)
if (ap->a_eofflag)
*ap->a_eofflag = 0;
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (uio_resid(uio) < sizeof(struct dirent))
- return EINVAL;
+ return (EXTERROR(EINVAL, "Buffer is too small"));
tresid = uio->uio_resid;
err = fuse_filehandle_get_dir(vp, &fufh, cred, pid);
@@ -2012,7 +2034,8 @@ fuse_vnop_readlink(struct vop_readlink_args *ap)
int err;
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (!vnode_islnk(vp)) {
return EINVAL;
@@ -2023,10 +2046,11 @@ fuse_vnop_readlink(struct vop_readlink_args *ap)
goto out;
}
if (strnlen(fdi.answ, fdi.iosize) + 1 < fdi.iosize) {
+ static const char exterr[] = "Server returned an embedded NUL "
+ "from FUSE_READLINK.";
struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
- fuse_warn(data, FSESS_WARN_READLINK_EMBEDDED_NUL,
- "Returned an embedded NUL from FUSE_READLINK.");
- err = EIO;
+ fuse_warn(data, FSESS_WARN_READLINK_EMBEDDED_NUL, exterr);
+ err = EXTERROR(EIO, exterr);
goto out;
}
if (((char *)fdi.answ)[0] == '/' &&
@@ -2110,10 +2134,11 @@ fuse_vnop_remove(struct vop_remove_args *ap)
int err;
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (vnode_isdir(vp)) {
- return EPERM;
+ return (EXTERROR(EPERM, "vnode is a directory"));
}
err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK);
@@ -2146,12 +2171,13 @@ fuse_vnop_rename(struct vop_rename_args *ap)
int err = 0;
if (fuse_isdeadfs(fdvp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (fvp->v_mount != tdvp->v_mount ||
(tvp && fvp->v_mount != tvp->v_mount)) {
SDT_PROBE2(fusefs, , vnops, trace, 1, "cross-device rename");
- err = EXDEV;
+ err = EXTERROR(EXDEV, "Cross-device rename");
goto out;
}
cache_purge(fvp);
@@ -2222,10 +2248,12 @@ fuse_vnop_rmdir(struct vop_rmdir_args *ap)
int err;
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (VTOFUD(vp) == VTOFUD(dvp)) {
- return EINVAL;
+ return (EXTERROR(EINVAL, "Directory to be removed "
+ "contains itself"));
}
err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR);
@@ -2262,7 +2290,8 @@ fuse_vnop_setattr(struct vop_setattr_args *ap)
checkperm = dataflags & FSESS_DEFAULT_PERMISSIONS;
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (vap->va_uid != (uid_t)VNOVAL) {
@@ -2427,7 +2456,8 @@ fuse_vnop_symlink(struct vop_symlink_args *ap)
size_t len;
if (fuse_isdeadfs(dvp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
/*
* Unlike the other creator type calls, here we have to create a message
@@ -2473,7 +2503,8 @@ fuse_vnop_write(struct vop_write_args *ap)
MPASS(vp->v_type == VREG || vp->v_type == VDIR);
if (fuse_isdeadfs(vp)) {
- return ENXIO;
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
}
if (VTOFUD(vp)->flag & FN_DIRECTIO) {
@@ -2626,10 +2657,12 @@ fuse_vnop_getextattr(struct vop_getextattr_args *ap)
int err;
if (fuse_isdeadfs(vp))
- return (ENXIO);
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
if (fsess_not_impl(mp, FUSE_GETXATTR))
- return EOPNOTSUPP;
+ return (EXTERROR(EOPNOTSUPP, "This server does not implement "
+ "extended attributes"));
err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
if (err)
@@ -2667,7 +2700,8 @@ fuse_vnop_getextattr(struct vop_getextattr_args *ap)
if (err != 0) {
if (err == ENOSYS) {
fsess_set_notimpl(mp, FUSE_GETXATTR);
- err = EOPNOTSUPP;
+ err = (EXTERROR(EOPNOTSUPP, "This server does not "
+ "implement extended attributes"));
}
goto out;
}
@@ -2713,10 +2747,12 @@ fuse_vnop_setextattr(struct vop_setextattr_args *ap)
int err;
if (fuse_isdeadfs(vp))
- return (ENXIO);
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
if (fsess_not_impl(mp, FUSE_SETXATTR))
- return EOPNOTSUPP;
+ return (EXTERROR(EOPNOTSUPP, "This server does not implement "
+ "setting extended attributes"));
if (vfs_isrdonly(mp))
return EROFS;
@@ -2728,9 +2764,11 @@ fuse_vnop_setextattr(struct vop_setextattr_args *ap)
* return EOPNOTSUPP.
*/
if (fsess_not_impl(mp, FUSE_REMOVEXATTR))
- return (EOPNOTSUPP);
+ return (EXTERROR(EOPNOTSUPP, "This server does not "
+ "implement removing extended attributess"));
else
- return (EINVAL);
+ return (EXTERROR(EINVAL, "DELETEEXTATTR should be used "
+ "to remove extattrs"));
}
err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td,
@@ -2776,7 +2814,8 @@ fuse_vnop_setextattr(struct vop_setextattr_args *ap)
if (err == ENOSYS) {
fsess_set_notimpl(mp, FUSE_SETXATTR);
- err = EOPNOTSUPP;
+ err = EXTERROR(EOPNOTSUPP, "This server does not implement "
+ "setting extended attributes");
}
if (err == ERESTART) {
/* Can't restart after calling uiomove */
@@ -2887,10 +2926,12 @@ fuse_vnop_listextattr(struct vop_listextattr_args *ap)
int err;
if (fuse_isdeadfs(vp))
- return (ENXIO);
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
if (fsess_not_impl(mp, FUSE_LISTXATTR))
- return EOPNOTSUPP;
+ return (EXTERROR(EOPNOTSUPP, "This server does not implement "
+ "extended attributes"));
err = fuse_extattr_check_cred(vp, ap->a_attrnamespace, cred, td, VREAD);
if (err)
@@ -2918,7 +2959,8 @@ fuse_vnop_listextattr(struct vop_listextattr_args *ap)
if (err != 0) {
if (err == ENOSYS) {
fsess_set_notimpl(mp, FUSE_LISTXATTR);
- err = EOPNOTSUPP;
+ err = EXTERROR(EOPNOTSUPP, "This server does not "
+ "implement extended attributes");
}
goto out;
}
@@ -3018,7 +3060,8 @@ fuse_vnop_deallocate(struct vop_deallocate_args *ap)
bool closefufh = false;
if (fuse_isdeadfs(vp))
- return (ENXIO);
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
if (vfs_isrdonly(mp))
return (EROFS);
@@ -3124,10 +3167,12 @@ fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
int err;
if (fuse_isdeadfs(vp))
- return (ENXIO);
+ return (EXTERROR(ENXIO, "This FUSE session is about "
+ "to be closed"));
if (fsess_not_impl(mp, FUSE_REMOVEXATTR))
- return EOPNOTSUPP;
+ return (EXTERROR(EOPNOTSUPP, "This server does not implement "
+ "removing extended attributes"));
if (vfs_isrdonly(mp))
return EROFS;
@@ -3156,7 +3201,8 @@ fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
err = fdisp_wait_answ(&fdi);
if (err == ENOSYS) {
fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
- err = EOPNOTSUPP;
+ err = EXTERROR(EOPNOTSUPP, "This server does not implement "
+ "removing extended attributes");
}
fdisp_destroy(&fdi);
@@ -3210,7 +3256,8 @@ fuse_vnop_vptofh(struct vop_vptofh_args *ap)
/* NFS requires lookups for "." and ".." */
SDT_PROBE2(fusefs, , vnops, trace, 1,
"VOP_VPTOFH without FUSE_EXPORT_SUPPORT");
- return EOPNOTSUPP;
+ return (EXTERROR(EOPNOTSUPP, "This server is "
+ "missing FUSE_EXPORT_SUPPORT"));
}
if ((mp->mnt_flag & MNT_EXPORTED) &&
fsess_is_impl(mp, FUSE_OPENDIR))
@@ -3228,7 +3275,8 @@ fuse_vnop_vptofh(struct vop_vptofh_args *ap)
*/
SDT_PROBE2(fusefs, , vnops, trace, 1,
"VOP_VPTOFH with FUSE_OPENDIR");
- return EOPNOTSUPP;
+ return (EXTERROR(EOPNOTSUPP, "This server implements "
+ "FUSE_OPENDIR so is not compatible with getfh"));
}
err = fuse_internal_getattr(vp, &va, curthread->td_ucred, curthread);
@@ -3242,6 +3290,7 @@ fuse_vnop_vptofh(struct vop_vptofh_args *ap)
if (fvdat->generation <= UINT32_MAX)
fhp->gen = fvdat->generation;
else
- return EOVERFLOW;
+ return (EXTERROR(EOVERFLOW, "inode generation "
+ "number overflow"));
return (0);
}
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c
index da4848169173..208b64930e61 100644
--- a/sys/fs/msdosfs/msdosfs_conv.c
+++ b/sys/fs/msdosfs/msdosfs_conv.c
@@ -797,19 +797,24 @@ mbsadjpos(const char **instr, size_t inlen, size_t outlen, int weight, int flag,
static u_char *
dos2unixchr(u_char *outbuf, const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp)
{
- u_char c, *outp;
- size_t len, olen;
+ u_char c, *outp, *outp1;
+ size_t i, len, olen;
outp = outbuf;
if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
olen = len = 4;
+ outp1 = outp;
if (lower & (LCASE_BASE | LCASE_EXT))
msdosfs_iconv->convchr_case(pmp->pm_d2u, (const char **)instr,
ilen, (char **)&outp, &olen, KICONV_LOWER);
else
msdosfs_iconv->convchr(pmp->pm_d2u, (const char **)instr,
ilen, (char **)&outp, &olen);
+ for (i = 0; i < outp - outp1; i++) {
+ if (outp1[i] == '/')
+ outp1[i] = '?';
+ }
len -= olen;
/*
@@ -826,6 +831,8 @@ dos2unixchr(u_char *outbuf, const u_char **instr, size_t *ilen, int lower, struc
c = dos2unix[c];
if (lower & (LCASE_BASE | LCASE_EXT))
c = u2l[c];
+ if (c == '/')
+ c = '?';
*outp++ = c;
outbuf[1] = '\0';
}
diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c
index e799a5ce05f6..8ab6d35a2685 100644
--- a/sys/fs/msdosfs/msdosfs_lookup.c
+++ b/sys/fs/msdosfs/msdosfs_lookup.c
@@ -845,7 +845,6 @@ doscheckpath(struct denode *source, struct denode *target, daddr_t *wait_scn)
*wait_scn = 0;
pmp = target->de_pmp;
- lockmgr_assert(&pmp->pm_checkpath_lock, KA_XLOCKED);
KASSERT(pmp == source->de_pmp,
("doscheckpath: source and target on different filesystems"));
diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
index adcffe45df82..4431d36c8a8e 100644
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -575,7 +575,6 @@ mountmsdosfs(struct vnode *odevvp, struct mount *mp)
pmp->pm_bo = bo;
lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0);
- lockinit(&pmp->pm_checkpath_lock, 0, "msdoscp", 0, 0);
TASK_INIT(&pmp->pm_rw2ro_task, 0, msdosfs_remount_ro, pmp);
@@ -871,7 +870,6 @@ error_exit:
}
if (pmp != NULL) {
lockdestroy(&pmp->pm_fatlock);
- lockdestroy(&pmp->pm_checkpath_lock);
free(pmp->pm_inusemap, M_MSDOSFSFAT);
free(pmp, M_MSDOSFSMNT);
mp->mnt_data = NULL;
@@ -971,7 +969,6 @@ msdosfs_unmount(struct mount *mp, int mntflags)
dev_rel(pmp->pm_dev);
free(pmp->pm_inusemap, M_MSDOSFSFAT);
lockdestroy(&pmp->pm_fatlock);
- lockdestroy(&pmp->pm_checkpath_lock);
free(pmp, M_MSDOSFSMNT);
mp->mnt_data = NULL;
return (error);
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
index 6417b7dac16b..33e0d94954d7 100644
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -945,7 +945,7 @@ msdosfs_rename(struct vop_rename_args *ap)
struct denode *fdip, *fip, *tdip, *tip, *nip;
u_char toname[12], oldname[11];
u_long to_diroffset;
- bool checkpath_locked, doingdirectory, newparent;
+ bool doingdirectory, newparent;
int error;
u_long cn, pcl, blkoff;
daddr_t bn, wait_scn, scn;
@@ -986,8 +986,6 @@ msdosfs_rename(struct vop_rename_args *ap)
if (tvp != NULL && tvp != tdvp)
VOP_UNLOCK(tvp);
- checkpath_locked = false;
-
relock:
doingdirectory = newparent = false;
@@ -1108,12 +1106,8 @@ relock:
if (doingdirectory && newparent) {
if (error != 0) /* write access check above */
goto unlock;
- lockmgr(&pmp->pm_checkpath_lock, LK_EXCLUSIVE, NULL);
- checkpath_locked = true;
error = doscheckpath(fip, tdip, &wait_scn);
if (wait_scn != 0) {
- lockmgr(&pmp->pm_checkpath_lock, LK_RELEASE, NULL);
- checkpath_locked = false;
VOP_UNLOCK(fdvp);
VOP_UNLOCK(tdvp);
VOP_UNLOCK(fvp);
@@ -1276,8 +1270,6 @@ relock:
cache_purge(fvp);
unlock:
- if (checkpath_locked)
- lockmgr(&pmp->pm_checkpath_lock, LK_RELEASE, NULL);
vput(fdvp);
vput(fvp);
if (tvp != NULL) {
@@ -1289,7 +1281,6 @@ unlock:
vput(tdvp);
return (error);
releout:
- MPASS(!checkpath_locked);
vrele(tdvp);
if (tvp != NULL)
vrele(tvp);
@@ -1530,6 +1521,9 @@ msdosfs_readdir(struct vop_readdir_args *ap)
ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
#endif
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 0;
+
/*
* msdosfs_readdir() won't operate properly on regular files since
* it does i/o only with the filesystem vnode, and hence can
@@ -1623,8 +1617,11 @@ msdosfs_readdir(struct vop_readdir_args *ap)
on = (offset - bias) & pmp->pm_crbomask;
n = min(pmp->pm_bpcluster - on, uio->uio_resid);
diff = dep->de_FileSize - (offset - bias);
- if (diff <= 0)
- break;
+ if (diff <= 0) {
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 1;
+ goto out;
+ }
n = min(n, diff);
error = pcbmap(dep, lbn, &bn, &cn, &blsize);
if (error)
@@ -1655,6 +1652,8 @@ msdosfs_readdir(struct vop_readdir_args *ap)
*/
if (dentp->deName[0] == SLOT_EMPTY) {
brelse(bp);
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 1;
goto out;
}
/*
@@ -1752,15 +1751,6 @@ out:
uio->uio_offset = off;
- /*
- * Set the eofflag (NFS uses it)
- */
- if (ap->a_eofflag) {
- if (dep->de_FileSize - (offset - bias) <= 0)
- *ap->a_eofflag = 1;
- else
- *ap->a_eofflag = 0;
- }
return (error);
}
@@ -1951,6 +1941,9 @@ msdosfs_pathconf(struct vop_pathconf_args *ap)
case _PC_NO_TRUNC:
*ap->a_retval = 0;
return (0);
+ case _PC_HAS_HIDDENSYSTEM:
+ *ap->a_retval = 1;
+ return (0);
default:
return (vop_stdpathconf(ap));
}
diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h
index fcaac544a74d..04e6b75bea2a 100644
--- a/sys/fs/msdosfs/msdosfsmount.h
+++ b/sys/fs/msdosfs/msdosfsmount.h
@@ -118,7 +118,6 @@ struct msdosfsmount {
void *pm_u2d; /* Unicode->DOS iconv handle */
void *pm_d2u; /* DOS->Local iconv handle */
struct lock pm_fatlock; /* lockmgr protecting allocations */
- struct lock pm_checkpath_lock; /* protects doscheckpath result */
struct task pm_rw2ro_task; /* context for emergency remount ro */
};
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index f46b0d282861..a957315aaa12 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -630,6 +630,10 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
+ if ((flags & NFSSATTR_FULL) && vap->va_flags != VNOVAL) {
+ NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
+ NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
+ }
if (vap->va_atime.tv_sec != VNOVAL)
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
if (vap->va_mtime.tv_sec != VNOVAL)
@@ -643,7 +647,8 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
NFSATTRBIT_TIMECREATE))
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE);
(void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
- &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
+ &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL,
+ false, false, false);
break;
}
}
@@ -1314,6 +1319,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
u_int32_t freenum = 0, tuint;
u_int64_t uquad = 0, thyp, thyp2;
uint16_t tui16;
+ long has_pathconf;
#ifdef QUOTA
struct dqblk dqb;
uid_t savuid;
@@ -1421,6 +1427,16 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
}
+ /* Some filesystems do not support uf_hidden */
+ if (vp == NULL || VOP_PATHCONF(vp,
+ _PC_HAS_HIDDENSYSTEM, &has_pathconf) != 0)
+ has_pathconf = 0;
+ if (has_pathconf == 0) {
+ NFSCLRBIT_ATTRBIT(&checkattrbits,
+ NFSATTRBIT_HIDDEN);
+ NFSCLRBIT_ATTRBIT(&checkattrbits,
+ NFSATTRBIT_SYSTEM);
+ }
if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
|| retnotsup)
*retcmpp = NFSERR_NOTSAME;
@@ -1521,15 +1537,13 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
if (compare) {
if (!(*retcmpp)) {
- long has_named_attr;
-
if (vp == NULL || VOP_PATHCONF(vp,
- _PC_HAS_NAMEDATTR, &has_named_attr)
+ _PC_HAS_NAMEDATTR, &has_pathconf)
!= 0)
- has_named_attr = 0;
- if ((has_named_attr != 0 &&
+ has_pathconf = 0;
+ if ((has_pathconf != 0 &&
*tl != newnfs_true) ||
- (has_named_attr == 0 &&
+ (has_pathconf == 0 &&
*tl != newnfs_false))
*retcmpp = NFSERR_NOTSAME;
}
@@ -1792,9 +1806,17 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
free(cp2, M_NFSSTRING);
break;
case NFSATTRBIT_HIDDEN:
- NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
- if (compare && !(*retcmpp))
- *retcmpp = NFSERR_ATTRNOTSUPP;
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp) && ((*tl == newnfs_true &&
+ (nap->na_flags & UF_HIDDEN) == 0) ||
+ (*tl == newnfs_false &&
+ (nap->na_flags & UF_HIDDEN) != 0)))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (nap != NULL) {
+ if (*tl == newnfs_true)
+ nap->na_flags |= UF_HIDDEN;
+ }
attrsum += NFSX_UNSIGNED;
break;
case NFSATTRBIT_HOMOGENEOUS:
@@ -2166,9 +2188,17 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
attrsum += NFSX_HYPER;
break;
case NFSATTRBIT_SYSTEM:
- NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
- if (compare && !(*retcmpp))
- *retcmpp = NFSERR_ATTRNOTSUPP;
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp) && ((*tl == newnfs_true &&
+ (nap->na_flags & UF_SYSTEM) == 0) ||
+ (*tl == newnfs_false &&
+ (nap->na_flags & UF_SYSTEM) != 0)))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (nap != NULL) {
+ if (*tl == newnfs_true)
+ nap->na_flags |= UF_SYSTEM;
+ }
attrsum += NFSX_UNSIGNED;
break;
case NFSATTRBIT_TIMEACCESS:
@@ -2617,7 +2647,8 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
- struct statfs *pnfssf)
+ struct statfs *pnfssf, bool xattrsupp, bool has_hiddensystem,
+ bool has_namedattr)
{
int bitpos, retnum = 0;
u_int32_t *tl;
@@ -2631,10 +2662,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
struct nfsfsinfo fsinf;
struct timespec temptime;
NFSACL_T *aclp, *naclp = NULL;
- size_t atsiz;
- bool xattrsupp;
short irflag;
- long has_named_attr;
#ifdef QUOTA
struct dqblk dqb;
uid_t savuid;
@@ -2718,18 +2746,6 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
}
}
- /* Check to see if Extended Attributes are supported. */
- xattrsupp = false;
- if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
- if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
- error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
- "xxx", NULL, &atsiz, cred, p);
- NFSVOPUNLOCK(vp);
- if (error != EOPNOTSUPP)
- xattrsupp = true;
- }
- }
-
/*
* Put out the attribute bitmap for the ones being filled in
* and get the field for the number of attributes returned.
@@ -2751,6 +2767,10 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
}
+ if (!has_hiddensystem) {
+ NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
+ NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
+ }
retnum += nfsrv_putattrbit(nd, &attrbits);
break;
case NFSATTRBIT_TYPE:
@@ -2791,10 +2811,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
break;
case NFSATTRBIT_NAMEDATTR:
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
- if (VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR, &has_named_attr)
- != 0)
- has_named_attr = 0;
- if (has_named_attr != 0)
+ if (has_namedattr)
*tl = newnfs_true;
else
*tl = newnfs_false;
@@ -2899,6 +2916,14 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
*tl = 0;
retnum += 2 * NFSX_UNSIGNED;
break;
+ case NFSATTRBIT_HIDDEN:
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ if ((vap->va_flags & UF_HIDDEN) != 0)
+ *tl = newnfs_true;
+ else
+ *tl = newnfs_false;
+ retnum += NFSX_UNSIGNED;
+ break;
case NFSATTRBIT_HOMOGENEOUS:
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
@@ -3088,6 +3113,14 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
txdr_hyper(vap->va_bytes, tl);
retnum += NFSX_HYPER;
break;
+ case NFSATTRBIT_SYSTEM:
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ if ((vap->va_flags & UF_SYSTEM) != 0)
+ *tl = newnfs_true;
+ else
+ *tl = newnfs_false;
+ retnum += NFSX_UNSIGNED;
+ break;
case NFSATTRBIT_TIMEACCESS:
NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
txdr_nfsv4time(&vap->va_atime, tl);
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index 3b6c1ec90c06..54f60a753c50 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -395,8 +395,9 @@ int nfsrv_putopbit(struct nfsrv_descript *, nfsopbit_t *);
void nfsrv_wcc(struct nfsrv_descript *, int, struct nfsvattr *, int,
struct nfsvattr *);
int nfsv4_fillattr(struct nfsrv_descript *, struct mount *, vnode_t, NFSACL_T *,
- struct vattr *, fhandle_t *, int, nfsattrbit_t *,
- struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t, struct statfs *);
+ struct vattr *, fhandle_t *, int, nfsattrbit_t *, struct ucred *,
+ NFSPROC_T *, int, int, int, int, uint64_t, struct statfs *, bool, bool,
+ bool);
void nfsrv_fillattr(struct nfsrv_descript *, struct nfsvattr *);
struct mbuf *nfsrv_adj(struct mbuf *, int, int);
void nfsrv_postopattr(struct nfsrv_descript *, int, struct nfsvattr *);
@@ -735,7 +736,8 @@ int nfsvno_updfilerev(vnode_t, struct nfsvattr *, struct nfsrv_descript *,
NFSPROC_T *);
int nfsvno_fillattr(struct nfsrv_descript *, struct mount *, vnode_t,
struct nfsvattr *, fhandle_t *, int, nfsattrbit_t *,
- struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t);
+ struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t, bool, bool,
+ bool);
int nfsrv_sattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, nfsattrbit_t *,
NFSACL_T *, NFSPROC_T *);
int nfsv4_sattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, nfsattrbit_t *,
diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h
index eff53e1a384e..cb5a80e8df73 100644
--- a/sys/fs/nfs/nfsproto.h
+++ b/sys/fs/nfs/nfsproto.h
@@ -1142,6 +1142,7 @@ struct nfsv3_sattr {
NFSATTRBM_FILESFREE | \
NFSATTRBM_FILESTOTAL | \
NFSATTRBM_FSLOCATIONS | \
+ NFSATTRBM_HIDDEN | \
NFSATTRBM_HOMOGENEOUS | \
NFSATTRBM_MAXFILESIZE | \
NFSATTRBM_MAXLINK | \
@@ -1163,6 +1164,7 @@ struct nfsv3_sattr {
NFSATTRBM_SPACEFREE | \
NFSATTRBM_SPACETOTAL | \
NFSATTRBM_SPACEUSED | \
+ NFSATTRBM_SYSTEM | \
NFSATTRBM_TIMEACCESS | \
NFSATTRBM_TIMECREATE | \
NFSATTRBM_TIMEDELTA | \
@@ -1210,11 +1212,13 @@ struct nfsv3_sattr {
*/
#define NFSATTRBIT_SETABLE0 \
(NFSATTRBM_SIZE | \
+ NFSATTRBM_HIDDEN | \
NFSATTRBM_ACL)
#define NFSATTRBIT_SETABLE1 \
(NFSATTRBM_MODE | \
NFSATTRBM_OWNER | \
NFSATTRBM_OWNERGROUP | \
+ NFSATTRBM_SYSTEM | \
NFSATTRBM_TIMECREATE | \
NFSATTRBM_TIMEACCESSSET | \
NFSATTRBM_TIMEMODIFYSET)
@@ -1254,6 +1258,7 @@ struct nfsv3_sattr {
NFSATTRBM_SIZE | \
NFSATTRBM_FSID | \
NFSATTRBM_FILEID | \
+ NFSATTRBM_HIDDEN | \
NFSATTRBM_MAXREAD)
/*
@@ -1266,6 +1271,7 @@ struct nfsv3_sattr {
NFSATTRBM_OWNERGROUP | \
NFSATTRBM_RAWDEV | \
NFSATTRBM_SPACEUSED | \
+ NFSATTRBM_SYSTEM | \
NFSATTRBM_TIMEACCESS | \
NFSATTRBM_TIMECREATE | \
NFSATTRBM_TIMEMETADATA | \
@@ -1288,6 +1294,7 @@ struct nfsv3_sattr {
NFSATTRBM_SIZE | \
NFSATTRBM_FSID | \
NFSATTRBM_FILEID | \
+ NFSATTRBM_HIDDEN | \
NFSATTRBM_MAXREAD)
/*
@@ -1298,6 +1305,7 @@ struct nfsv3_sattr {
NFSATTRBM_NUMLINKS | \
NFSATTRBM_RAWDEV | \
NFSATTRBM_SPACEUSED | \
+ NFSATTRBM_SYSTEM | \
NFSATTRBM_TIMEACCESS | \
NFSATTRBM_TIMECREATE | \
NFSATTRBM_TIMEMETADATA | \
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index c07da6f9275f..2f3c59b68518 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -4158,6 +4158,13 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
NFSATTRBIT_TIMECREATE))
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE);
+ if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
+ NFSATTRBIT_HIDDEN) ||
+ !NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
+ NFSATTRBIT_SYSTEM)) {
+ NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
+ NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
+ }
}
/*
@@ -5429,7 +5436,8 @@ nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
NFSZERO_ATTRBIT(&attrbits);
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
(void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0,
- &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
+ &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL, false, false,
+ false);
error = nfscl_request(nd, vp, p, cred);
if (error)
return (error);
diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index 1ae5ed1a75ca..99a781640c53 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -3701,7 +3701,7 @@ nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p)
if (!error)
(void) nfsv4_fillattr(nd, NULL, NULL, NULL, &va,
NULL, 0, &rattrbits, NULL, p, 0, 0, 0, 0,
- (uint64_t)0, NULL);
+ (uint64_t)0, NULL, false, false, false);
break;
case NFSV4OP_CBRECALL:
NFSCL_DEBUG(4, "cbrecall\n");
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 0049d7edca33..fa451887e73e 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -1074,21 +1074,29 @@ nfs_setattr(struct vop_setattr_args *ap)
int error = 0;
u_quad_t tsize;
struct timespec ts;
+ struct nfsmount *nmp;
#ifndef nolint
tsize = (u_quad_t)0;
#endif
/*
- * Setting of flags and marking of atimes are not supported.
+ * Only setting of UF_HIDDEN and UF_SYSTEM are supported and
+ * only for NFSv4 servers that support them.
*/
- if (vap->va_flags != VNOVAL)
+ nmp = VFSTONFS(vp->v_mount);
+ if (vap->va_flags != VNOVAL && (!NFSHASNFSV4(nmp) ||
+ (vap->va_flags & ~(UF_HIDDEN | UF_SYSTEM)) != 0 ||
+ ((vap->va_flags & UF_HIDDEN) != 0 &&
+ !NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_HIDDEN)) ||
+ ((vap->va_flags & UF_SYSTEM) != 0 &&
+ !NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_SYSTEM))))
return (EOPNOTSUPP);
/*
* Disallow write attempts if the filesystem is mounted read-only.
*/
- if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
+ if ((vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
vap->va_mtime.tv_sec != VNOVAL ||
vap->va_birthtime.tv_sec != VNOVAL ||
@@ -4754,6 +4762,15 @@ nfs_pathconf(struct vop_pathconf_args *ap)
else
*ap->a_retval = 0;
break;
+ case _PC_HAS_HIDDENSYSTEM:
+ if (NFS_ISV4(vp) && NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
+ NFSATTRBIT_HIDDEN) &&
+ NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
+ NFSATTRBIT_SYSTEM))
+ *ap->a_retval = 1;
+ else
+ *ap->a_retval = 0;
+ break;
default:
error = vop_stdpathconf(ap);
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 3bf54d82b959..4f0d5946d6b9 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -449,6 +449,7 @@ nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap,
}
nvap->na_bsdflags = 0;
+ nvap->na_flags = 0;
error = VOP_GETATTR(vp, &nvap->na_vattr, nd->nd_cred);
if (lockedit != 0)
NFSVOPUNLOCK(vp);
@@ -1651,10 +1652,11 @@ nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp,
}
if (fvp == tvp) {
/*
- * If source and destination are the same, there is nothing to
- * do. Set error to -1 to indicate this.
+ * If source and destination are the same, there is
+ * nothing to do. Set error to EJUSTRETURN to indicate
+ * this.
*/
- error = -1;
+ error = EJUSTRETURN;
goto out;
}
if (nd->nd_flag & ND_NFSV4) {
@@ -1696,10 +1698,26 @@ nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp,
" dsdvp=%p\n", dsdvp[0]);
}
out:
- if (!error) {
+ mp = NULL;
+ if (error == 0) {
+ error = VOP_GETWRITEMOUNT(tondp->ni_dvp, &mp);
+ if (error == 0) {
+ if (mp == NULL) {
+ error = ENOENT;
+ } else {
+ error = lockmgr(&mp->mnt_renamelock,
+ LK_EXCLUSIVE | LK_NOWAIT, NULL);
+ if (error != 0)
+ error = ERELOOKUP;
+ }
+ }
+ }
+ if (error == 0) {
error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp,
&fromndp->ni_cnd, tondp->ni_dvp, tondp->ni_vp,
&tondp->ni_cnd);
+ lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0);
+ vfs_rel(mp);
} else {
if (tdvp == tvp)
vrele(tdvp);
@@ -1709,8 +1727,13 @@ out:
vput(tvp);
vrele(fromndp->ni_dvp);
vrele(fvp);
- if (error == -1)
+ if (error == EJUSTRETURN) {
error = 0;
+ } else if (error == ERELOOKUP && mp != NULL) {
+ lockmgr(&mp->mnt_renamelock, LK_EXCLUSIVE, 0);
+ lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0);
+ vfs_rel(mp);
+ }
}
/*
@@ -2089,7 +2112,8 @@ int
nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
struct nfsvattr *nvap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
struct ucred *cred, struct thread *p, int isdgram, int reterr,
- int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
+ int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
+ bool xattrsupp, bool has_hiddensystem, bool has_namedattr)
{
struct statfs *sf;
int error;
@@ -2108,7 +2132,7 @@ nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
}
error = nfsv4_fillattr(nd, mp, vp, NULL, &nvap->na_vattr, fhp, rderror,
attrbitp, cred, p, isdgram, reterr, supports_nfsv4acls, at_root,
- mounted_on_fileno, sf);
+ mounted_on_fileno, sf, xattrsupp, has_hiddensystem, has_namedattr);
free(sf, M_TEMP);
NFSEXITCODE2(0, nd);
return (error);
@@ -2425,7 +2449,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
struct nfsvattr nva, at, *nvap = &nva;
struct mbuf *mb0, *mb1;
struct nfsreferral *refp;
- int nlen, r, error = 0, getret = 1, usevget = 1;
+ int nlen, r, error = 0, getret = 1, ret, usevget = 1;
int siz, cnt, fullsiz, eofflag, ncookies, entrycnt;
caddr_t bpos0, bpos1;
u_int64_t off, toff, verf __unused;
@@ -2439,6 +2463,9 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
uint64_t mounted_on_fileno;
struct thread *p = curthread;
int bextpg0, bextpg1, bextpgsiz0, bextpgsiz1;
+ size_t atsiz;
+ long pathval;
+ bool has_hiddensystem, has_namedattr, xattrsupp;
if (nd->nd_repstat) {
nfsrv_postopattr(nd, getret, &at);
@@ -2913,9 +2940,32 @@ again:
*tl++ = newnfs_true;
txdr_hyper(*cookiep, tl);
dirlen += nfsm_strtom(nd, dp->d_name, nlen);
+ xattrsupp = false;
+ has_hiddensystem = false;
+ has_namedattr = false;
if (nvp != NULL) {
supports_nfsv4acls =
nfs_supportsnfsv4acls(nvp);
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_XATTRSUPPORT)) {
+ ret = VOP_GETEXTATTR(nvp,
+ EXTATTR_NAMESPACE_USER,
+ "xxx", NULL, &atsiz,
+ nd->nd_cred, p);
+ xattrsupp = ret != EOPNOTSUPP;
+ }
+ if (VOP_PATHCONF(nvp,
+ _PC_HAS_HIDDENSYSTEM, &pathval) !=
+ 0)
+ pathval = 0;
+ has_hiddensystem = pathval > 0;
+ pathval = 0;
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_NAMEDATTR) &&
+ VOP_PATHCONF(nvp, _PC_HAS_NAMEDATTR,
+ &pathval) != 0)
+ pathval = 0;
+ has_namedattr = pathval > 0;
NFSVOPUNLOCK(nvp);
} else
supports_nfsv4acls = 0;
@@ -2935,13 +2985,15 @@ again:
nvp, nvap, &nfh, r, &rderrbits,
nd->nd_cred, p, isdgram, 0,
supports_nfsv4acls, at_root,
- mounted_on_fileno);
+ mounted_on_fileno, xattrsupp,
+ has_hiddensystem, has_namedattr);
} else {
dirlen += nfsvno_fillattr(nd, new_mp,
nvp, nvap, &nfh, r, &attrbits,
nd->nd_cred, p, isdgram, 0,
supports_nfsv4acls, at_root,
- mounted_on_fileno);
+ mounted_on_fileno, xattrsupp,
+ has_hiddensystem, has_namedattr);
}
if (nvp != NULL)
vrele(nvp);
@@ -3127,6 +3179,9 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
bitpos = NFSATTRBIT_MAX;
} else {
bitpos = 0;
+ if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_HIDDEN) ||
+ NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SYSTEM))
+ nvap->na_flags = 0;
}
moderet = 0;
for (; bitpos < NFSATTRBIT_MAX; bitpos++) {
@@ -3163,9 +3218,11 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
attrsum += NFSX_UNSIGNED;
break;
case NFSATTRBIT_HIDDEN:
- NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
- if (!nd->nd_repstat)
- nd->nd_repstat = NFSERR_ATTRNOTSUPP;
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ if (nd->nd_repstat == 0) {
+ if (*tl == newnfs_true)
+ nvap->na_flags |= UF_HIDDEN;
+ }
attrsum += NFSX_UNSIGNED;
break;
case NFSATTRBIT_MIMETYPE:
@@ -3240,9 +3297,11 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
break;
case NFSATTRBIT_SYSTEM:
- NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
- if (!nd->nd_repstat)
- nd->nd_repstat = NFSERR_ATTRNOTSUPP;
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ if (nd->nd_repstat == 0) {
+ if (*tl == newnfs_true)
+ nvap->na_flags |= UF_SYSTEM;
+ }
attrsum += NFSX_UNSIGNED;
break;
case NFSATTRBIT_TIMEACCESSSET:
@@ -6326,7 +6385,7 @@ nfsrv_setacldsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
* the same type (VREG).
*/
nfsv4_fillattr(nd, NULL, vp, aclp, NULL, NULL, 0, &attrbits, NULL,
- NULL, 0, 0, 0, 0, 0, NULL);
+ NULL, 0, 0, 0, 0, 0, NULL, false, false, false);
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
if (error != 0) {
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index 4e15d55eb312..9eebcda548c6 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -241,7 +241,7 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
{
struct nfsvattr nva;
fhandle_t fh;
- int at_root = 0, error = 0, supports_nfsv4acls;
+ int at_root = 0, error = 0, ret, supports_nfsv4acls;
struct nfsreferral *refp;
nfsattrbit_t attrbits, tmpbits;
struct mount *mp;
@@ -250,6 +250,9 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
uint64_t mounted_on_fileno = 0;
accmode_t accmode;
struct thread *p = curthread;
+ size_t atsiz;
+ long pathval;
+ bool has_hiddensystem, has_namedattr, xattrsupp;
if (nd->nd_repstat)
goto out;
@@ -307,6 +310,26 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
&nva, &attrbits, p);
if (nd->nd_repstat == 0) {
supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
+ xattrsupp = false;
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_XATTRSUPPORT)) {
+ ret = VOP_GETEXTATTR(vp,
+ EXTATTR_NAMESPACE_USER,
+ "xxx", NULL, &atsiz, nd->nd_cred,
+ p);
+ xattrsupp = ret != EOPNOTSUPP;
+ }
+ if (VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM,
+ &pathval) != 0)
+ pathval = 0;
+ has_hiddensystem = pathval > 0;
+ pathval = 0;
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_NAMEDATTR) &&
+ VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR,
+ &pathval) != 0)
+ pathval = 0;
+ has_namedattr = pathval > 0;
mp = vp->v_mount;
if (nfsrv_enable_crossmntpt != 0 &&
vp->v_type == VDIR &&
@@ -340,7 +363,9 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
(void)nfsvno_fillattr(nd, mp, vp, &nva,
&fh, 0, &attrbits, nd->nd_cred, p,
isdgram, 1, supports_nfsv4acls,
- at_root, mounted_on_fileno);
+ at_root, mounted_on_fileno,
+ xattrsupp, has_hiddensystem,
+ has_namedattr);
vfs_unbusy(mp);
}
vrele(vp);
@@ -403,8 +428,10 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
if (error)
goto nfsmout;
- /* For NFSv4, only va_uid is used from nva2. */
+ /* For NFSv4, only va_uid and va_flags is used from nva2. */
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
+ NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN);
+ NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM);
preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
if (!nd->nd_repstat)
nd->nd_repstat = preat_ret;
@@ -463,6 +490,9 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
&nva, &attrbits, exp, p);
if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
+ u_long oldflags;
+
+ oldflags = nva2.na_flags;
/*
* For V4, try setting the attributes in sets, so that the
* reply bitmap will be correct for an error case.
@@ -532,6 +562,32 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
}
}
+ if (!nd->nd_repstat &&
+ (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN) ||
+ NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))) {
+ if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) {
+ if ((nva.na_flags & UF_HIDDEN) != 0)
+ oldflags |= UF_HIDDEN;
+ else
+ oldflags &= ~UF_HIDDEN;
+ }
+ if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM)) {
+ if ((nva.na_flags & UF_SYSTEM) != 0)
+ oldflags |= UF_SYSTEM;
+ else
+ oldflags &= ~UF_SYSTEM;
+ }
+ NFSVNO_ATTRINIT(&nva2);
+ NFSVNO_SETATTRVAL(&nva2, flags, oldflags);
+ nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
+ exp);
+ if (!nd->nd_repstat) {
+ if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN))
+ NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN);
+ if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))
+ NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM);
+ }
+ }
#ifdef NFS4_ACL_EXTATTR_NAME
if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
@@ -4322,9 +4378,10 @@ nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
int error = 0;
NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN |
- NOFOLLOW);
+ NOFOLLOW | LOCKLEAF);
cn.cn_nameptr = ".";
cn.cn_namelen = 1;
+ cn.cn_lkflags = LK_SHARED;
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
if (*tl == newnfs_true)
cn.cn_flags |= CREATENAMED;
@@ -4343,6 +4400,8 @@ nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
if (nd->nd_repstat == ENOATTR)
nd->nd_repstat = NFSERR_NOENT;
}
+ if (nd->nd_repstat == 0)
+ NFSVOPUNLOCK(*vpp);
vput(dp);
NFSEXITCODE2(0, nd);
diff --git a/sys/fs/nullfs/null_subr.c b/sys/fs/nullfs/null_subr.c
index 0356877eaf05..7dcc83880bb9 100644
--- a/sys/fs/nullfs/null_subr.c
+++ b/sys/fs/nullfs/null_subr.c
@@ -245,6 +245,10 @@ null_nodeget(struct mount *mp, struct vnode *lowervp, struct vnode **vpp)
vp->v_object = lowervp->v_object;
vn_irflag_set(vp, VIRF_PGREAD);
}
+ if ((vn_irflag_read(lowervp) & VIRF_INOTIFY) != 0)
+ vn_irflag_set(vp, VIRF_INOTIFY);
+ if ((vn_irflag_read(lowervp) & VIRF_INOTIFY_PARENT) != 0)
+ vn_irflag_set(vp, VIRF_INOTIFY_PARENT);
if (lowervp == MOUNTTONULLMOUNT(mp)->nullm_lowerrootvp)
vp->v_vflag |= VV_ROOT;
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c
index 8608216e10e5..74c1a8f3acb6 100644
--- a/sys/fs/nullfs/null_vnops.c
+++ b/sys/fs/nullfs/null_vnops.c
@@ -190,6 +190,26 @@ SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW,
&null_bug_bypass, 0, "");
/*
+ * Synchronize inotify flags with the lower vnode:
+ * - If the upper vnode has the flag set and the lower does not, then the lower
+ * vnode is unwatched and the upper vnode does not need to go through
+ * VOP_INOTIFY.
+ * - If the lower vnode is watched, then the upper vnode should go through
+ * VOP_INOTIFY, so copy the flag up.
+ */
+static void
+null_copy_inotify(struct vnode *vp, struct vnode *lvp, short flag)
+{
+ if ((vn_irflag_read(vp) & flag) != 0) {
+ if (__predict_false((vn_irflag_read(lvp) & flag) == 0))
+ vn_irflag_unset(vp, flag);
+ } else if ((vn_irflag_read(lvp) & flag) != 0) {
+ if (__predict_false((vn_irflag_read(vp) & flag) == 0))
+ vn_irflag_set(vp, flag);
+ }
+}
+
+/*
* This is the 10-Apr-92 bypass routine.
* This version has been optimized for speed, throwing away some
* safety checks. It should still always work, but it's not as
@@ -305,7 +325,10 @@ null_bypass(struct vop_generic_args *ap)
lvp = *(vps_p[i]);
/*
- * Get rid of the transient hold on lvp.
+ * Get rid of the transient hold on lvp. Copy inotify
+ * flags up in case something is watching the lower
+ * layer.
+ *
* If lowervp was unlocked during VOP
* operation, nullfs upper vnode could have
* been reclaimed, which changes its v_vnlock
@@ -314,6 +337,10 @@ null_bypass(struct vop_generic_args *ap)
* upper (reclaimed) vnode.
*/
if (lvp != NULLVP) {
+ null_copy_inotify(old_vps[i], lvp,
+ VIRF_INOTIFY);
+ null_copy_inotify(old_vps[i], lvp,
+ VIRF_INOTIFY_PARENT);
if (VOP_ISLOCKED(lvp) == LK_EXCLUSIVE &&
old_vps[i]->v_vnlock != lvp->v_vnlock) {
VOP_UNLOCK(lvp);
diff --git a/sys/fs/p9fs/p9fs_vnops.c b/sys/fs/p9fs/p9fs_vnops.c
index 56bf766ef801..227e2b93883e 100644
--- a/sys/fs/p9fs/p9fs_vnops.c
+++ b/sys/fs/p9fs/p9fs_vnops.c
@@ -1784,6 +1784,9 @@ p9fs_readdir(struct vop_readdir_args *ap)
return (EBADF);
}
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 0;
+
io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK);
/* We haven't reached the end yet. read more. */
@@ -1801,8 +1804,11 @@ p9fs_readdir(struct vop_readdir_args *ap)
count = p9_client_readdir(vofid, (char *)io_buffer,
diroffset, count);
- if (count == 0)
+ if (count == 0) {
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 1;
break;
+ }
if (count < 0) {
error = EIO;
diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c
index c30995508c00..5d412cabadb8 100644
--- a/sys/fs/smbfs/smbfs_vnops.c
+++ b/sys/fs/smbfs/smbfs_vnops.c
@@ -810,6 +810,9 @@ smbfs_pathconf(struct vop_pathconf_args *ap)
case _PC_NO_TRUNC:
*retval = 1;
break;
+ case _PC_HAS_HIDDENSYSTEM:
+ *retval = 1;
+ break;
default:
error = vop_stdpathconf(ap);
}
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index c99d0732be50..9d2a587b177a 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -1691,6 +1691,10 @@ tmpfs_pathconf(struct vop_pathconf_args *v)
*retval = PAGE_SIZE;
break;
+ case _PC_HAS_HIDDENSYSTEM:
+ *retval = 1;
+ break;
+
default:
error = vop_stdpathconf(v);
}
diff --git a/sys/fs/udf/ecma167-udf.h b/sys/fs/udf/ecma167-udf.h
index 839bbec08254..19e114763cac 100644
--- a/sys/fs/udf/ecma167-udf.h
+++ b/sys/fs/udf/ecma167-udf.h
@@ -243,7 +243,7 @@ struct part_map_spare {
uint8_t n_st; /* Number of Sparing Tables */
uint8_t reserved1;
uint32_t st_size;
- uint32_t st_loc[1];
+ uint32_t st_loc[];
} __packed;
union udf_pmap {
@@ -266,7 +266,7 @@ struct udf_sparing_table {
uint16_t rt_l; /* Relocation Table len */
uint8_t reserved[2];
uint32_t seq_num;
- struct spare_map_entry entries[1];
+ struct spare_map_entry entries[];
} __packed;
/* Partition Descriptor [3/10.5] */
diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c
index c7438147c0a0..c5ef1f686093 100644
--- a/sys/fs/udf/udf_vfsops.c
+++ b/sys/fs/udf/udf_vfsops.c
@@ -81,6 +81,7 @@
#include <sys/fcntl.h>
#include <sys/iconv.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/namei.h>
@@ -729,7 +730,7 @@ udf_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
struct ifid *ifhp;
struct vnode *nvp;
struct udf_node *np;
- off_t fsize;
+ uint64_t fsize;
int error;
ifhp = (struct ifid *)fhp;
@@ -741,6 +742,10 @@ udf_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
np = VTON(nvp);
fsize = le64toh(np->fentry->inf_len);
+ if (fsize > OFF_MAX) {
+ *vpp = NULLVP;
+ return (EIO);
+ }
*vpp = nvp;
vnode_create_vobject(*vpp, fsize, curthread);
diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c
index 88bf4917a851..37889241e8c3 100644
--- a/sys/fs/udf/udf_vnops.c
+++ b/sys/fs/udf/udf_vnops.c
@@ -39,6 +39,7 @@
#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/iconv.h>
+#include <sys/limits.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/dirent.h>
@@ -182,11 +183,14 @@ udf_access(struct vop_access_args *a)
}
static int
-udf_open(struct vop_open_args *ap) {
+udf_open(struct vop_open_args *ap)
+{
struct udf_node *np = VTON(ap->a_vp);
- off_t fsize;
+ uint64_t fsize;
fsize = le64toh(np->fentry->inf_len);
+ if (fsize > OFF_MAX)
+ return (EIO);
vnode_create_vobject(ap->a_vp, fsize, ap->a_td);
return 0;
}
@@ -314,12 +318,13 @@ udf_getattr(struct vop_getattr_args *a)
* that directories consume at least one logical block,
* make it appear so.
*/
- if (fentry->logblks_rec != 0) {
- vap->va_size =
- le64toh(fentry->logblks_rec) * node->udfmp->bsize;
- } else {
+ vap->va_size = le64toh(fentry->logblks_rec);
+ if (vap->va_size == 0)
vap->va_size = node->udfmp->bsize;
- }
+ else if (vap->va_size > UINT64_MAX / node->udfmp->bsize)
+ vap->va_size = UINT64_MAX;
+ else
+ vap->va_size *= node->udfmp->bsize;
} else {
vap->va_size = le64toh(fentry->inf_len);
}
@@ -446,6 +451,7 @@ udf_read(struct vop_read_args *ap)
struct buf *bp;
uint8_t *data;
daddr_t lbn, rablock;
+ uint64_t len;
off_t diff, fsize;
ssize_t n;
int error = 0;
@@ -471,7 +477,12 @@ udf_read(struct vop_read_args *ap)
return (error);
}
- fsize = le64toh(node->fentry->inf_len);
+ len = le64toh(node->fentry->inf_len);
+ if (len > OFF_MAX) {
+ /* too big, just cap to the requested length */
+ len = uio->uio_resid;
+ }
+ fsize = len;
udfmp = node->udfmp;
do {
lbn = lblkno(udfmp, uio->uio_offset);
@@ -783,6 +794,7 @@ udf_readdir(struct vop_readdir_args *a)
struct udf_uiodir uiodir;
struct udf_dirstream *ds;
uint64_t *cookies = NULL;
+ uint64_t len;
int ncookies;
int error = 0;
@@ -811,8 +823,12 @@ udf_readdir(struct vop_readdir_args *a)
* Iterate through the file id descriptors. Give the parent dir
* entry special attention.
*/
- ds = udf_opendir(node, uio->uio_offset, le64toh(node->fentry->inf_len),
- node->udfmp);
+ len = le64toh(node->fentry->inf_len);
+ if (len > INT_MAX) {
+ /* too big, just cap to INT_MAX */
+ len = INT_MAX;
+ }
+ ds = udf_opendir(node, uio->uio_offset, len, node->udfmp);
while ((fid = udf_getfid(ds)) != NULL) {
/* XXX Should we return an error on a bad fid? */
@@ -904,7 +920,8 @@ udf_readlink(struct vop_readlink_args *ap)
struct udf_node *node;
void *buf;
char *cp;
- int error, len, root;
+ uint64_t len;
+ int error, root;
/*
* A symbolic link in UDF is a list of variable-length path
@@ -914,6 +931,8 @@ udf_readlink(struct vop_readlink_args *ap)
vp = ap->a_vp;
node = VTON(vp);
len = le64toh(node->fentry->inf_len);
+ if (len > MAXPATHLEN)
+ return (EIO);
buf = malloc(len, M_DEVBUF, M_WAITOK);
iov[0].iov_len = len;
iov[0].iov_base = buf;
@@ -1116,13 +1135,14 @@ udf_lookup(struct vop_cachedlookup_args *a)
struct udf_mnt *udfmp;
struct fileid_desc *fid = NULL;
struct udf_dirstream *ds;
+ uint64_t fsize;
u_long nameiop;
u_long flags;
char *nameptr;
long namelen;
ino_t id = 0;
int offset, error = 0;
- int fsize, lkflags, ltype, numdirpasses;
+ int lkflags, ltype, numdirpasses;
dvp = a->a_dvp;
node = VTON(dvp);
@@ -1133,6 +1153,10 @@ udf_lookup(struct vop_cachedlookup_args *a)
nameptr = a->a_cnp->cn_nameptr;
namelen = a->a_cnp->cn_namelen;
fsize = le64toh(node->fentry->inf_len);
+ if (fsize > INT_MAX) {
+ /* too big, just cap to INT_MAX */
+ fsize = INT_MAX;
+ }
/*
* If this is a LOOKUP and we've already partially searched through
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index e7d460af21d4..f577cd07ac7c 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -17,6 +17,8 @@
# in NOTES.
#
+#NO_UNIVERSE
+
cpu I486_CPU
cpu I586_CPU
cpu I686_CPU
diff --git a/sys/i386/conf/GENERIC-NODEBUG b/sys/i386/conf/GENERIC-NODEBUG
index ea07613a796f..a93304481b5f 100644
--- a/sys/i386/conf/GENERIC-NODEBUG
+++ b/sys/i386/conf/GENERIC-NODEBUG
@@ -25,6 +25,8 @@
# in NOTES.
#
+#NO_UNIVERSE
+
include GENERIC
include "std.nodebug"
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 41207eb63cb9..2e947202f723 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -1,3 +1,4 @@
+#NO_UNIVERSE
include "../../conf/NOTES"
include "../../x86/conf/NOTES"
diff --git a/sys/i386/conf/MINIMAL b/sys/i386/conf/MINIMAL
index 2a06eb84bff8..8019617ca4d4 100644
--- a/sys/i386/conf/MINIMAL
+++ b/sys/i386/conf/MINIMAL
@@ -31,6 +31,8 @@
# in NOTES.
#
+#NO_UNIVERSE
+
cpu I486_CPU
cpu I586_CPU
cpu I686_CPU
diff --git a/sys/i386/conf/PAE b/sys/i386/conf/PAE
index a39d32d77106..72af9e9a9eec 100644
--- a/sys/i386/conf/PAE
+++ b/sys/i386/conf/PAE
@@ -2,6 +2,8 @@
# PAE -- Generic kernel configuration file for FreeBSD/i386 PAE
#
+#NO_UNIVERSE
+
include GENERIC
ident PAE-GENERIC
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
index 465b4d0f365b..b44f5e08bbcf 100644
--- a/sys/i386/i386/pmap.c
+++ b/sys/i386/i386/pmap.c
@@ -876,14 +876,16 @@ __CONCAT(PMTYPE, init_pat)(void)
#ifdef PMAP_PAE_COMP
static void *
-pmap_pdpt_allocf(uma_zone_t zone, vm_size_t bytes, int domain, uint8_t *flags,
- int wait)
+pmap_pdpt_allocf(uma_zone_t zone, vm_size_t bytes, int domain, uint8_t *sflagsp,
+ int flags)
{
/* Inform UMA that this allocator uses kernel_map/object. */
- *flags = UMA_SLAB_KERNEL;
+ *sflagsp = UMA_SLAB_KERNEL;
+ /* contig allocations cannot be NEVERFREED */
+ flags &= ~M_NEVERFREED;
return ((void *)kmem_alloc_contig_domainset(DOMAINSET_FIXED(domain),
- bytes, wait, 0x0ULL, 0xffffffffULL, 1, 0, VM_MEMATTR_DEFAULT));
+ bytes, flags, 0x0ULL, 0xffffffffULL, 1, 0, VM_MEMATTR_DEFAULT));
}
#endif
@@ -5617,6 +5619,8 @@ __CONCAT(PMTYPE, unmapdev)(void *p, vm_size_t size)
static void
__CONCAT(PMTYPE, page_set_memattr)(vm_page_t m, vm_memattr_t ma)
{
+ if (m->md.pat_mode == ma)
+ return;
m->md.pat_mode = ma;
if ((m->flags & PG_FICTITIOUS) != 0)
diff --git a/sys/i386/linux/linux_proto.h b/sys/i386/linux/linux_proto.h
index aa2dfbb68745..49f002a633d2 100644
--- a/sys/i386/linux/linux_proto.h
+++ b/sys/i386/linux/linux_proto.h
@@ -981,10 +981,13 @@ struct linux_inotify_init_args {
syscallarg_t dummy;
};
struct linux_inotify_add_watch_args {
- syscallarg_t dummy;
+ char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)];
+ char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)];
+ char mask_l_[PADL_(uint32_t)]; uint32_t mask; char mask_r_[PADR_(uint32_t)];
};
struct linux_inotify_rm_watch_args {
- syscallarg_t dummy;
+ char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)];
+ char wd_l_[PADL_(uint32_t)]; uint32_t wd; char wd_r_[PADR_(uint32_t)];
};
struct linux_migrate_pages_args {
syscallarg_t dummy;
@@ -1178,7 +1181,7 @@ struct linux_pipe2_args {
char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
};
struct linux_inotify_init1_args {
- syscallarg_t dummy;
+ char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
};
struct linux_preadv_args {
char fd_l_[PADL_(l_ulong)]; l_ulong fd; char fd_r_[PADR_(l_ulong)];
diff --git a/sys/i386/linux/linux_sysent.c b/sys/i386/linux/linux_sysent.c
index 7be646f34144..b8893008944b 100644
--- a/sys/i386/linux/linux_sysent.c
+++ b/sys/i386/linux/linux_sysent.c
@@ -306,8 +306,8 @@ struct sysent linux_sysent[] = {
{ .sy_narg = AS(linux_ioprio_set_args), .sy_call = (sy_call_t *)linux_ioprio_set, .sy_auevent = AUE_SETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 289 = linux_ioprio_set */
{ .sy_narg = AS(linux_ioprio_get_args), .sy_call = (sy_call_t *)linux_ioprio_get, .sy_auevent = AUE_GETPRIORITY, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 290 = linux_ioprio_get */
{ .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_init, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 291 = linux_inotify_init */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_add_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 292 = linux_inotify_add_watch */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_rm_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 293 = linux_inotify_rm_watch */
+ { .sy_narg = AS(linux_inotify_add_watch_args), .sy_call = (sy_call_t *)linux_inotify_add_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 292 = linux_inotify_add_watch */
+ { .sy_narg = AS(linux_inotify_rm_watch_args), .sy_call = (sy_call_t *)linux_inotify_rm_watch, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 293 = linux_inotify_rm_watch */
{ .sy_narg = 0, .sy_call = (sy_call_t *)linux_migrate_pages, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 294 = linux_migrate_pages */
{ .sy_narg = AS(linux_openat_args), .sy_call = (sy_call_t *)linux_openat, .sy_auevent = AUE_OPEN_RWTC, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 295 = linux_openat */
{ .sy_narg = AS(linux_mkdirat_args), .sy_call = (sy_call_t *)linux_mkdirat, .sy_auevent = AUE_MKDIRAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 296 = linux_mkdirat */
@@ -346,7 +346,7 @@ struct sysent linux_sysent[] = {
{ .sy_narg = AS(linux_epoll_create1_args), .sy_call = (sy_call_t *)linux_epoll_create1, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 329 = linux_epoll_create1 */
{ .sy_narg = AS(linux_dup3_args), .sy_call = (sy_call_t *)linux_dup3, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 330 = linux_dup3 */
{ .sy_narg = AS(linux_pipe2_args), .sy_call = (sy_call_t *)linux_pipe2, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 331 = linux_pipe2 */
- { .sy_narg = 0, .sy_call = (sy_call_t *)linux_inotify_init1, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 332 = linux_inotify_init1 */
+ { .sy_narg = AS(linux_inotify_init1_args), .sy_call = (sy_call_t *)linux_inotify_init1, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 332 = linux_inotify_init1 */
{ .sy_narg = AS(linux_preadv_args), .sy_call = (sy_call_t *)linux_preadv, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 333 = linux_preadv */
{ .sy_narg = AS(linux_pwritev_args), .sy_call = (sy_call_t *)linux_pwritev, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 334 = linux_pwritev */
{ .sy_narg = AS(linux_rt_tgsigqueueinfo_args), .sy_call = (sy_call_t *)linux_rt_tgsigqueueinfo, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 335 = linux_rt_tgsigqueueinfo */
diff --git a/sys/i386/linux/linux_systrace_args.c b/sys/i386/linux/linux_systrace_args.c
index f3e3c32a2bbf..563d1a795ae1 100644
--- a/sys/i386/linux/linux_systrace_args.c
+++ b/sys/i386/linux/linux_systrace_args.c
@@ -2071,12 +2071,19 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
}
/* linux_inotify_add_watch */
case 292: {
- *n_args = 0;
+ struct linux_inotify_add_watch_args *p = params;
+ iarg[a++] = p->fd; /* l_int */
+ uarg[a++] = (intptr_t)p->pathname; /* const char * */
+ uarg[a++] = p->mask; /* uint32_t */
+ *n_args = 3;
break;
}
/* linux_inotify_rm_watch */
case 293: {
- *n_args = 0;
+ struct linux_inotify_rm_watch_args *p = params;
+ iarg[a++] = p->fd; /* l_int */
+ uarg[a++] = p->wd; /* uint32_t */
+ *n_args = 2;
break;
}
/* linux_migrate_pages */
@@ -2410,7 +2417,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
}
/* linux_inotify_init1 */
case 332: {
- *n_args = 0;
+ struct linux_inotify_init1_args *p = params;
+ iarg[a++] = p->flags; /* l_int */
+ *n_args = 1;
break;
}
/* linux_preadv */
@@ -6604,9 +6613,32 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_inotify_add_watch */
case 292:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ case 1:
+ p = "userland const char *";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
break;
/* linux_inotify_rm_watch */
case 293:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ case 1:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
break;
/* linux_migrate_pages */
case 294:
@@ -7172,6 +7204,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_inotify_init1 */
case 332:
+ switch (ndx) {
+ case 0:
+ p = "l_int";
+ break;
+ default:
+ break;
+ };
break;
/* linux_preadv */
case 333:
@@ -9889,8 +9928,14 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
case 291:
/* linux_inotify_add_watch */
case 292:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_inotify_rm_watch */
case 293:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_migrate_pages */
case 294:
/* linux_openat */
@@ -10062,6 +10107,9 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_inotify_init1 */
case 332:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_preadv */
case 333:
if (ndx == 0 || ndx == 1)
diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master
index 958336be0f08..2113ea51ac5d 100644
--- a/sys/i386/linux/syscalls.master
+++ b/sys/i386/linux/syscalls.master
@@ -1605,10 +1605,17 @@
int linux_inotify_init(void);
}
292 AUE_NULL STD {
- int linux_inotify_add_watch(void);
+ int linux_inotify_add_watch(
+ l_int fd,
+ const char *pathname,
+ uint32_t mask
+ );
}
293 AUE_NULL STD {
- int linux_inotify_rm_watch(void);
+ int linux_inotify_rm_watch(
+ l_int fd,
+ uint32_t wd
+ );
}
; Linux 2.6.16:
294 AUE_NULL STD {
@@ -1872,7 +1879,9 @@
);
}
332 AUE_NULL STD {
- int linux_inotify_init1(void);
+ int linux_inotify_init1(
+ l_int flags
+ );
}
; Linux 2.6.30:
333 AUE_NULL STD {
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index a48a513aa3b5..91792430d24c 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -658,5 +658,7 @@ struct sysent sysent[] = {
{ .sy_narg = AS(getrlimitusage_args), .sy_call = (sy_call_t *)sys_getrlimitusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimitusage */
{ .sy_narg = AS(fchroot_args), .sy_call = (sy_call_t *)sys_fchroot, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 590 = fchroot */
{ .sy_narg = AS(setcred_args), .sy_call = (sy_call_t *)sys_setcred, .sy_auevent = AUE_SETCRED, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 591 = setcred */
- { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */
+ { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */
+ { .sy_narg = AS(inotify_add_watch_at_args), .sy_call = (sy_call_t *)sys_inotify_add_watch_at, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 593 = inotify_add_watch_at */
+ { .sy_narg = AS(inotify_rm_watch_args), .sy_call = (sy_call_t *)sys_inotify_rm_watch, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 594 = inotify_rm_watch */
};
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index ac4b6ac3f457..a27ab33b34da 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -38,9 +38,11 @@
#include "opt_ddb.h"
#include "opt_ktrace.h"
+#define EXTERR_CATEGORY EXTERR_CAT_FILEDESC
#include <sys/systm.h>
#include <sys/capsicum.h>
#include <sys/conf.h>
+#include <sys/exterrvar.h>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/filedesc.h>
@@ -478,6 +480,92 @@ kern_fcntl_freebsd(struct thread *td, int fd, int cmd, intptr_t arg)
return (error);
}
+struct flags_trans_elem {
+ u_int f;
+ u_int t;
+};
+
+static u_int
+flags_trans(const struct flags_trans_elem *ftes, int nitems, u_int from_flags)
+{
+ u_int res;
+ int i;
+
+ res = 0;
+ for (i = 0; i < nitems; i++) {
+ if ((from_flags & ftes[i].f) != 0)
+ res |= ftes[i].t;
+ }
+ return (res);
+}
+
+static uint8_t
+fd_to_fde_flags(int fd_flags)
+{
+ static const struct flags_trans_elem fd_to_fde_flags_s[] = {
+ { .f = FD_CLOEXEC, .t = UF_EXCLOSE },
+ { .f = FD_CLOFORK, .t = UF_FOCLOSE },
+ { .f = FD_RESOLVE_BENEATH, .t = UF_RESOLVE_BENEATH },
+ };
+
+ return (flags_trans(fd_to_fde_flags_s, nitems(fd_to_fde_flags_s),
+ fd_flags));
+}
+
+static int
+fde_to_fd_flags(uint8_t fde_flags)
+{
+ static const struct flags_trans_elem fde_to_fd_flags_s[] = {
+ { .f = UF_EXCLOSE, .t = FD_CLOEXEC },
+ { .f = UF_FOCLOSE, .t = FD_CLOFORK },
+ { .f = UF_RESOLVE_BENEATH, .t = FD_RESOLVE_BENEATH },
+ };
+
+ return (flags_trans(fde_to_fd_flags_s, nitems(fde_to_fd_flags_s),
+ fde_flags));
+}
+
+static uint8_t
+fddup_to_fde_flags(int fddup_flags)
+{
+ static const struct flags_trans_elem fddup_to_fde_flags_s[] = {
+ { .f = FDDUP_FLAG_CLOEXEC, .t = UF_EXCLOSE },
+ { .f = FDDUP_FLAG_CLOFORK, .t = UF_FOCLOSE },
+ };
+
+ return (flags_trans(fddup_to_fde_flags_s, nitems(fddup_to_fde_flags_s),
+ fddup_flags));
+}
+
+static uint8_t
+close_range_to_fde_flags(int close_range_flags)
+{
+ static const struct flags_trans_elem close_range_to_fde_flags_s[] = {
+ { .f = CLOSE_RANGE_CLOEXEC, .t = UF_EXCLOSE },
+ { .f = CLOSE_RANGE_CLOFORK, .t = UF_FOCLOSE },
+ };
+
+ return (flags_trans(close_range_to_fde_flags_s,
+ nitems(close_range_to_fde_flags_s), close_range_flags));
+}
+
+static uint8_t
+open_to_fde_flags(int open_flags, bool sticky_orb)
+{
+ static const struct flags_trans_elem open_to_fde_flags_s[] = {
+ { .f = O_CLOEXEC, .t = UF_EXCLOSE },
+ { .f = O_CLOFORK, .t = UF_FOCLOSE },
+ { .f = O_RESOLVE_BENEATH, .t = UF_RESOLVE_BENEATH },
+ };
+#if defined(__clang__) && __clang_major__ >= 19
+ _Static_assert(open_to_fde_flags_s[nitems(open_to_fde_flags_s) - 1].f ==
+ O_RESOLVE_BENEATH, "O_RESOLVE_BENEATH must be last, for sticky_orb");
+#endif
+
+ return (flags_trans(open_to_fde_flags_s, nitems(open_to_fde_flags_s) -
+ (sticky_orb ? 0 : 1), open_flags));
+}
+
int
kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
{
@@ -492,6 +580,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
int error, flg, kif_sz, seals, tmp, got_set, got_cleared;
uint64_t bsize;
off_t foffset;
+ int flags;
error = 0;
flg = F_POSIX;
@@ -511,6 +600,11 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
error = kern_dup(td, FDDUP_FCNTL, FDDUP_FLAG_CLOEXEC, fd, tmp);
break;
+ case F_DUPFD_CLOFORK:
+ tmp = arg;
+ error = kern_dup(td, FDDUP_FCNTL, FDDUP_FLAG_CLOFORK, fd, tmp);
+ break;
+
case F_DUP2FD:
tmp = arg;
error = kern_dup(td, FDDUP_FIXED, 0, fd, tmp);
@@ -526,10 +620,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
FILEDESC_SLOCK(fdp);
fde = fdeget_noref(fdp, fd);
if (fde != NULL) {
- td->td_retval[0] =
- ((fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0) |
- ((fde->fde_flags & UF_RESOLVE_BENEATH) ?
- FD_RESOLVE_BENEATH : 0);
+ td->td_retval[0] = fde_to_fd_flags(fde->fde_flags);
error = 0;
}
FILEDESC_SUNLOCK(fdp);
@@ -543,10 +634,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
/*
* UF_RESOLVE_BENEATH is sticky and cannot be cleared.
*/
- fde->fde_flags = (fde->fde_flags & ~UF_EXCLOSE) |
- ((arg & FD_CLOEXEC) != 0 ? UF_EXCLOSE : 0) |
- ((arg & FD_RESOLVE_BENEATH) != 0 ?
- UF_RESOLVE_BENEATH : 0);
+ fde->fde_flags = (fde->fde_flags &
+ ~(UF_EXCLOSE | UF_FOCLOSE)) | fd_to_fde_flags(arg);
error = 0;
}
FILEDESC_XUNLOCK(fdp);
@@ -916,7 +1005,17 @@ revert_f_setfl:
break;
default:
- error = EINVAL;
+ if ((cmd & ((1u << F_DUP3FD_SHIFT) - 1)) != F_DUP3FD)
+ return (EXTERROR(EINVAL, "invalid fcntl cmd"));
+ /* Handle F_DUP3FD */
+ flags = (cmd >> F_DUP3FD_SHIFT);
+ if ((flags & ~(FD_CLOEXEC | FD_CLOFORK)) != 0)
+ return (EXTERROR(EINVAL, "invalid flags for F_DUP3FD"));
+ tmp = arg;
+ error = kern_dup(td, FDDUP_FIXED,
+ ((flags & FD_CLOEXEC) != 0 ? FDDUP_FLAG_CLOEXEC : 0) |
+ ((flags & FD_CLOFORK) != 0 ? FDDUP_FLAG_CLOFORK : 0),
+ fd, tmp);
break;
}
return (error);
@@ -946,7 +1045,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new)
fdp = p->p_fd;
oioctls = NULL;
- MPASS((flags & ~(FDDUP_FLAG_CLOEXEC)) == 0);
+ MPASS((flags & ~(FDDUP_FLAG_CLOEXEC | FDDUP_FLAG_CLOFORK)) == 0);
MPASS(mode < FDDUP_LASTMODE);
AUDIT_ARG_FD(old);
@@ -971,8 +1070,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new)
goto unlock;
if (mode == FDDUP_FIXED && old == new) {
td->td_retval[0] = new;
- if (flags & FDDUP_FLAG_CLOEXEC)
- fdp->fd_ofiles[new].fde_flags |= UF_EXCLOSE;
+ fdp->fd_ofiles[new].fde_flags |= fddup_to_fde_flags(flags);
error = 0;
goto unlock;
}
@@ -1047,10 +1145,8 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new)
fde_copy(oldfde, newfde);
filecaps_copy_finish(&oldfde->fde_caps, &newfde->fde_caps,
nioctls);
- if ((flags & FDDUP_FLAG_CLOEXEC) != 0)
- newfde->fde_flags = oldfde->fde_flags | UF_EXCLOSE;
- else
- newfde->fde_flags = oldfde->fde_flags & ~UF_EXCLOSE;
+ newfde->fde_flags = (oldfde->fde_flags & ~(UF_EXCLOSE | UF_FOCLOSE)) |
+ fddup_to_fde_flags(flags);
#ifdef CAPABILITIES
seqc_write_end(&newfde->fde_seqc);
#endif
@@ -1416,13 +1512,14 @@ kern_close(struct thread *td, int fd)
}
static int
-close_range_cloexec(struct thread *td, u_int lowfd, u_int highfd)
+close_range_flags(struct thread *td, u_int lowfd, u_int highfd, int flags)
{
struct filedesc *fdp;
struct fdescenttbl *fdt;
struct filedescent *fde;
- int fd;
+ int fd, fde_flags;
+ fde_flags = close_range_to_fde_flags(flags);
fdp = td->td_proc->p_fd;
FILEDESC_XLOCK(fdp);
fdt = atomic_load_ptr(&fdp->fd_files);
@@ -1434,7 +1531,7 @@ close_range_cloexec(struct thread *td, u_int lowfd, u_int highfd)
for (; fd <= highfd; fd++) {
fde = &fdt->fdt_ofiles[fd];
if (fde->fde_file != NULL)
- fde->fde_flags |= UF_EXCLOSE;
+ fde->fde_flags |= fde_flags;
}
out_locked:
FILEDESC_XUNLOCK(fdp);
@@ -1492,8 +1589,8 @@ kern_close_range(struct thread *td, int flags, u_int lowfd, u_int highfd)
return (EINVAL);
}
- if ((flags & CLOSE_RANGE_CLOEXEC) != 0)
- return (close_range_cloexec(td, lowfd, highfd));
+ if ((flags & (CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_CLOFORK)) != 0)
+ return (close_range_flags(td, lowfd, highfd, flags));
return (close_range_impl(td, lowfd, highfd));
}
@@ -1513,7 +1610,7 @@ sys_close_range(struct thread *td, struct close_range_args *uap)
AUDIT_ARG_CMD(uap->highfd);
AUDIT_ARG_FFLAGS(uap->flags);
- if ((uap->flags & ~(CLOSE_RANGE_CLOEXEC)) != 0)
+ if ((uap->flags & ~(CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_CLOFORK)) != 0)
return (EINVAL);
return (kern_close_range(td, uap->flags, uap->lowfd, uap->highfd));
}
@@ -2171,8 +2268,7 @@ _finstall(struct filedesc *fdp, struct file *fp, int fd, int flags,
seqc_write_begin(&fde->fde_seqc);
#endif
fde->fde_file = fp;
- fde->fde_flags = ((flags & O_CLOEXEC) != 0 ? UF_EXCLOSE : 0) |
- ((flags & O_RESOLVE_BENEATH) != 0 ? UF_RESOLVE_BENEATH : 0);
+ fde->fde_flags = open_to_fde_flags(flags, true);
if (fcaps != NULL)
filecaps_move(fcaps, &fde->fde_caps);
else
@@ -2432,6 +2528,7 @@ fdcopy(struct filedesc *fdp)
newfdp->fd_freefile = fdp->fd_freefile;
FILEDESC_FOREACH_FDE(fdp, i, ofde) {
if ((ofde->fde_file->f_ops->fo_flags & DFLAG_PASSABLE) == 0 ||
+ (ofde->fde_flags & UF_FOCLOSE) != 0 ||
!fhold(ofde->fde_file)) {
if (newfdp->fd_freefile == fdp->fd_freefile)
newfdp->fd_freefile = i;
@@ -2729,6 +2826,12 @@ fdcloseexec(struct thread *td)
fdfree(fdp, i);
(void) closefp(fdp, i, fp, td, false, false);
FILEDESC_UNLOCK_ASSERT(fdp);
+ } else if (fde->fde_flags & UF_FOCLOSE) {
+ /*
+ * https://austingroupbugs.net/view.php?id=1851
+ * FD_CLOFORK should not be preserved across exec
+ */
+ fde->fde_flags &= ~UF_FOCLOSE;
}
}
}
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c
index c8b01afeab4f..dcd38c6e6fbe 100644
--- a/sys/kern/kern_resource.c
+++ b/sys/kern/kern_resource.c
@@ -1637,6 +1637,12 @@ uifree(struct uidinfo *uip)
if (uip->ui_pipecnt != 0)
printf("freeing uidinfo: uid = %d, pipecnt = %ld\n",
uip->ui_uid, uip->ui_pipecnt);
+ if (uip->ui_inotifycnt != 0)
+ printf("freeing uidinfo: uid = %d, inotifycnt = %ld\n",
+ uip->ui_uid, uip->ui_inotifycnt);
+ if (uip->ui_inotifywatchcnt != 0)
+ printf("freeing uidinfo: uid = %d, inotifywatchcnt = %ld\n",
+ uip->ui_uid, uip->ui_inotifywatchcnt);
free(uip, M_UIDINFO);
}
@@ -1742,6 +1748,21 @@ chgpipecnt(struct uidinfo *uip, int diff, rlim_t max)
return (chglimit(uip, &uip->ui_pipecnt, diff, max, "pipecnt"));
}
+int
+chginotifycnt(struct uidinfo *uip, int diff, rlim_t max)
+{
+
+ return (chglimit(uip, &uip->ui_inotifycnt, diff, max, "inotifycnt"));
+}
+
+int
+chginotifywatchcnt(struct uidinfo *uip, int diff, rlim_t max)
+{
+
+ return (chglimit(uip, &uip->ui_inotifywatchcnt, diff, max,
+ "inotifywatchcnt"));
+}
+
static int
sysctl_kern_proc_rlimit_usage(SYSCTL_HANDLER_ARGS)
{
diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c
index 17b53208157a..35b258e68701 100644
--- a/sys/kern/kern_sendfile.c
+++ b/sys/kern/kern_sendfile.c
@@ -27,12 +27,12 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "opt_kern_tls.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/capsicum.h>
+#include <sys/inotify.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/ktls.h>
@@ -1246,6 +1246,8 @@ out:
*/
if (error == 0) {
td->td_retval[0] = 0;
+ if (sbytes > 0 && vp != NULL)
+ INOTIFY(vp, IN_ACCESS);
}
if (sent != NULL) {
(*sent) = sbytes;
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 4565abc4b540..5d51aa675cb7 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1050,8 +1050,7 @@ osigaction(struct thread *td, struct osigaction_args *uap)
int
osigreturn(struct thread *td, struct osigreturn_args *uap)
{
-
- return (nosys(td, (struct nosys_args *)uap));
+ return (kern_nosys(td, 0));
}
#endif
#endif /* COMPAT_43 */
@@ -4139,7 +4138,7 @@ coredump(struct thread *td)
struct flock lf;
struct vattr vattr;
size_t fullpathsize;
- int error, error1, locked;
+ int error, error1, jid, locked, ppid, sig;
char *name; /* name of corefile */
void *rl_cookie;
off_t limit;
@@ -4168,6 +4167,10 @@ coredump(struct thread *td)
PROC_UNLOCK(p);
return (EFBIG);
}
+
+ ppid = p->p_oppid;
+ sig = p->p_sig;
+ jid = p->p_ucred->cr_prison->pr_id;
PROC_UNLOCK(p);
error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td,
@@ -4253,6 +4256,9 @@ coredump(struct thread *td)
}
devctl_safe_quote_sb(sb, name);
sbuf_putc(sb, '"');
+
+ sbuf_printf(sb, " jid=%d pid=%d ppid=%d signo=%d",
+ jid, p->p_pid, ppid, sig);
if (sbuf_finish(sb) == 0)
devctl_notify("kernel", "signal", "coredump", sbuf_data(sb));
out2:
@@ -4281,6 +4287,12 @@ struct nosys_args {
int
nosys(struct thread *td, struct nosys_args *args)
{
+ return (kern_nosys(td, args->dummy));
+}
+
+int
+kern_nosys(struct thread *td, int dummy)
+{
struct proc *p;
p = td->td_proc;
diff --git a/sys/kern/kern_syscalls.c b/sys/kern/kern_syscalls.c
index 24406763a93a..a93d711e7597 100644
--- a/sys/kern/kern_syscalls.c
+++ b/sys/kern/kern_syscalls.c
@@ -35,6 +35,7 @@
#include <sys/resourcevar.h>
#include <sys/sx.h>
#include <sys/syscall.h>
+#include <sys/syscallsubr.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/systm.h>
@@ -50,14 +51,14 @@ int
lkmnosys(struct thread *td, struct nosys_args *args)
{
- return (nosys(td, args));
+ return (kern_nosys(td, 0));
}
int
lkmressys(struct thread *td, struct nosys_args *args)
{
- return (nosys(td, args));
+ return (kern_nosys(td, 0));
}
struct sysent nosys_sysent = {
diff --git a/sys/kern/subr_asan.c b/sys/kern/subr_asan.c
index 0edb631d1475..464efda1e91a 100644
--- a/sys/kern/subr_asan.c
+++ b/sys/kern/subr_asan.c
@@ -263,8 +263,7 @@ kasan_mark(const void *addr, size_t size, size_t redzsize, uint8_t code)
if (__predict_false(!kasan_enabled))
return;
- if ((vm_offset_t)addr >= DMAP_MIN_ADDRESS &&
- (vm_offset_t)addr < DMAP_MAX_ADDRESS)
+ if (kasan_md_unsupported((vm_offset_t)addr))
return;
KASSERT((vm_offset_t)addr >= VM_MIN_KERNEL_ADDRESS &&
diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c
index 7cc6fb593697..5ad5b0af1681 100644
--- a/sys/kern/subr_capability.c
+++ b/sys/kern/subr_capability.c
@@ -74,6 +74,10 @@ const cap_rights_t cap_getsockopt_rights =
CAP_RIGHTS_INITIALIZER(CAP_GETSOCKOPT);
const cap_rights_t cap_getsockname_rights =
CAP_RIGHTS_INITIALIZER(CAP_GETSOCKNAME);
+const cap_rights_t cap_inotify_add_rights =
+ CAP_RIGHTS_INITIALIZER(CAP_INOTIFY_ADD);
+const cap_rights_t cap_inotify_rm_rights =
+ CAP_RIGHTS_INITIALIZER(CAP_INOTIFY_RM);
const cap_rights_t cap_ioctl_rights = CAP_RIGHTS_INITIALIZER(CAP_IOCTL);
const cap_rights_t cap_listen_rights = CAP_RIGHTS_INITIALIZER(CAP_LISTEN);
const cap_rights_t cap_linkat_source_rights =
diff --git a/sys/kern/subr_pctrie.c b/sys/kern/subr_pctrie.c
index 3a3548bad52b..bb86c779b936 100644
--- a/sys/kern/subr_pctrie.c
+++ b/sys/kern/subr_pctrie.c
@@ -691,21 +691,23 @@ _pctrie_lookup_ge(struct pctrie *ptree, struct pctrie_node *node,
*/
if (node == PCTRIE_NULL || *pctrie_toval(node) < index) {
/* Climb the path to find a node with a descendant > index. */
- for (node = parent; node != NULL; node = pctrie_parent(node)) {
- slot = pctrie_slot(node, index) + 1;
- if ((node->pn_popmap >> slot) != 0)
+ node = NULL;
+ while (parent != NULL) {
+ slot = pctrie_slot(parent, index) + 1;
+ if ((parent->pn_popmap >> slot) != 0)
break;
+ node = parent;
+ parent = pctrie_parent(node);
}
- if (node == NULL) {
+ if (parent == NULL) {
if (parent_out != NULL)
- *parent_out = NULL;
+ *parent_out = node;
return (NULL);
}
/* Step to the least child with a descendant > index. */
- slot += ffs(node->pn_popmap >> slot) - 1;
- parent = node;
- node = pctrie_node_load(&node->pn_child[slot], NULL,
+ slot += ffs(parent->pn_popmap >> slot) - 1;
+ node = pctrie_node_load(&parent->pn_child[slot], NULL,
PCTRIE_LOCKED);
}
/* Descend to the least leaf of the subtrie. */
@@ -785,21 +787,23 @@ _pctrie_lookup_le(struct pctrie *ptree, struct pctrie_node *node,
*/
if (node == PCTRIE_NULL || *pctrie_toval(node) > index) {
/* Climb the path to find a node with a descendant < index. */
- for (node = parent; node != NULL; node = pctrie_parent(node)) {
- slot = pctrie_slot(node, index);
- if ((node->pn_popmap & ((1 << slot) - 1)) != 0)
+ node = NULL;
+ while (parent != NULL) {
+ slot = pctrie_slot(parent, index);
+ if ((parent->pn_popmap & ((1 << slot) - 1)) != 0)
break;
+ node = parent;
+ parent = pctrie_parent(node);
}
- if (node == NULL) {
+ if (parent == NULL) {
if (parent_out != NULL)
- *parent_out = NULL;
+ *parent_out = node;
return (NULL);
}
/* Step to the greatest child with a descendant < index. */
- slot = ilog2(node->pn_popmap & ((1 << slot) - 1));
- parent = node;
- node = pctrie_node_load(&node->pn_child[slot], NULL,
+ slot = ilog2(parent->pn_popmap & ((1 << slot) - 1));
+ node = pctrie_node_load(&parent->pn_child[slot], NULL,
PCTRIE_LOCKED);
}
/* Descend to the greatest leaf of the subtrie. */
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
index 18388ae5f232..bac7d0080c71 100644
--- a/sys/kern/subr_trap.c
+++ b/sys/kern/subr_trap.c
@@ -338,8 +338,9 @@ ast_handler(struct thread *td, struct trapframe *framep, bool dtor)
td->td_ast = 0;
}
- CTR3(KTR_SYSC, "ast: thread %p (pid %d, %s)", td, td->td_proc->p_pid,
- td->td_proc->p_comm);
+ CTR3(KTR_SYSC, "ast: thread %p (pid %d, %s)", td,
+ td->td_proc == NULL ? -1 : td->td_proc->p_pid,
+ td->td_proc == NULL ? "" : td->td_proc->p_comm);
KASSERT(framep == NULL || TRAPF_USERMODE(framep),
("ast in kernel mode"));
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index d31ff3b939cc..b472aaea89e6 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -37,16 +37,17 @@
#include "opt_capsicum.h"
#include "opt_ktrace.h"
-#define EXTERR_CATEGORY EXTERR_CAT_FILEDESC
+#define EXTERR_CATEGORY EXTERR_CAT_GENIO
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/capsicum.h>
+#include <sys/exterrvar.h>
#include <sys/filedesc.h>
#include <sys/filio.h>
#include <sys/fcntl.h>
#include <sys/file.h>
-#include <sys/exterrvar.h>
+#include <sys/inotify.h>
#include <sys/lock.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
@@ -195,7 +196,7 @@ sys_read(struct thread *td, struct read_args *uap)
int error;
if (uap->nbyte > IOSIZE_MAX)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "length > iosize_max"));
aiov.iov_base = uap->buf;
aiov.iov_len = uap->nbyte;
auio.uio_iov = &aiov;
@@ -233,7 +234,7 @@ kern_pread(struct thread *td, int fd, void *buf, size_t nbyte, off_t offset)
int error;
if (nbyte > IOSIZE_MAX)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "length > iosize_max"));
aiov.iov_base = buf;
aiov.iov_len = nbyte;
auio.uio_iov = &aiov;
@@ -329,7 +330,7 @@ kern_preadv(struct thread *td, int fd, struct uio *auio, off_t offset)
error = ESPIPE;
else if (offset < 0 &&
(fp->f_vnode == NULL || fp->f_vnode->v_type != VCHR))
- error = EINVAL;
+ error = EXTERROR(EINVAL, "neg offset");
else
error = dofileread(td, fd, fp, auio, offset, FOF_OFFSET);
fdrop(fp, td);
@@ -396,7 +397,7 @@ sys_write(struct thread *td, struct write_args *uap)
int error;
if (uap->nbyte > IOSIZE_MAX)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "length > iosize_max"));
aiov.iov_base = (void *)(uintptr_t)uap->buf;
aiov.iov_len = uap->nbyte;
auio.uio_iov = &aiov;
@@ -435,7 +436,7 @@ kern_pwrite(struct thread *td, int fd, const void *buf, size_t nbyte,
int error;
if (nbyte > IOSIZE_MAX)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "length > iosize_max"));
aiov.iov_base = (void *)(uintptr_t)buf;
aiov.iov_len = nbyte;
auio.uio_iov = &aiov;
@@ -531,7 +532,7 @@ kern_pwritev(struct thread *td, int fd, struct uio *auio, off_t offset)
error = ESPIPE;
else if (offset < 0 &&
(fp->f_vnode == NULL || fp->f_vnode->v_type != VCHR))
- error = EINVAL;
+ error = EXTERROR(EINVAL, "neg offset");
else
error = dofilewrite(td, fd, fp, auio, offset, FOF_OFFSET);
fdrop(fp, td);
@@ -602,14 +603,14 @@ kern_ftruncate(struct thread *td, int fd, off_t length)
AUDIT_ARG_FD(fd);
if (length < 0)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "negative length"));
error = fget(td, fd, &cap_ftruncate_rights, &fp);
if (error)
return (error);
AUDIT_ARG_FILE(td->td_proc, fp);
if (!(fp->f_flag & FWRITE)) {
fdrop(fp, td);
- return (EINVAL);
+ return (EXTERROR(EINVAL, "non-writable"));
}
error = fo_truncate(fp, length, td->td_ucred, td);
fdrop(fp, td);
@@ -840,8 +841,10 @@ kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len)
int error;
AUDIT_ARG_FD(fd);
- if (offset < 0 || len <= 0)
- return (EINVAL);
+ if (offset < 0)
+ return (EXTERROR(EINVAL, "negative offset"));
+ if (len <= 0)
+ return (EXTERROR(EINVAL, "negative length"));
/* Check for wrap. */
if (offset > OFF_MAX - len)
return (EFBIG);
@@ -898,16 +901,21 @@ kern_fspacectl(struct thread *td, int fd, int cmd,
AUDIT_ARG_FFLAGS(flags);
if (rqsr == NULL)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "no range"));
rmsr = *rqsr;
if (rmsrp != NULL)
*rmsrp = rmsr;
- if (cmd != SPACECTL_DEALLOC ||
- rqsr->r_offset < 0 || rqsr->r_len <= 0 ||
- rqsr->r_offset > OFF_MAX - rqsr->r_len ||
- (flags & ~SPACECTL_F_SUPPORTED) != 0)
- return (EINVAL);
+ if (cmd != SPACECTL_DEALLOC)
+ return (EXTERROR(EINVAL, "cmd", cmd));
+ if (rqsr->r_offset < 0)
+ return (EXTERROR(EINVAL, "neg offset"));
+ if (rqsr->r_len <= 0)
+ return (EXTERROR(EINVAL, "neg len"));
+ if (rqsr->r_offset > OFF_MAX - rqsr->r_len)
+ return (EXTERROR(EINVAL, "offset too large"));
+ if ((flags & ~SPACECTL_F_SUPPORTED) != 0)
+ return (EXTERROR(EINVAL, "reserved flags", flags));
error = fget_write(td, fd, &cap_pwrite_rights, &fp);
if (error != 0)
@@ -939,7 +947,6 @@ int
kern_specialfd(struct thread *td, int type, void *arg)
{
struct file *fp;
- struct specialfd_eventfd *ae;
int error, fd, fflags;
fflags = 0;
@@ -948,14 +955,24 @@ kern_specialfd(struct thread *td, int type, void *arg)
return (error);
switch (type) {
- case SPECIALFD_EVENTFD:
+ case SPECIALFD_EVENTFD: {
+ struct specialfd_eventfd *ae;
+
ae = arg;
if ((ae->flags & EFD_CLOEXEC) != 0)
fflags |= O_CLOEXEC;
error = eventfd_create_file(td, fp, ae->initval, ae->flags);
break;
+ }
+ case SPECIALFD_INOTIFY: {
+ struct specialfd_inotify *si;
+
+ si = arg;
+ error = inotify_create_file(td, fp, si->flags, &fflags);
+ break;
+ }
default:
- error = EINVAL;
+ error = EXTERROR(EINVAL, "invalid type", type);
break;
}
@@ -970,13 +987,14 @@ kern_specialfd(struct thread *td, int type, void *arg)
int
sys___specialfd(struct thread *td, struct __specialfd_args *args)
{
- struct specialfd_eventfd ae;
int error;
switch (args->type) {
- case SPECIALFD_EVENTFD:
+ case SPECIALFD_EVENTFD: {
+ struct specialfd_eventfd ae;
+
if (args->len != sizeof(struct specialfd_eventfd)) {
- error = EINVAL;
+ error = EXTERROR(EINVAL, "eventfd params ABI");
break;
}
error = copyin(args->req, &ae, sizeof(ae));
@@ -984,13 +1002,27 @@ sys___specialfd(struct thread *td, struct __specialfd_args *args)
break;
if ((ae.flags & ~(EFD_CLOEXEC | EFD_NONBLOCK |
EFD_SEMAPHORE)) != 0) {
- error = EINVAL;
+ error = EXTERROR(EINVAL, "reserved flag");
break;
}
error = kern_specialfd(td, args->type, &ae);
break;
+ }
+ case SPECIALFD_INOTIFY: {
+ struct specialfd_inotify si;
+
+ if (args->len != sizeof(si)) {
+ error = EINVAL;
+ break;
+ }
+ error = copyin(args->req, &si, sizeof(si));
+ if (error != 0)
+ break;
+ error = kern_specialfd(td, args->type, &si);
+ break;
+ }
default:
- error = EINVAL;
+ error = EXTERROR(EINVAL, "unknown type", args->type);
break;
}
return (error);
@@ -1166,7 +1198,7 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
int error, lf, ndu;
if (nd < 0)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "negative ndescs"));
fdp = td->td_proc->p_fd;
ndu = nd;
lf = fdp->fd_nfiles;
@@ -1259,7 +1291,7 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
rtv = *tvp;
if (rtv.tv_sec < 0 || rtv.tv_usec < 0 ||
rtv.tv_usec >= 1000000) {
- error = EINVAL;
+ error = EXTERROR(EINVAL, "invalid timeval");
goto done;
}
if (!timevalisset(&rtv))
@@ -1491,7 +1523,7 @@ sys_poll(struct thread *td, struct poll_args *uap)
if (uap->timeout != INFTIM) {
if (uap->timeout < 0)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "invalid timeout"));
ts.tv_sec = uap->timeout / 1000;
ts.tv_nsec = (uap->timeout % 1000) * 1000000;
tsp = &ts;
@@ -1516,7 +1548,7 @@ kern_poll_kfds(struct thread *td, struct pollfd *kfds, u_int nfds,
precision = 0;
if (tsp != NULL) {
if (!timespecvalid_interval(tsp))
- return (EINVAL);
+ return (EXTERROR(EINVAL, "invalid timespec"));
if (tsp->tv_sec == 0 && tsp->tv_nsec == 0)
sbt = 0;
else {
@@ -1619,7 +1651,7 @@ kern_poll(struct thread *td, struct pollfd *ufds, u_int nfds,
int error;
if (kern_poll_maxfds(nfds))
- return (EINVAL);
+ return (EXTERROR(EINVAL, "too large nfds"));
if (nfds > nitems(stackfds))
kfds = mallocarray(nfds, sizeof(*kfds), M_TEMP, M_WAITOK);
else
@@ -1796,7 +1828,7 @@ selsocket(struct socket *so, int events, struct timeval *tvp, struct thread *td)
rtv = *tvp;
if (rtv.tv_sec < 0 || rtv.tv_usec < 0 ||
rtv.tv_usec >= 1000000)
- return (EINVAL);
+ return (EXTERROR(EINVAL, "invalid timeval"));
if (!timevalisset(&rtv))
asbt = 0;
else if (rtv.tv_sec <= INT32_MAX) {
@@ -2173,7 +2205,7 @@ kern_kcmp(struct thread *td, pid_t pid1, pid_t pid2, int type,
(uintptr_t)p2->p_vmspace);
break;
default:
- error = EINVAL;
+ error = EXTERROR(EINVAL, "unknown op");
break;
}
@@ -2277,6 +2309,12 @@ sys_exterrctl(struct thread *td, struct exterrctl_args *uap)
return (EINVAL);
td->td_pflags2 &= ~TDP2_UEXTERR;
return (0);
+ case EXTERRCTL_UD:
+ /*
+ * Important: this code must always return EINVAL and never any
+ * extended error, for testing purposes.
+ */
+ /* FALLTHROUGH */
default:
return (EINVAL);
}
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index 9340779918a2..ed651da96b14 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -548,7 +548,7 @@ sys_pipe2(struct thread *td, struct pipe2_args *uap)
{
int error, fildes[2];
- if (uap->flags & ~(O_CLOEXEC | O_NONBLOCK))
+ if ((uap->flags & ~(O_CLOEXEC | O_CLOFORK | O_NONBLOCK)) != 0)
return (EINVAL);
error = kern_pipe(td, fildes, uap->flags, NULL, NULL);
if (error)
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index fa36cc824078..90a4f3a7dad8 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -598,4 +598,6 @@ const char *syscallnames[] = {
"fchroot", /* 590 = fchroot */
"setcred", /* 591 = setcred */
"exterrctl", /* 592 = exterrctl */
+ "inotify_add_watch_at", /* 593 = inotify_add_watch_at */
+ "inotify_rm_watch", /* 594 = inotify_rm_watch */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 08b557a7a540..90559fab6086 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3349,11 +3349,26 @@
size_t size
);
}
-592 AUE_NULL STD {
+592 AUE_NULL STD|CAPENABLED {
int exterrctl(
u_int op,
u_int flags,
_In_reads_bytes_(4) void *ptr
);
}
+593 AUE_INOTIFY STD|CAPENABLED {
+ int inotify_add_watch_at(
+ int fd,
+ int dfd,
+ _In_z_ const char *path,
+ uint32_t mask
+ );
+ }
+594 AUE_INOTIFY STD|CAPENABLED {
+ int inotify_rm_watch(
+ int fd,
+ int wd
+ );
+ }
+
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
index 15789d3eb5fa..90b21616a558 100644
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3482,6 +3482,24 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 3;
break;
}
+ /* inotify_add_watch_at */
+ case 593: {
+ struct inotify_add_watch_at_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ iarg[a++] = p->dfd; /* int */
+ uarg[a++] = (intptr_t)p->path; /* const char * */
+ uarg[a++] = p->mask; /* uint32_t */
+ *n_args = 4;
+ break;
+ }
+ /* inotify_rm_watch */
+ case 594: {
+ struct inotify_rm_watch_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ iarg[a++] = p->wd; /* int */
+ *n_args = 2;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9317,6 +9335,38 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
};
break;
+ /* inotify_add_watch_at */
+ case 593:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const char *";
+ break;
+ case 3:
+ p = "uint32_t";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* inotify_rm_watch */
+ case 594:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11305,6 +11355,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* inotify_add_watch_at */
+ case 593:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* inotify_rm_watch */
+ case 594:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c
index 11141d197aec..a545a0a54c25 100644
--- a/sys/kern/sysv_msg.c
+++ b/sys/kern/sysv_msg.c
@@ -1724,7 +1724,7 @@ freebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
return (sys_msgsys(td, (struct msgsys_args *)uap));
}
#else
- return (nosys(td, NULL));
+ return (kern_nosys(td, 0));
#endif
}
diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c
index e399517010fc..a99e1a4de14e 100644
--- a/sys/kern/sysv_sem.c
+++ b/sys/kern/sysv_sem.c
@@ -1904,7 +1904,7 @@ freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap)
return (sys_semsys(td, (struct semsys_args *)uap));
}
#else
- return (nosys(td, NULL));
+ return (kern_nosys(td, 0));
#endif
}
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c
index 60e3fe92a4b7..8d1a469127c6 100644
--- a/sys/kern/sysv_shm.c
+++ b/sys/kern/sysv_shm.c
@@ -1474,7 +1474,7 @@ freebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap)
return (EINVAL);
}
#else
- return (nosys(td, NULL));
+ return (kern_nosys(td, 0));
#endif
}
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index ad8485028987..133724ac76c5 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -151,6 +151,10 @@ kern_socket(struct thread *td, int domain, int type, int protocol)
type &= ~SOCK_CLOEXEC;
oflag |= O_CLOEXEC;
}
+ if ((type & SOCK_CLOFORK) != 0) {
+ type &= ~SOCK_CLOFORK;
+ oflag |= O_CLOFORK;
+ }
if ((type & SOCK_NONBLOCK) != 0) {
type &= ~SOCK_NONBLOCK;
fflag |= FNONBLOCK;
@@ -352,7 +356,8 @@ kern_accept4(struct thread *td, int s, struct sockaddr *sa, int flags,
goto done;
#endif
error = falloc_caps(td, &nfp, &fd,
- (flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps);
+ ((flags & SOCK_CLOEXEC) != 0 ? O_CLOEXEC : 0) |
+ ((flags & SOCK_CLOFORK) != 0 ? O_CLOFORK : 0), &fcaps);
if (error != 0)
goto done;
SOCK_LOCK(head);
@@ -435,7 +440,7 @@ int
sys_accept4(struct thread *td, struct accept4_args *uap)
{
- if (uap->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+ if ((uap->flags & ~(SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK)) != 0)
return (EINVAL);
return (accept1(td, uap->s, uap->name, uap->anamelen, uap->flags));
@@ -557,6 +562,10 @@ kern_socketpair(struct thread *td, int domain, int type, int protocol,
type &= ~SOCK_CLOEXEC;
oflag |= O_CLOEXEC;
}
+ if ((type & SOCK_CLOFORK) != 0) {
+ type &= ~SOCK_CLOFORK;
+ oflag |= O_CLOFORK;
+ }
if ((type & SOCK_NONBLOCK) != 0) {
type &= ~SOCK_NONBLOCK;
fflag |= FNONBLOCK;
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 72bd0246db11..0056dac65c7d 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -3463,7 +3463,8 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags)
UNP_LINK_UNLOCK_ASSERT();
- fdflags = (flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
+ fdflags = ((flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0) |
+ ((flags & MSG_CMSG_CLOFORK) ? O_CLOFORK : 0);
error = 0;
if (controlp != NULL) /* controlp == NULL => free control messages */
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index 97dc854c9386..02973146068d 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -301,7 +301,7 @@ static TAILQ_HEAD(,kaiocb) aio_jobs; /* (c) Async job list */
static struct unrhdr *aiod_unr;
static void aio_biocleanup(struct bio *bp);
-void aio_init_aioinfo(struct proc *p);
+static int aio_init_aioinfo(struct proc *p);
static int aio_onceonly(void);
static int aio_free_entry(struct kaiocb *job);
static void aio_process_rw(struct kaiocb *job);
@@ -309,7 +309,7 @@ static void aio_process_sync(struct kaiocb *job);
static void aio_process_mlock(struct kaiocb *job);
static void aio_schedule_fsync(void *context, int pending);
static int aio_newproc(int *);
-int aio_aqueue(struct thread *td, struct aiocb *ujob,
+static int aio_aqueue(struct thread *td, struct aiocb *ujob,
struct aioliojob *lio, int type, struct aiocb_ops *ops);
static int aio_queue_file(struct file *fp, struct kaiocb *job);
static void aio_biowakeup(struct bio *bp);
@@ -422,10 +422,11 @@ aio_onceonly(void)
* Init the per-process aioinfo structure. The aioinfo limits are set
* per-process for user limit (resource) management.
*/
-void
+static int
aio_init_aioinfo(struct proc *p)
{
struct kaioinfo *ki;
+ int error;
ki = uma_zalloc(kaio_zone, M_WAITOK);
mtx_init(&ki->kaio_mtx, "aiomtx", NULL, MTX_DEF | MTX_NEW);
@@ -451,8 +452,20 @@ aio_init_aioinfo(struct proc *p)
uma_zfree(kaio_zone, ki);
}
- while (num_aio_procs < MIN(target_aio_procs, max_aio_procs))
- aio_newproc(NULL);
+ error = 0;
+ while (num_aio_procs < MIN(target_aio_procs, max_aio_procs)) {
+ error = aio_newproc(NULL);
+ if (error != 0) {
+ /*
+ * At least one worker is enough to have AIO
+ * functional. Clear error in that case.
+ */
+ if (num_aio_procs > 0)
+ error = 0;
+ break;
+ }
+ }
+ return (error);
}
static int
@@ -1476,7 +1489,7 @@ static struct aiocb_ops aiocb_ops_osigevent = {
* Queue a new AIO request. Choosing either the threaded or direct bio VCHR
* technique is done in this code.
*/
-int
+static int
aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj,
int type, struct aiocb_ops *ops)
{
@@ -1490,8 +1503,11 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj,
int fd, kqfd;
u_short evflags;
- if (p->p_aioinfo == NULL)
- aio_init_aioinfo(p);
+ if (p->p_aioinfo == NULL) {
+ error = aio_init_aioinfo(p);
+ if (error != 0)
+ goto err1;
+ }
ki = p->p_aioinfo;
@@ -2213,8 +2229,11 @@ kern_lio_listio(struct thread *td, int mode, struct aiocb * const *uacb_list,
if (nent < 0 || nent > max_aio_queue_per_proc)
return (EINVAL);
- if (p->p_aioinfo == NULL)
- aio_init_aioinfo(p);
+ if (p->p_aioinfo == NULL) {
+ error = aio_init_aioinfo(p);
+ if (error != 0)
+ return (error);
+ }
ki = p->p_aioinfo;
@@ -2503,8 +2522,11 @@ kern_aio_waitcomplete(struct thread *td, struct aiocb **ujobp,
timo = tvtohz(&atv);
}
- if (p->p_aioinfo == NULL)
- aio_init_aioinfo(p);
+ if (p->p_aioinfo == NULL) {
+ error = aio_init_aioinfo(p);
+ if (error != 0)
+ return (error);
+ }
ki = p->p_aioinfo;
error = 0;
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 883beaf6d1da..89c1d779f04c 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -41,6 +41,7 @@
#include <sys/counter.h>
#include <sys/filedesc.h>
#include <sys/fnv_hash.h>
+#include <sys/inotify.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/lock.h>
@@ -331,7 +332,8 @@ SDT_PROBE_DEFINE2(vfs, namecache, evict_negative, done, "struct vnode *",
"char *");
SDT_PROBE_DEFINE1(vfs, namecache, symlink, alloc__fail, "size_t");
-SDT_PROBE_DEFINE3(vfs, fplookup, lookup, done, "struct nameidata", "int", "bool");
+SDT_PROBE_DEFINE3(vfs, fplookup, lookup, done, "struct nameidata *", "int",
+ "enum cache_fpl_status");
SDT_PROBE_DECLARE(vfs, namei, lookup, entry);
SDT_PROBE_DECLARE(vfs, namei, lookup, return);
@@ -2629,6 +2631,14 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp,
atomic_store_ptr(&dvp->v_cache_dd, ncp);
} else if (vp != NULL) {
/*
+ * Take the slow path in INOTIFY(). This flag will be lazily
+ * cleared by cache_vop_inotify() once all directories referring
+ * to vp are unwatched.
+ */
+ if (__predict_false((vn_irflag_read(dvp) & VIRF_INOTIFY) != 0))
+ vn_irflag_set_cond(vp, VIRF_INOTIFY_PARENT);
+
+ /*
* For this case, the cache entry maps both the
* directory name in it and the name ".." for the
* directory's parent.
@@ -4008,6 +4018,56 @@ out:
return (error);
}
+void
+cache_vop_inotify(struct vnode *vp, int event, uint32_t cookie)
+{
+ struct mtx *vlp;
+ struct namecache *ncp;
+ int isdir;
+ bool logged, self;
+
+ isdir = vp->v_type == VDIR ? IN_ISDIR : 0;
+ self = (vn_irflag_read(vp) & VIRF_INOTIFY) != 0 &&
+ (vp->v_type != VDIR || (event & ~_IN_DIR_EVENTS) != 0);
+
+ if (self) {
+ int selfevent;
+
+ if (event == _IN_ATTRIB_LINKCOUNT)
+ selfevent = IN_ATTRIB;
+ else
+ selfevent = event;
+ inotify_log(vp, NULL, 0, selfevent | isdir, cookie);
+ }
+ if ((event & IN_ALL_EVENTS) == 0)
+ return;
+
+ logged = false;
+ vlp = VP2VNODELOCK(vp);
+ mtx_lock(vlp);
+ TAILQ_FOREACH(ncp, &vp->v_cache_dst, nc_dst) {
+ if ((ncp->nc_flag & NCF_ISDOTDOT) != 0)
+ continue;
+ if ((vn_irflag_read(ncp->nc_dvp) & VIRF_INOTIFY) != 0) {
+ /*
+ * XXX-MJ if the vnode has two links in the same
+ * dir, we'll log the same event twice.
+ */
+ inotify_log(ncp->nc_dvp, ncp->nc_name, ncp->nc_nlen,
+ event | isdir, cookie);
+ logged = true;
+ }
+ }
+ if (!logged && (vn_irflag_read(vp) & VIRF_INOTIFY_PARENT) != 0) {
+ /*
+ * We didn't find a watched directory that contains this vnode,
+ * so stop calling VOP_INOTIFY for operations on the vnode.
+ */
+ vn_irflag_unset(vp, VIRF_INOTIFY_PARENT);
+ }
+ mtx_unlock(vlp);
+}
+
#ifdef DDB
static void
db_print_vpath(struct vnode *vp)
@@ -6361,15 +6421,11 @@ out:
cache_fpl_smr_assert_not_entered(&fpl);
cache_fpl_assert_status(&fpl);
*status = fpl.status;
- if (SDT_PROBES_ENABLED()) {
- SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status);
- if (fpl.status == CACHE_FPL_STATUS_HANDLED)
- SDT_PROBE4(vfs, namei, lookup, return, error, ndp->ni_vp, true,
- ndp);
- }
-
+ SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status);
if (__predict_true(fpl.status == CACHE_FPL_STATUS_HANDLED)) {
MPASS(error != CACHE_FPL_FAILED);
+ SDT_PROBE4(vfs, namei, lookup, return, error, ndp->ni_vp, true,
+ ndp);
if (error != 0) {
cache_fpl_cleanup_cnp(fpl.cnp);
MPASS(fpl.dvp == NULL);
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index be49c0887609..fd6202a1424c 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -39,6 +39,7 @@
#include <sys/conf.h>
#include <sys/event.h>
#include <sys/filio.h>
+#include <sys/inotify.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/lock.h>
@@ -119,6 +120,8 @@ struct vop_vector default_vnodeops = {
.vop_getwritemount = vop_stdgetwritemount,
.vop_inactive = VOP_NULL,
.vop_need_inactive = vop_stdneed_inactive,
+ .vop_inotify = vop_stdinotify,
+ .vop_inotify_add_watch = vop_stdinotify_add_watch,
.vop_ioctl = vop_stdioctl,
.vop_kqfilter = vop_stdkqfilter,
.vop_islocked = vop_stdislocked,
@@ -453,6 +456,7 @@ vop_stdpathconf(struct vop_pathconf_args *ap)
case _PC_MAC_PRESENT:
case _PC_NAMEDATTR_ENABLED:
case _PC_HAS_NAMEDATTR:
+ case _PC_HAS_HIDDENSYSTEM:
*ap->a_retval = 0;
return (0);
default:
@@ -1306,6 +1310,20 @@ vop_stdneed_inactive(struct vop_need_inactive_args *ap)
}
int
+vop_stdinotify(struct vop_inotify_args *ap)
+{
+ vn_inotify(ap->a_vp, ap->a_dvp, ap->a_cnp, ap->a_event, ap->a_cookie);
+ return (0);
+}
+
+int
+vop_stdinotify_add_watch(struct vop_inotify_add_watch_args *ap)
+{
+ return (vn_inotify_add_watch(ap->a_vp, ap->a_sc, ap->a_mask,
+ ap->a_wdp, ap->a_td));
+}
+
+int
vop_stdioctl(struct vop_ioctl_args *ap)
{
struct vnode *vp;
diff --git a/sys/kern/vfs_inotify.c b/sys/kern/vfs_inotify.c
new file mode 100644
index 000000000000..d3cd0d1f9832
--- /dev/null
+++ b/sys/kern/vfs_inotify.c
@@ -0,0 +1,1011 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Klara, Inc.
+ */
+
+#include "opt_ktrace.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/caprights.h>
+#include <sys/counter.h>
+#include <sys/dirent.h>
+#define EXTERR_CATEGORY EXTERR_CAT_INOTIFY
+#include <sys/exterrvar.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filio.h>
+#include <sys/inotify.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/ktrace.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/resourcevar.h>
+#include <sys/selinfo.h>
+#include <sys/stat.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/syslimits.h>
+#include <sys/sysproto.h>
+#include <sys/tree.h>
+#include <sys/user.h>
+#include <sys/vnode.h>
+
+uint32_t inotify_rename_cookie;
+
+static SYSCTL_NODE(_vfs, OID_AUTO, inotify, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ "inotify configuration");
+
+static int inotify_max_queued_events = 16384;
+SYSCTL_INT(_vfs_inotify, OID_AUTO, max_queued_events, CTLFLAG_RWTUN,
+ &inotify_max_queued_events, 0,
+ "Maximum number of events to queue on an inotify descriptor");
+
+static int inotify_max_user_instances = 256;
+SYSCTL_INT(_vfs_inotify, OID_AUTO, max_user_instances, CTLFLAG_RWTUN,
+ &inotify_max_user_instances, 0,
+ "Maximum number of inotify descriptors per user");
+
+static int inotify_max_user_watches;
+SYSCTL_INT(_vfs_inotify, OID_AUTO, max_user_watches, CTLFLAG_RWTUN,
+ &inotify_max_user_watches, 0,
+ "Maximum number of inotify watches per user");
+
+static int inotify_max_watches;
+SYSCTL_INT(_vfs_inotify, OID_AUTO, max_watches, CTLFLAG_RWTUN,
+ &inotify_max_watches, 0,
+ "Maximum number of inotify watches system-wide");
+
+static int inotify_watches;
+SYSCTL_INT(_vfs_inotify, OID_AUTO, watches, CTLFLAG_RD,
+ &inotify_watches, 0,
+ "Total number of inotify watches currently in use");
+
+static int inotify_coalesce = 1;
+SYSCTL_INT(_vfs_inotify, OID_AUTO, coalesce, CTLFLAG_RWTUN,
+ &inotify_coalesce, 0,
+ "Coalesce inotify events when possible");
+
+static COUNTER_U64_DEFINE_EARLY(inotify_event_drops);
+SYSCTL_COUNTER_U64(_vfs_inotify, OID_AUTO, event_drops, CTLFLAG_RD,
+ &inotify_event_drops,
+ "Number of inotify events dropped due to limits or allocation failures");
+
+static fo_rdwr_t inotify_read;
+static fo_ioctl_t inotify_ioctl;
+static fo_poll_t inotify_poll;
+static fo_kqfilter_t inotify_kqfilter;
+static fo_stat_t inotify_stat;
+static fo_close_t inotify_close;
+static fo_fill_kinfo_t inotify_fill_kinfo;
+
+static const struct fileops inotifyfdops = {
+ .fo_read = inotify_read,
+ .fo_write = invfo_rdwr,
+ .fo_truncate = invfo_truncate,
+ .fo_ioctl = inotify_ioctl,
+ .fo_poll = inotify_poll,
+ .fo_kqfilter = inotify_kqfilter,
+ .fo_stat = inotify_stat,
+ .fo_close = inotify_close,
+ .fo_chmod = invfo_chmod,
+ .fo_chown = invfo_chown,
+ .fo_sendfile = invfo_sendfile,
+ .fo_fill_kinfo = inotify_fill_kinfo,
+ .fo_cmp = file_kcmp_generic,
+ .fo_flags = DFLAG_PASSABLE,
+};
+
+static void filt_inotifydetach(struct knote *kn);
+static int filt_inotifyevent(struct knote *kn, long hint);
+
+static const struct filterops inotify_rfiltops = {
+ .f_isfd = 1,
+ .f_detach = filt_inotifydetach,
+ .f_event = filt_inotifyevent,
+};
+
+static MALLOC_DEFINE(M_INOTIFY, "inotify", "inotify data structures");
+
+struct inotify_record {
+ STAILQ_ENTRY(inotify_record) link;
+ struct inotify_event ev;
+};
+
+static uint64_t inotify_ino = 1;
+
+/*
+ * On LP64 systems this occupies 64 bytes, so we don't get internal
+ * fragmentation by allocating watches with malloc(9). If the size changes,
+ * consider using a UMA zone to improve memory efficiency.
+ */
+struct inotify_watch {
+ struct inotify_softc *sc; /* back-pointer */
+ int wd; /* unique ID */
+ uint32_t mask; /* event mask */
+ struct vnode *vp; /* vnode being watched, refed */
+ RB_ENTRY(inotify_watch) ilink; /* inotify linkage */
+ TAILQ_ENTRY(inotify_watch) vlink; /* vnode linkage */
+};
+
+static void
+inotify_init(void *arg __unused)
+{
+ /* Don't let a user hold too many vnodes. */
+ inotify_max_user_watches = desiredvnodes / 3;
+ /* Don't let the system hold too many vnodes. */
+ inotify_max_watches = desiredvnodes / 2;
+}
+SYSINIT(inotify, SI_SUB_VFS, SI_ORDER_ANY, inotify_init, NULL);
+
+static int
+inotify_watch_cmp(const struct inotify_watch *a,
+ const struct inotify_watch *b)
+{
+ if (a->wd < b->wd)
+ return (-1);
+ else if (a->wd > b->wd)
+ return (1);
+ else
+ return (0);
+}
+RB_HEAD(inotify_watch_tree, inotify_watch);
+RB_GENERATE_STATIC(inotify_watch_tree, inotify_watch, ilink, inotify_watch_cmp);
+
+struct inotify_softc {
+ struct mtx lock; /* serialize all softc writes */
+ STAILQ_HEAD(, inotify_record) pending; /* events waiting to be read */
+ struct inotify_record overflow; /* preallocated record */
+ int nextwatch; /* next watch ID to try */
+ int npending; /* number of pending events */
+ size_t nbpending; /* bytes available to read */
+ uint64_t ino; /* unique identifier */
+ struct inotify_watch_tree watches; /* active watches */
+ struct selinfo sel; /* select/poll/kevent info */
+ struct ucred *cred; /* credential ref */
+};
+
+static struct inotify_record *
+inotify_dequeue(struct inotify_softc *sc)
+{
+ struct inotify_record *rec;
+
+ mtx_assert(&sc->lock, MA_OWNED);
+ KASSERT(!STAILQ_EMPTY(&sc->pending),
+ ("%s: queue for %p is empty", __func__, sc));
+
+ rec = STAILQ_FIRST(&sc->pending);
+ STAILQ_REMOVE_HEAD(&sc->pending, link);
+ sc->npending--;
+ sc->nbpending -= sizeof(rec->ev) + rec->ev.len;
+ return (rec);
+}
+
+static void
+inotify_enqueue(struct inotify_softc *sc, struct inotify_record *rec, bool head)
+{
+ mtx_assert(&sc->lock, MA_OWNED);
+
+ if (head)
+ STAILQ_INSERT_HEAD(&sc->pending, rec, link);
+ else
+ STAILQ_INSERT_TAIL(&sc->pending, rec, link);
+ sc->npending++;
+ sc->nbpending += sizeof(rec->ev) + rec->ev.len;
+}
+
+static int
+inotify_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags,
+ struct thread *td)
+{
+ struct inotify_softc *sc;
+ struct inotify_record *rec;
+ int error;
+ bool first;
+
+ sc = fp->f_data;
+ error = 0;
+
+ mtx_lock(&sc->lock);
+ while (STAILQ_EMPTY(&sc->pending)) {
+ if ((flags & IO_NDELAY) != 0 || (fp->f_flag & FNONBLOCK) != 0) {
+ mtx_unlock(&sc->lock);
+ return (EWOULDBLOCK);
+ }
+ error = msleep(&sc->pending, &sc->lock, PCATCH, "inotify", 0);
+ if (error != 0) {
+ mtx_unlock(&sc->lock);
+ return (error);
+ }
+ }
+ for (first = true; !STAILQ_EMPTY(&sc->pending); first = false) {
+ size_t len;
+
+ rec = inotify_dequeue(sc);
+ len = sizeof(rec->ev) + rec->ev.len;
+ if (uio->uio_resid < (ssize_t)len) {
+ inotify_enqueue(sc, rec, true);
+ if (first) {
+ error = EXTERROR(EINVAL,
+ "read buffer is too small");
+ }
+ break;
+ }
+ mtx_unlock(&sc->lock);
+ error = uiomove(&rec->ev, len, uio);
+#ifdef KTRACE
+ if (error == 0 && KTRPOINT(td, KTR_STRUCT))
+ ktrstruct("inotify", &rec->ev, len);
+#endif
+ mtx_lock(&sc->lock);
+ if (error != 0) {
+ inotify_enqueue(sc, rec, true);
+ mtx_unlock(&sc->lock);
+ return (error);
+ }
+ if (rec == &sc->overflow) {
+ /*
+ * Signal to inotify_queue_record() that the overflow
+ * record can be reused.
+ */
+ memset(rec, 0, sizeof(*rec));
+ } else {
+ free(rec, M_INOTIFY);
+ }
+ }
+ mtx_unlock(&sc->lock);
+ return (error);
+}
+
+static int
+inotify_ioctl(struct file *fp, u_long com, void *data, struct ucred *cred,
+ struct thread *td)
+{
+ struct inotify_softc *sc;
+
+ sc = fp->f_data;
+
+ switch (com) {
+ case FIONREAD:
+ *(int *)data = (int)sc->nbpending;
+ return (0);
+ case FIONBIO:
+ case FIOASYNC:
+ return (0);
+ default:
+ return (ENOTTY);
+ }
+
+ return (0);
+}
+
+static int
+inotify_poll(struct file *fp, int events, struct ucred *cred, struct thread *td)
+{
+ struct inotify_softc *sc;
+ int revents;
+
+ sc = fp->f_data;
+ revents = 0;
+
+ mtx_lock(&sc->lock);
+ if ((events & (POLLIN | POLLRDNORM)) != 0 && sc->npending > 0)
+ revents |= events & (POLLIN | POLLRDNORM);
+ else
+ selrecord(td, &sc->sel);
+ mtx_unlock(&sc->lock);
+ return (revents);
+}
+
+static void
+filt_inotifydetach(struct knote *kn)
+{
+ struct inotify_softc *sc;
+
+ sc = kn->kn_hook;
+ knlist_remove(&sc->sel.si_note, kn, 0);
+}
+
+static int
+filt_inotifyevent(struct knote *kn, long hint)
+{
+ struct inotify_softc *sc;
+
+ sc = kn->kn_hook;
+ mtx_assert(&sc->lock, MA_OWNED);
+ kn->kn_data = sc->nbpending;
+ return (kn->kn_data > 0);
+}
+
+static int
+inotify_kqfilter(struct file *fp, struct knote *kn)
+{
+ struct inotify_softc *sc;
+
+ if (kn->kn_filter != EVFILT_READ)
+ return (EINVAL);
+ sc = fp->f_data;
+ kn->kn_fop = &inotify_rfiltops;
+ kn->kn_hook = sc;
+ knlist_add(&sc->sel.si_note, kn, 0);
+ return (0);
+}
+
+static int
+inotify_stat(struct file *fp, struct stat *sb, struct ucred *cred)
+{
+ struct inotify_softc *sc;
+
+ sc = fp->f_data;
+
+ memset(sb, 0, sizeof(*sb));
+ sb->st_mode = S_IFREG | S_IRUSR;
+ sb->st_blksize = sizeof(struct inotify_event) + _IN_NAMESIZE(NAME_MAX);
+ mtx_lock(&sc->lock);
+ sb->st_size = sc->nbpending;
+ sb->st_blocks = sc->npending;
+ sb->st_uid = sc->cred->cr_ruid;
+ sb->st_gid = sc->cred->cr_rgid;
+ sb->st_ino = sc->ino;
+ mtx_unlock(&sc->lock);
+ return (0);
+}
+
+static void
+inotify_unlink_watch_locked(struct inotify_softc *sc, struct inotify_watch *watch)
+{
+ struct vnode *vp;
+
+ vp = watch->vp;
+ mtx_assert(&vp->v_pollinfo->vpi_lock, MA_OWNED);
+
+ atomic_subtract_int(&inotify_watches, 1);
+ (void)chginotifywatchcnt(sc->cred->cr_ruidinfo, -1, 0);
+
+ TAILQ_REMOVE(&vp->v_pollinfo->vpi_inotify, watch, vlink);
+ if (TAILQ_EMPTY(&vp->v_pollinfo->vpi_inotify))
+ vn_irflag_unset(vp, VIRF_INOTIFY);
+}
+
+/*
+ * Assumes that the watch has already been removed from its softc.
+ */
+static void
+inotify_remove_watch(struct inotify_watch *watch)
+{
+ struct inotify_softc *sc;
+ struct vnode *vp;
+
+ sc = watch->sc;
+
+ vp = watch->vp;
+ mtx_lock(&vp->v_pollinfo->vpi_lock);
+ inotify_unlink_watch_locked(sc, watch);
+ mtx_unlock(&vp->v_pollinfo->vpi_lock);
+
+ vrele(vp);
+ free(watch, M_INOTIFY);
+}
+
+static int
+inotify_close(struct file *fp, struct thread *td)
+{
+ struct inotify_softc *sc;
+ struct inotify_record *rec;
+ struct inotify_watch *watch;
+
+ sc = fp->f_data;
+
+ mtx_lock(&sc->lock);
+ (void)chginotifycnt(sc->cred->cr_ruidinfo, -1, 0);
+ while ((watch = RB_MIN(inotify_watch_tree, &sc->watches)) != NULL) {
+ RB_REMOVE(inotify_watch_tree, &sc->watches, watch);
+ mtx_unlock(&sc->lock);
+ inotify_remove_watch(watch);
+ mtx_lock(&sc->lock);
+ }
+ while (!STAILQ_EMPTY(&sc->pending)) {
+ rec = inotify_dequeue(sc);
+ if (rec != &sc->overflow)
+ free(rec, M_INOTIFY);
+ }
+ mtx_unlock(&sc->lock);
+ seldrain(&sc->sel);
+ knlist_destroy(&sc->sel.si_note);
+ mtx_destroy(&sc->lock);
+ crfree(sc->cred);
+ free(sc, M_INOTIFY);
+ return (0);
+}
+
+static int
+inotify_fill_kinfo(struct file *fp, struct kinfo_file *kif,
+ struct filedesc *fdp)
+{
+ struct inotify_softc *sc;
+
+ sc = fp->f_data;
+
+ kif->kf_type = KF_TYPE_INOTIFY;
+ kif->kf_un.kf_inotify.kf_inotify_npending = sc->npending;
+ kif->kf_un.kf_inotify.kf_inotify_nbpending = sc->nbpending;
+ return (0);
+}
+
+int
+inotify_create_file(struct thread *td, struct file *fp, int flags, int *fflagsp)
+{
+ struct inotify_softc *sc;
+ int fflags;
+
+ if ((flags & ~(IN_NONBLOCK | IN_CLOEXEC)) != 0)
+ return (EINVAL);
+
+ if (!chginotifycnt(td->td_ucred->cr_ruidinfo, 1,
+ inotify_max_user_instances))
+ return (EMFILE);
+
+ sc = malloc(sizeof(*sc), M_INOTIFY, M_WAITOK | M_ZERO);
+ sc->nextwatch = 1; /* Required for compatibility. */
+ STAILQ_INIT(&sc->pending);
+ RB_INIT(&sc->watches);
+ mtx_init(&sc->lock, "inotify", NULL, MTX_DEF);
+ knlist_init_mtx(&sc->sel.si_note, &sc->lock);
+ sc->cred = crhold(td->td_ucred);
+ sc->ino = atomic_fetchadd_64(&inotify_ino, 1);
+
+ fflags = FREAD;
+ if ((flags & IN_NONBLOCK) != 0)
+ fflags |= FNONBLOCK;
+ if ((flags & IN_CLOEXEC) != 0)
+ *fflagsp |= O_CLOEXEC;
+ finit(fp, fflags, DTYPE_INOTIFY, sc, &inotifyfdops);
+
+ return (0);
+}
+
+static struct inotify_record *
+inotify_alloc_record(uint32_t wd, const char *name, size_t namelen, int event,
+ uint32_t cookie, int waitok)
+{
+ struct inotify_event *evp;
+ struct inotify_record *rec;
+
+ rec = malloc(sizeof(*rec) + _IN_NAMESIZE(namelen), M_INOTIFY,
+ waitok | M_ZERO);
+ if (rec == NULL)
+ return (NULL);
+ evp = &rec->ev;
+ evp->wd = wd;
+ evp->mask = event;
+ evp->cookie = cookie;
+ evp->len = _IN_NAMESIZE(namelen);
+ if (name != NULL)
+ memcpy(evp->name, name, namelen);
+ return (rec);
+}
+
+static bool
+inotify_can_coalesce(struct inotify_softc *sc, struct inotify_event *evp)
+{
+ struct inotify_record *prev;
+
+ mtx_assert(&sc->lock, MA_OWNED);
+
+ prev = STAILQ_LAST(&sc->pending, inotify_record, link);
+ return (prev != NULL && prev->ev.mask == evp->mask &&
+ prev->ev.wd == evp->wd && prev->ev.cookie == evp->cookie &&
+ prev->ev.len == evp->len &&
+ memcmp(prev->ev.name, evp->name, evp->len) == 0);
+}
+
+static void
+inotify_overflow_event(struct inotify_event *evp)
+{
+ evp->mask = IN_Q_OVERFLOW;
+ evp->wd = -1;
+ evp->cookie = 0;
+ evp->len = 0;
+}
+
+/*
+ * Put an event record on the queue for an inotify desscriptor. Return false if
+ * the record was not enqueued for some reason, true otherwise.
+ */
+static bool
+inotify_queue_record(struct inotify_softc *sc, struct inotify_record *rec)
+{
+ struct inotify_event *evp;
+
+ mtx_assert(&sc->lock, MA_OWNED);
+
+ evp = &rec->ev;
+ if (__predict_false(rec == &sc->overflow)) {
+ /*
+ * Is the overflow record already in the queue? If so, there's
+ * not much else we can do: we're here because a kernel memory
+ * shortage prevented new record allocations.
+ */
+ counter_u64_add(inotify_event_drops, 1);
+ if (evp->mask == IN_Q_OVERFLOW)
+ return (false);
+ inotify_overflow_event(evp);
+ } else {
+ /* Try to coalesce duplicate events. */
+ if (inotify_coalesce && inotify_can_coalesce(sc, evp))
+ return (false);
+
+ /*
+ * Would this one overflow the queue? If so, convert it to an
+ * overflow event and try again to coalesce.
+ */
+ if (sc->npending >= inotify_max_queued_events) {
+ counter_u64_add(inotify_event_drops, 1);
+ inotify_overflow_event(evp);
+ if (inotify_can_coalesce(sc, evp))
+ return (false);
+ }
+ }
+ inotify_enqueue(sc, rec, false);
+ selwakeup(&sc->sel);
+ KNOTE_LOCKED(&sc->sel.si_note, 0);
+ wakeup(&sc->pending);
+ return (true);
+}
+
+static int
+inotify_log_one(struct inotify_watch *watch, const char *name, size_t namelen,
+ int event, uint32_t cookie)
+{
+ struct inotify_watch key;
+ struct inotify_softc *sc;
+ struct inotify_record *rec;
+ int relecount;
+ bool allocfail;
+
+ relecount = 0;
+
+ sc = watch->sc;
+ rec = inotify_alloc_record(watch->wd, name, namelen, event, cookie,
+ M_NOWAIT);
+ if (rec == NULL) {
+ rec = &sc->overflow;
+ allocfail = true;
+ } else {
+ allocfail = false;
+ }
+
+ mtx_lock(&sc->lock);
+ if (!inotify_queue_record(sc, rec) && rec != &sc->overflow)
+ free(rec, M_INOTIFY);
+ if ((watch->mask & IN_ONESHOT) != 0 ||
+ (event & (IN_DELETE_SELF | IN_UNMOUNT)) != 0) {
+ if (!allocfail) {
+ rec = inotify_alloc_record(watch->wd, NULL, 0,
+ IN_IGNORED, 0, M_NOWAIT);
+ if (rec == NULL)
+ rec = &sc->overflow;
+ if (!inotify_queue_record(sc, rec) &&
+ rec != &sc->overflow)
+ free(rec, M_INOTIFY);
+ }
+
+ /*
+ * Remove the watch, taking care to handle races with
+ * inotify_close().
+ */
+ key.wd = watch->wd;
+ if (RB_FIND(inotify_watch_tree, &sc->watches, &key) != NULL) {
+ RB_REMOVE(inotify_watch_tree, &sc->watches, watch);
+ inotify_unlink_watch_locked(sc, watch);
+ free(watch, M_INOTIFY);
+
+ /* Defer vrele() to until locks are dropped. */
+ relecount++;
+ }
+ }
+ mtx_unlock(&sc->lock);
+ return (relecount);
+}
+
+void
+inotify_log(struct vnode *vp, const char *name, size_t namelen, int event,
+ uint32_t cookie)
+{
+ struct inotify_watch *watch, *tmp;
+ int relecount;
+
+ KASSERT((event & ~(IN_ALL_EVENTS | IN_ISDIR | IN_UNMOUNT)) == 0,
+ ("inotify_log: invalid event %#x", event));
+
+ relecount = 0;
+ mtx_lock(&vp->v_pollinfo->vpi_lock);
+ TAILQ_FOREACH_SAFE(watch, &vp->v_pollinfo->vpi_inotify, vlink, tmp) {
+ KASSERT(watch->vp == vp,
+ ("inotify_log: watch %p vp != vp", watch));
+ if ((watch->mask & event) != 0 || event == IN_UNMOUNT) {
+ relecount += inotify_log_one(watch, name, namelen, event,
+ cookie);
+ }
+ }
+ mtx_unlock(&vp->v_pollinfo->vpi_lock);
+
+ for (int i = 0; i < relecount; i++)
+ vrele(vp);
+}
+
+/*
+ * An inotify event occurred on a watched vnode.
+ */
+void
+vn_inotify(struct vnode *vp, struct vnode *dvp, struct componentname *cnp,
+ int event, uint32_t cookie)
+{
+ int isdir;
+
+ VNPASS(vp->v_holdcnt > 0, vp);
+
+ isdir = vp->v_type == VDIR ? IN_ISDIR : 0;
+
+ if (dvp != NULL) {
+ VNPASS(dvp->v_holdcnt > 0, dvp);
+
+ /*
+ * Should we log an event for the vnode itself?
+ */
+ if ((vn_irflag_read(vp) & VIRF_INOTIFY) != 0) {
+ int selfevent;
+
+ switch (event) {
+ case _IN_MOVE_DELETE:
+ case IN_DELETE:
+ /*
+ * IN_DELETE_SELF is only generated when the
+ * last hard link of a file is removed.
+ */
+ selfevent = IN_DELETE_SELF;
+ if (vp->v_type != VDIR) {
+ struct vattr va;
+ int error;
+
+ error = VOP_GETATTR(vp, &va,
+ cnp->cn_cred);
+ if (error == 0 && va.va_nlink != 0)
+ selfevent = 0;
+ }
+ break;
+ case IN_MOVED_FROM:
+ cookie = 0;
+ selfevent = IN_MOVE_SELF;
+ break;
+ case _IN_ATTRIB_LINKCOUNT:
+ selfevent = IN_ATTRIB;
+ break;
+ default:
+ selfevent = event;
+ break;
+ }
+
+ if ((selfevent & ~_IN_DIR_EVENTS) != 0) {
+ inotify_log(vp, NULL, 0, selfevent | isdir,
+ cookie);
+ }
+ }
+
+ /*
+ * Something is watching the directory through which this vnode
+ * was referenced, so we may need to log the event.
+ */
+ if ((event & IN_ALL_EVENTS) != 0 &&
+ (vn_irflag_read(dvp) & VIRF_INOTIFY) != 0) {
+ inotify_log(dvp, cnp->cn_nameptr,
+ cnp->cn_namelen, event | isdir, cookie);
+ }
+ } else {
+ /*
+ * We don't know which watched directory might contain the
+ * vnode, so we have to fall back to searching the name cache.
+ */
+ cache_vop_inotify(vp, event, cookie);
+ }
+}
+
+int
+vn_inotify_add_watch(struct vnode *vp, struct inotify_softc *sc, uint32_t mask,
+ uint32_t *wdp, struct thread *td)
+{
+ struct inotify_watch *watch, *watch1;
+ uint32_t wd;
+
+ /*
+ * If this is a directory, make sure all of its entries are present in
+ * the name cache so that we're able to look them up if an event occurs.
+ * The persistent reference on the directory prevents the outgoing name
+ * cache entries from being reclaimed.
+ */
+ if (vp->v_type == VDIR) {
+ struct dirent *dp;
+ char *buf;
+ off_t off;
+ size_t buflen, len;
+ int eof, error;
+
+ buflen = 128 * sizeof(struct dirent);
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
+
+ error = 0;
+ len = off = eof = 0;
+ for (;;) {
+ struct nameidata nd;
+
+ error = vn_dir_next_dirent(vp, td, buf, buflen, &dp,
+ &len, &off, &eof);
+ if (error != 0)
+ break;
+ if (len == 0)
+ /* Finished reading. */
+ break;
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+
+ /*
+ * namei() consumes a reference on the starting
+ * directory if it's specified as a vnode.
+ */
+ vrefact(vp);
+ VOP_UNLOCK(vp);
+ NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE,
+ dp->d_name, vp);
+ error = namei(&nd);
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ if (error != 0)
+ break;
+ vn_irflag_set_cond(nd.ni_vp, VIRF_INOTIFY_PARENT);
+ vrele(nd.ni_vp);
+ }
+ free(buf, M_TEMP);
+ if (error != 0)
+ return (error);
+ }
+
+ /*
+ * The vnode referenced in kern_inotify_add_watch() might be different
+ * than this one if nullfs is in the picture.
+ */
+ vrefact(vp);
+ watch = malloc(sizeof(*watch), M_INOTIFY, M_WAITOK | M_ZERO);
+ watch->sc = sc;
+ watch->vp = vp;
+ watch->mask = mask;
+
+ /*
+ * Are we updating an existing watch? Search the vnode's list rather
+ * than that of the softc, as the former is likely to be shorter.
+ */
+ v_addpollinfo(vp);
+ mtx_lock(&vp->v_pollinfo->vpi_lock);
+ TAILQ_FOREACH(watch1, &vp->v_pollinfo->vpi_inotify, vlink) {
+ if (watch1->sc == sc)
+ break;
+ }
+ mtx_lock(&sc->lock);
+ if (watch1 != NULL) {
+ mtx_unlock(&vp->v_pollinfo->vpi_lock);
+
+ /*
+ * We found an existing watch, update it based on our flags.
+ */
+ if ((mask & IN_MASK_CREATE) != 0) {
+ mtx_unlock(&sc->lock);
+ vrele(vp);
+ free(watch, M_INOTIFY);
+ return (EEXIST);
+ }
+ if ((mask & IN_MASK_ADD) != 0)
+ watch1->mask |= mask;
+ else
+ watch1->mask = mask;
+ *wdp = watch1->wd;
+ mtx_unlock(&sc->lock);
+ vrele(vp);
+ free(watch, M_INOTIFY);
+ return (EJUSTRETURN);
+ }
+
+ /*
+ * We're creating a new watch. Add it to the softc and vnode watch
+ * lists.
+ */
+ do {
+ struct inotify_watch key;
+
+ /*
+ * Search for the next available watch descriptor. This is
+ * implemented so as to avoid reusing watch descriptors for as
+ * long as possible.
+ */
+ key.wd = wd = sc->nextwatch++;
+ watch1 = RB_FIND(inotify_watch_tree, &sc->watches, &key);
+ } while (watch1 != NULL || wd == 0);
+ watch->wd = wd;
+ RB_INSERT(inotify_watch_tree, &sc->watches, watch);
+ TAILQ_INSERT_TAIL(&vp->v_pollinfo->vpi_inotify, watch, vlink);
+ mtx_unlock(&sc->lock);
+ mtx_unlock(&vp->v_pollinfo->vpi_lock);
+ vn_irflag_set_cond(vp, VIRF_INOTIFY);
+
+ *wdp = wd;
+
+ return (0);
+}
+
+void
+vn_inotify_revoke(struct vnode *vp)
+{
+ if (vp->v_pollinfo == NULL) {
+ /* This is a nullfs vnode which shadows a watched vnode. */
+ return;
+ }
+ inotify_log(vp, NULL, 0, IN_UNMOUNT, 0);
+}
+
+static int
+fget_inotify(struct thread *td, int fd, const cap_rights_t *needrightsp,
+ struct file **fpp)
+{
+ struct file *fp;
+ int error;
+
+ error = fget(td, fd, needrightsp, &fp);
+ if (error != 0)
+ return (error);
+ if (fp->f_type != DTYPE_INOTIFY) {
+ fdrop(fp, td);
+ return (EINVAL);
+ }
+ *fpp = fp;
+ return (0);
+}
+
+int
+kern_inotify_add_watch(int fd, int dfd, const char *path, uint32_t mask,
+ struct thread *td)
+{
+ struct nameidata nd;
+ struct file *fp;
+ struct inotify_softc *sc;
+ struct vnode *vp;
+ uint32_t wd;
+ int count, error;
+
+ fp = NULL;
+ vp = NULL;
+
+ if ((mask & IN_ALL_EVENTS) == 0)
+ return (EXTERROR(EINVAL, "no events specified"));
+ if ((mask & (IN_MASK_ADD | IN_MASK_CREATE)) ==
+ (IN_MASK_ADD | IN_MASK_CREATE))
+ return (EXTERROR(EINVAL,
+ "IN_MASK_ADD and IN_MASK_CREATE are mutually exclusive"));
+ if ((mask & ~(IN_ALL_EVENTS | _IN_ALL_FLAGS | IN_UNMOUNT)) != 0)
+ return (EXTERROR(EINVAL, "unrecognized flag"));
+
+ error = fget_inotify(td, fd, &cap_inotify_add_rights, &fp);
+ if (error != 0)
+ return (error);
+ sc = fp->f_data;
+
+ NDINIT_AT(&nd, LOOKUP,
+ ((mask & IN_DONT_FOLLOW) ? NOFOLLOW : FOLLOW) | LOCKLEAF |
+ LOCKSHARED | AUDITVNODE1, UIO_USERSPACE, path, dfd);
+ error = namei(&nd);
+ if (error != 0)
+ goto out;
+ NDFREE_PNBUF(&nd);
+ vp = nd.ni_vp;
+
+ error = VOP_ACCESS(vp, VREAD, td->td_ucred, td);
+ if (error != 0)
+ goto out;
+
+ if ((mask & IN_ONLYDIR) != 0 && vp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
+ }
+
+ count = atomic_fetchadd_int(&inotify_watches, 1);
+ if (count > inotify_max_watches) {
+ atomic_subtract_int(&inotify_watches, 1);
+ error = ENOSPC;
+ goto out;
+ }
+ if (!chginotifywatchcnt(sc->cred->cr_ruidinfo, 1,
+ inotify_max_user_watches)) {
+ atomic_subtract_int(&inotify_watches, 1);
+ error = ENOSPC;
+ goto out;
+ }
+ error = VOP_INOTIFY_ADD_WATCH(vp, sc, mask, &wd, td);
+ if (error != 0) {
+ atomic_subtract_int(&inotify_watches, 1);
+ (void)chginotifywatchcnt(sc->cred->cr_ruidinfo, -1, 0);
+ if (error == EJUSTRETURN) {
+ /* We updated an existing watch, everything is ok. */
+ error = 0;
+ } else {
+ goto out;
+ }
+ }
+ td->td_retval[0] = wd;
+
+out:
+ if (vp != NULL)
+ vput(vp);
+ fdrop(fp, td);
+ return (error);
+}
+
+int
+sys_inotify_add_watch_at(struct thread *td,
+ struct inotify_add_watch_at_args *uap)
+{
+ return (kern_inotify_add_watch(uap->fd, uap->dfd, uap->path,
+ uap->mask, td));
+}
+
+int
+kern_inotify_rm_watch(int fd, uint32_t wd, struct thread *td)
+{
+ struct file *fp;
+ struct inotify_softc *sc;
+ struct inotify_record *rec;
+ struct inotify_watch key, *watch;
+ int error;
+
+ error = fget_inotify(td, fd, &cap_inotify_rm_rights, &fp);
+ if (error != 0)
+ return (error);
+ sc = fp->f_data;
+
+ rec = inotify_alloc_record(wd, NULL, 0, IN_IGNORED, 0, M_WAITOK);
+
+ /*
+ * For compatibility with Linux, we do not remove pending events
+ * associated with the watch. Watch descriptors are implemented so as
+ * to avoid being reused for as long as possible, so one hopes that any
+ * pending events from the removed watch descriptor will be removed
+ * before the watch descriptor is recycled.
+ */
+ key.wd = wd;
+ mtx_lock(&sc->lock);
+ watch = RB_FIND(inotify_watch_tree, &sc->watches, &key);
+ if (watch == NULL) {
+ free(rec, M_INOTIFY);
+ error = EINVAL;
+ } else {
+ RB_REMOVE(inotify_watch_tree, &sc->watches, watch);
+ if (!inotify_queue_record(sc, rec)) {
+ free(rec, M_INOTIFY);
+ error = 0;
+ }
+ }
+ mtx_unlock(&sc->lock);
+ if (watch != NULL)
+ inotify_remove_watch(watch);
+ fdrop(fp, td);
+ return (error);
+}
+
+int
+sys_inotify_rm_watch(struct thread *td, struct inotify_rm_watch_args *uap)
+{
+ return (kern_inotify_rm_watch(uap->fd, uap->wd, td));
+}
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 86c7bdaa02c0..fb3e6a7a2534 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -75,14 +75,20 @@ static void NDVALIDATE_impl(struct nameidata *, int);
#endif
/*
+ * Reset ndp to its original state.
+ */
+#define NDRESET(ndp) do { \
+ NDREINIT_DBG(ndp); \
+ ndp->ni_resflags = 0; \
+ ndp->ni_cnd.cn_flags &= ~NAMEI_INTERNAL_FLAGS; \
+} while (0)
+/*
* Prepare namei() to restart. Reset components to its original state and set
* ISRESTARTED flag which signals the underlying lookup code to change the root
* from ABI root to actual root and prevents a further restarts.
*/
#define NDRESTART(ndp) do { \
- NDREINIT_DBG(ndp); \
- ndp->ni_resflags = 0; \
- ndp->ni_cnd.cn_flags &= ~NAMEI_INTERNAL_FLAGS; \
+ NDRESET(ndp); \
ndp->ni_cnd.cn_flags |= ISRESTARTED; \
} while (0)
@@ -162,8 +168,8 @@ static struct vop_vector crossmp_vnodeops = {
*/
struct nameicap_tracker {
- struct vnode *dp;
TAILQ_ENTRY(nameicap_tracker) nm_link;
+ struct mount *mp;
};
/* Zone for cap mode tracker elements used for dotdot capability checks. */
@@ -192,49 +198,75 @@ SYSCTL_INT(_vfs, OID_AUTO, lookup_cap_dotdot_nonlocal, CTLFLAG_RWTUN,
"enables \"..\" components in path lookup in capability mode "
"on non-local mount");
-static void
+static int
nameicap_tracker_add(struct nameidata *ndp, struct vnode *dp)
{
struct nameicap_tracker *nt;
+ struct mount *mp;
+ int error;
if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0 || dp->v_type != VDIR)
- return;
+ return (0);
+ mp = NULL;
+ error = VOP_GETWRITEMOUNT(dp, &mp);
+ if (error != 0)
+ return (error);
nt = TAILQ_LAST(&ndp->ni_cap_tracker, nameicap_tracker_head);
- if (nt != NULL && nt->dp == dp)
- return;
+ if (nt != NULL && nt->mp == mp) {
+ vfs_rel(mp);
+ return (0);
+ }
nt = malloc(sizeof(*nt), M_NAMEITRACKER, M_WAITOK);
- vhold(dp);
- nt->dp = dp;
- TAILQ_INSERT_TAIL(&ndp->ni_cap_tracker, nt, nm_link);
+ nt->mp = mp;
+ error = lockmgr(&mp->mnt_renamelock, LK_SHARED | LK_NOWAIT, 0);
+ if (error != 0) {
+ MPASS(ndp->ni_nctrack_mnt == NULL);
+ ndp->ni_nctrack_mnt = mp;
+ free(nt, M_NAMEITRACKER);
+ error = ERESTART;
+ } else {
+ TAILQ_INSERT_TAIL(&ndp->ni_cap_tracker, nt, nm_link);
+ }
+ return (error);
}
static void
-nameicap_cleanup_from(struct nameidata *ndp, struct nameicap_tracker *first)
+nameicap_cleanup(struct nameidata *ndp, int error)
{
struct nameicap_tracker *nt, *nt1;
+ struct mount *mp;
+
+ KASSERT((ndp->ni_nctrack_mnt == NULL &&
+ TAILQ_EMPTY(&ndp->ni_cap_tracker)) ||
+ (ndp->ni_lcf & NI_LCF_CAP_DOTDOT) != 0,
+ ("tracker active and not strictrelative"));
- nt = first;
- TAILQ_FOREACH_FROM_SAFE(nt, &ndp->ni_cap_tracker, nm_link, nt1) {
+ TAILQ_FOREACH_SAFE(nt, &ndp->ni_cap_tracker, nm_link, nt1) {
+ mp = nt->mp;
+ lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0);
+ vfs_rel(mp);
TAILQ_REMOVE(&ndp->ni_cap_tracker, nt, nm_link);
- vdrop(nt->dp);
free(nt, M_NAMEITRACKER);
}
-}
-static void
-nameicap_cleanup(struct nameidata *ndp)
-{
- KASSERT(TAILQ_EMPTY(&ndp->ni_cap_tracker) ||
- (ndp->ni_lcf & NI_LCF_CAP_DOTDOT) != 0, ("not strictrelative"));
- nameicap_cleanup_from(ndp, NULL);
+ mp = ndp->ni_nctrack_mnt;
+ if (mp != NULL) {
+ if (error == ERESTART) {
+ lockmgr(&mp->mnt_renamelock, LK_EXCLUSIVE, 0);
+ lockmgr(&mp->mnt_renamelock, LK_RELEASE, 0);
+ }
+ vfs_rel(mp);
+ ndp->ni_nctrack_mnt = NULL;
+ }
}
/*
- * For dotdot lookups in capability mode, only allow the component
- * lookup to succeed if the resulting directory was already traversed
- * during the operation. This catches situations where already
- * traversed directory is moved to different parent, and then we walk
- * over it with dotdots.
+ * For dotdot lookups in capability mode, disallow walking over the
+ * directory no_rbeneath_dpp that was used as the starting point of
+ * the lookup. Since we take the mnt_renamelocks of all mounts we
+ * ever walked over during lookup, parallel renames are disabled.
+ * This prevents the situation where we circumvent walk over
+ * ni_rbeneath_dpp following dotdots.
*
* Also allow to force failure of dotdot lookups for non-local
* filesystems, where external agents might assist local lookups to
@@ -243,7 +275,6 @@ nameicap_cleanup(struct nameidata *ndp)
static int
nameicap_check_dotdot(struct nameidata *ndp, struct vnode *dp)
{
- struct nameicap_tracker *nt;
struct mount *mp;
if (dp == NULL || dp->v_type != VDIR || (ndp->ni_lcf &
@@ -253,22 +284,16 @@ nameicap_check_dotdot(struct nameidata *ndp, struct vnode *dp)
NI_LCF_CAP_DOTDOT_KTR)) == NI_LCF_STRICTREL_KTR))
NI_CAP_VIOLATION(ndp, ndp->ni_cnd.cn_pnbuf);
if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0)
- return (ENOTCAPABLE);
+ goto violation;
+ if (dp == ndp->ni_rbeneath_dpp)
+ goto violation;
mp = dp->v_mount;
if (lookup_cap_dotdot_nonlocal == 0 && mp != NULL &&
(mp->mnt_flag & MNT_LOCAL) == 0)
- goto capfail;
- TAILQ_FOREACH_REVERSE(nt, &ndp->ni_cap_tracker, nameicap_tracker_head,
- nm_link) {
- if (dp == nt->dp) {
- nt = TAILQ_NEXT(nt, nm_link);
- if (nt != NULL)
- nameicap_cleanup_from(ndp, nt);
- return (0);
- }
- }
+ goto violation;
+ return (0);
-capfail:
+violation:
if (__predict_false((ndp->ni_lcf & NI_LCF_STRICTREL_KTR) != 0))
NI_CAP_VIOLATION(ndp, ndp->ni_cnd.cn_pnbuf);
return (ENOTCAPABLE);
@@ -394,6 +419,8 @@ namei_setup(struct nameidata *ndp, struct vnode **dpp, struct pwd **pwdp)
NI_LCF_CAP_DOTDOT;
}
}
+ if (error == 0 && (ndp->ni_lcf & NI_LCF_STRICTREL) != 0)
+ ndp->ni_rbeneath_dpp = *dpp;
/*
* If we are auditing the kernel pathname, save the user pathname.
@@ -631,6 +658,7 @@ restart:
error = namei_getpath(ndp);
if (__predict_false(error != 0)) {
namei_cleanup_cnp(cnp);
+ nameicap_cleanup(ndp, error);
SDT_PROBE4(vfs, namei, lookup, return, error, NULL,
false, ndp);
return (error);
@@ -661,12 +689,12 @@ restart:
else if (__predict_false(pwd->pwd_adir != pwd->pwd_rdir &&
(cnp->cn_flags & ISRESTARTED) == 0)) {
namei_cleanup_cnp(cnp);
+ nameicap_cleanup(ndp, ERESTART);
NDRESTART(ndp);
goto restart;
}
return (error);
case CACHE_FPL_STATUS_PARTIAL:
- TAILQ_INIT(&ndp->ni_cap_tracker);
dp = ndp->ni_startdir;
break;
case CACHE_FPL_STATUS_DESTROYED:
@@ -674,18 +702,21 @@ restart:
error = namei_getpath(ndp);
if (__predict_false(error != 0)) {
namei_cleanup_cnp(cnp);
+ nameicap_cleanup(ndp, error);
return (error);
}
cnp->cn_nameptr = cnp->cn_pnbuf;
/* FALLTHROUGH */
case CACHE_FPL_STATUS_ABORTED:
- TAILQ_INIT(&ndp->ni_cap_tracker);
MPASS(ndp->ni_lcf == 0);
if (*cnp->cn_pnbuf == '\0') {
if ((cnp->cn_flags & EMPTYPATH) != 0) {
- return (namei_emptypath(ndp));
+ error = namei_emptypath(ndp);
+ nameicap_cleanup(ndp, error);
+ return (error);
}
namei_cleanup_cnp(cnp);
+ nameicap_cleanup(ndp, ENOENT);
SDT_PROBE4(vfs, namei, lookup, return, ENOENT, NULL,
false, ndp);
return (ENOENT);
@@ -693,6 +724,7 @@ restart:
error = namei_setup(ndp, &dp, &pwd);
if (error != 0) {
namei_cleanup_cnp(cnp);
+ nameicap_cleanup(ndp, error);
return (error);
}
break;
@@ -705,16 +737,23 @@ restart:
ndp->ni_startdir = dp;
error = vfs_lookup(ndp);
if (error != 0) {
- if (__predict_false(pwd->pwd_adir != pwd->pwd_rdir &&
- error == ENOENT &&
- (cnp->cn_flags & ISRESTARTED) == 0)) {
- nameicap_cleanup(ndp);
- pwd_drop(pwd);
- namei_cleanup_cnp(cnp);
- NDRESTART(ndp);
- goto restart;
- } else
+ uint64_t was_restarted;
+ bool abi_restart;
+
+ was_restarted = ndp->ni_cnd.cn_flags &
+ ISRESTARTED;
+ abi_restart = pwd->pwd_adir != pwd->pwd_rdir &&
+ error == ENOENT && was_restarted == 0;
+ if (error != ERESTART && !abi_restart)
goto out;
+ nameicap_cleanup(ndp, error);
+ pwd_drop(pwd);
+ namei_cleanup_cnp(cnp);
+ NDRESET(ndp);
+ if (abi_restart)
+ was_restarted = ISRESTARTED;
+ ndp->ni_cnd.cn_flags |= was_restarted;
+ goto restart;
}
/*
@@ -723,7 +762,7 @@ restart:
if ((cnp->cn_flags & ISSYMLINK) == 0) {
SDT_PROBE4(vfs, namei, lookup, return, error,
ndp->ni_vp, false, ndp);
- nameicap_cleanup(ndp);
+ nameicap_cleanup(ndp, 0);
pwd_drop(pwd);
NDVALIDATE(ndp);
return (0);
@@ -756,10 +795,10 @@ restart:
ndp->ni_vp = NULL;
vrele(ndp->ni_dvp);
out:
- MPASS(error != 0);
+ MPASS(error != 0 && error != ERESTART);
SDT_PROBE4(vfs, namei, lookup, return, error, NULL, false, ndp);
namei_cleanup_cnp(cnp);
- nameicap_cleanup(ndp);
+ nameicap_cleanup(ndp, error);
pwd_drop(pwd);
return (error);
}
@@ -1185,7 +1224,9 @@ dirloop:
}
}
- nameicap_tracker_add(ndp, dp);
+ error = nameicap_tracker_add(ndp, dp);
+ if (error != 0)
+ goto bad;
/*
* Make sure degenerate names don't get here, their handling was
@@ -1210,9 +1251,7 @@ dirloop:
* the jail or chroot, don't let them out.
* 5. If doing a capability lookup and lookup_cap_dotdot is
* enabled, return ENOTCAPABLE if the lookup would escape
- * from the initial file descriptor directory. Checks are
- * done by ensuring that namei() already traversed the
- * result of dotdot lookup.
+ * from the initial file descriptor directory.
*/
if (cnp->cn_flags & ISDOTDOT) {
if (__predict_false((ndp->ni_lcf & (NI_LCF_STRICTREL_KTR |
@@ -1238,7 +1277,7 @@ dirloop:
NI_CAP_VIOLATION(ndp, cnp->cn_pnbuf);
if ((ndp->ni_lcf & NI_LCF_STRICTREL) != 0) {
error = ENOTCAPABLE;
- goto capdotdot;
+ goto bad;
}
}
if (isroot || ((dp->v_vflag & VV_ROOT) != 0 &&
@@ -1261,11 +1300,6 @@ dirloop:
vn_lock(dp,
enforce_lkflags(dp->v_mount, cnp->cn_lkflags |
LK_RETRY));
- error = nameicap_check_dotdot(ndp, dp);
- if (error != 0) {
-capdotdot:
- goto bad;
- }
}
}
@@ -1314,7 +1348,9 @@ unionlookup:
vn_lock(dp,
enforce_lkflags(dp->v_mount, cnp->cn_lkflags |
LK_RETRY));
- nameicap_tracker_add(ndp, dp);
+ error = nameicap_tracker_add(ndp, dp);
+ if (error != 0)
+ goto bad;
goto unionlookup;
}
@@ -1415,7 +1451,7 @@ nextname:
goto dirloop;
}
if (cnp->cn_flags & ISDOTDOT) {
- error = nameicap_check_dotdot(ndp, ndp->ni_vp);
+ error = nameicap_check_dotdot(ndp, ndp->ni_dvp);
if (error != 0)
goto bad2;
}
@@ -1485,8 +1521,11 @@ success:
}
success_right_lock:
if (ndp->ni_vp != NULL) {
- if ((cnp->cn_flags & ISDOTDOT) == 0)
- nameicap_tracker_add(ndp, ndp->ni_vp);
+ if ((cnp->cn_flags & ISDOTDOT) == 0) {
+ error = nameicap_tracker_add(ndp, ndp->ni_vp);
+ if (error != 0)
+ goto bad2;
+ }
if ((cnp->cn_flags & (FAILIFEXISTS | ISSYMLINK)) == FAILIFEXISTS)
return (vfs_lookup_failifexists(ndp));
}
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index cb18468d28bc..8e64a7fe966b 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -156,6 +156,7 @@ mount_init(void *mem, int size, int flags)
mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF);
mtx_init(&mp->mnt_listmtx, "struct mount vlist mtx", NULL, MTX_DEF);
lockinit(&mp->mnt_explock, PVFS, "explock", 0, 0);
+ lockinit(&mp->mnt_renamelock, PVFS, "rename", 0, 0);
mp->mnt_pcpu = uma_zalloc_pcpu(pcpu_zone_16, M_WAITOK | M_ZERO);
mp->mnt_ref = 0;
mp->mnt_vfs_ops = 1;
@@ -170,6 +171,7 @@ mount_fini(void *mem, int size)
mp = (struct mount *)mem;
uma_zfree_pcpu(pcpu_zone_16, mp->mnt_pcpu);
+ lockdestroy(&mp->mnt_renamelock);
lockdestroy(&mp->mnt_explock);
mtx_destroy(&mp->mnt_listmtx);
mtx_destroy(&mp->mnt_mtx);
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index dc2fb59fb81c..918b256e6c59 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -38,7 +38,6 @@
* External virtual filesystem routines
*/
-#include <sys/cdefs.h>
#include "opt_ddb.h"
#include "opt_watchdog.h"
@@ -57,6 +56,7 @@
#include <sys/extattr.h>
#include <sys/file.h>
#include <sys/fcntl.h>
+#include <sys/inotify.h>
#include <sys/jail.h>
#include <sys/kdb.h>
#include <sys/kernel.h>
@@ -5246,7 +5246,8 @@ destroy_vpollinfo_free(struct vpollinfo *vi)
static void
destroy_vpollinfo(struct vpollinfo *vi)
{
-
+ KASSERT(TAILQ_EMPTY(&vi->vpi_inotify),
+ ("%s: pollinfo %p has lingering watches", __func__, vi));
knlist_clear(&vi->vpi_selinfo.si_note, 1);
seldrain(&vi->vpi_selinfo);
destroy_vpollinfo_free(vi);
@@ -5260,12 +5261,13 @@ v_addpollinfo(struct vnode *vp)
{
struct vpollinfo *vi;
- if (vp->v_pollinfo != NULL)
+ if (atomic_load_ptr(&vp->v_pollinfo) != NULL)
return;
vi = malloc(sizeof(*vi), M_VNODEPOLL, M_WAITOK | M_ZERO);
mtx_init(&vi->vpi_lock, "vnode pollinfo", NULL, MTX_DEF);
knlist_init(&vi->vpi_selinfo.si_note, vp, vfs_knllock,
vfs_knlunlock, vfs_knl_assert_lock);
+ TAILQ_INIT(&vi->vpi_inotify);
VI_LOCK(vp);
if (vp->v_pollinfo != NULL) {
VI_UNLOCK(vp);
@@ -5851,6 +5853,8 @@ vop_rename_pre(void *ap)
struct vop_rename_args *a = ap;
#ifdef DEBUG_VFS_LOCKS
+ struct mount *tmp;
+
if (a->a_tvp)
ASSERT_VI_UNLOCKED(a->a_tvp, "VOP_RENAME");
ASSERT_VI_UNLOCKED(a->a_tdvp, "VOP_RENAME");
@@ -5868,6 +5872,11 @@ vop_rename_pre(void *ap)
if (a->a_tvp)
ASSERT_VOP_LOCKED(a->a_tvp, "vop_rename: tvp not locked");
ASSERT_VOP_LOCKED(a->a_tdvp, "vop_rename: tdvp not locked");
+
+ tmp = NULL;
+ VOP_GETWRITEMOUNT(a->a_tdvp, &tmp);
+ lockmgr_assert(&tmp->mnt_renamelock, KA_XLOCKED);
+ vfs_rel(tmp);
#endif
/*
* It may be tempting to add vn_seqc_write_begin/end calls here and
@@ -6057,6 +6066,28 @@ vop_need_inactive_debugpost(void *ap, int rc)
#endif
void
+vop_allocate_post(void *ap, int rc)
+{
+ struct vop_allocate_args *a;
+
+ a = ap;
+ if (rc == 0)
+ INOTIFY(a->a_vp, IN_MODIFY);
+}
+
+void
+vop_copy_file_range_post(void *ap, int rc)
+{
+ struct vop_copy_file_range_args *a;
+
+ a = ap;
+ if (rc == 0) {
+ INOTIFY(a->a_invp, IN_ACCESS);
+ INOTIFY(a->a_outvp, IN_MODIFY);
+ }
+}
+
+void
vop_create_pre(void *ap)
{
struct vop_create_args *a;
@@ -6076,8 +6107,20 @@ vop_create_post(void *ap, int rc)
a = ap;
dvp = a->a_dvp;
vn_seqc_write_end(dvp);
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(dvp, NOTE_WRITE);
+ INOTIFY_NAME(*a->a_vpp, dvp, a->a_cnp, IN_CREATE);
+ }
+}
+
+void
+vop_deallocate_post(void *ap, int rc)
+{
+ struct vop_deallocate_args *a;
+
+ a = ap;
+ if (rc == 0)
+ INOTIFY(a->a_vp, IN_MODIFY);
}
void
@@ -6122,8 +6165,10 @@ vop_deleteextattr_post(void *ap, int rc)
a = ap;
vp = a->a_vp;
vn_seqc_write_end(vp);
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB);
+ INOTIFY(vp, IN_ATTRIB);
+ }
}
void
@@ -6153,6 +6198,8 @@ vop_link_post(void *ap, int rc)
if (!rc) {
VFS_KNOTE_LOCKED(vp, NOTE_LINK);
VFS_KNOTE_LOCKED(tdvp, NOTE_WRITE);
+ INOTIFY_NAME(vp, tdvp, a->a_cnp, _IN_ATTRIB_LINKCOUNT);
+ INOTIFY_NAME(vp, tdvp, a->a_cnp, IN_CREATE);
}
}
@@ -6176,8 +6223,10 @@ vop_mkdir_post(void *ap, int rc)
a = ap;
dvp = a->a_dvp;
vn_seqc_write_end(dvp);
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(dvp, NOTE_WRITE | NOTE_LINK);
+ INOTIFY_NAME(*a->a_vpp, dvp, a->a_cnp, IN_CREATE);
+ }
}
#ifdef DEBUG_VFS_LOCKS
@@ -6212,8 +6261,10 @@ vop_mknod_post(void *ap, int rc)
a = ap;
dvp = a->a_dvp;
vn_seqc_write_end(dvp);
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(dvp, NOTE_WRITE);
+ INOTIFY_NAME(*a->a_vpp, dvp, a->a_cnp, IN_CREATE);
+ }
}
void
@@ -6225,8 +6276,10 @@ vop_reclaim_post(void *ap, int rc)
a = ap;
vp = a->a_vp;
ASSERT_VOP_IN_SEQC(vp);
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(vp, NOTE_REVOKE);
+ INOTIFY_REVOKE(vp);
+ }
}
void
@@ -6257,6 +6310,8 @@ vop_remove_post(void *ap, int rc)
if (!rc) {
VFS_KNOTE_LOCKED(dvp, NOTE_WRITE);
VFS_KNOTE_LOCKED(vp, NOTE_DELETE);
+ INOTIFY_NAME(vp, dvp, a->a_cnp, _IN_ATTRIB_LINKCOUNT);
+ INOTIFY_NAME(vp, dvp, a->a_cnp, IN_DELETE);
}
}
@@ -6288,6 +6343,8 @@ vop_rename_post(void *ap, int rc)
VFS_KNOTE_UNLOCKED(a->a_fvp, NOTE_RENAME);
if (a->a_tvp)
VFS_KNOTE_UNLOCKED(a->a_tvp, NOTE_DELETE);
+ INOTIFY_MOVE(a->a_fvp, a->a_fdvp, a->a_fcnp, a->a_tvp,
+ a->a_tdvp, a->a_tcnp);
}
if (a->a_tdvp != a->a_fdvp)
vdrop(a->a_fdvp);
@@ -6327,6 +6384,7 @@ vop_rmdir_post(void *ap, int rc)
vp->v_vflag |= VV_UNLINKED;
VFS_KNOTE_LOCKED(dvp, NOTE_WRITE | NOTE_LINK);
VFS_KNOTE_LOCKED(vp, NOTE_DELETE);
+ INOTIFY_NAME(vp, dvp, a->a_cnp, IN_DELETE);
}
}
@@ -6350,8 +6408,10 @@ vop_setattr_post(void *ap, int rc)
a = ap;
vp = a->a_vp;
vn_seqc_write_end(vp);
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(vp, NOTE_ATTRIB);
+ INOTIFY(vp, IN_ATTRIB);
+ }
}
void
@@ -6396,8 +6456,10 @@ vop_setextattr_post(void *ap, int rc)
a = ap;
vp = a->a_vp;
vn_seqc_write_end(vp);
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(vp, NOTE_ATTRIB);
+ INOTIFY(vp, IN_ATTRIB);
+ }
}
void
@@ -6420,8 +6482,10 @@ vop_symlink_post(void *ap, int rc)
a = ap;
dvp = a->a_dvp;
vn_seqc_write_end(dvp);
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(dvp, NOTE_WRITE);
+ INOTIFY_NAME(*a->a_vpp, dvp, a->a_cnp, IN_CREATE);
+ }
}
void
@@ -6429,8 +6493,10 @@ vop_open_post(void *ap, int rc)
{
struct vop_open_args *a = ap;
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(a->a_vp, NOTE_OPEN);
+ INOTIFY(a->a_vp, IN_OPEN);
+ }
}
void
@@ -6442,6 +6508,8 @@ vop_close_post(void *ap, int rc)
!VN_IS_DOOMED(a->a_vp))) {
VFS_KNOTE_LOCKED(a->a_vp, (a->a_fflag & FWRITE) != 0 ?
NOTE_CLOSE_WRITE : NOTE_CLOSE);
+ INOTIFY(a->a_vp, (a->a_fflag & FWRITE) != 0 ?
+ IN_CLOSE_WRITE : IN_CLOSE_NOWRITE);
}
}
@@ -6450,8 +6518,10 @@ vop_read_post(void *ap, int rc)
{
struct vop_read_args *a = ap;
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(a->a_vp, NOTE_READ);
+ INOTIFY(a->a_vp, IN_ACCESS);
+ }
}
void
@@ -6468,8 +6538,10 @@ vop_readdir_post(void *ap, int rc)
{
struct vop_readdir_args *a = ap;
- if (!rc)
+ if (!rc) {
VFS_KNOTE_LOCKED(a->a_vp, NOTE_READ);
+ INOTIFY(a->a_vp, IN_ACCESS);
+ }
}
static struct knlist fs_knlist;
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index c236f241bf20..c71e0d9ee569 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -3766,7 +3766,7 @@ int
kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
const char *new, enum uio_seg pathseg)
{
- struct mount *mp = NULL;
+ struct mount *mp, *tmp;
struct vnode *tvp, *fvp, *tdvp;
struct nameidata fromnd, tond;
uint64_t tondflags;
@@ -3774,6 +3774,7 @@ kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
short irflag;
again:
+ tmp = mp = NULL;
bwillwrite();
#ifdef MAC
if (mac_vnode_check_rename_from_enabled()) {
@@ -3809,6 +3810,7 @@ again:
tvp = tond.ni_vp;
error = vn_start_write(fvp, &mp, V_NOWAIT);
if (error != 0) {
+again1:
NDFREE_PNBUF(&fromnd);
NDFREE_PNBUF(&tond);
if (tvp != NULL)
@@ -3819,11 +3821,25 @@ again:
vput(tdvp);
vrele(fromnd.ni_dvp);
vrele(fvp);
+ if (tmp != NULL) {
+ lockmgr(&tmp->mnt_renamelock, LK_EXCLUSIVE, NULL);
+ lockmgr(&tmp->mnt_renamelock, LK_RELEASE, NULL);
+ vfs_rel(tmp);
+ tmp = NULL;
+ }
error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH);
if (error != 0)
return (error);
goto again;
}
+ error = VOP_GETWRITEMOUNT(tdvp, &tmp);
+ if (error != 0 || tmp == NULL)
+ goto again1;
+ error = lockmgr(&tmp->mnt_renamelock, LK_EXCLUSIVE | LK_NOWAIT, NULL);
+ if (error != 0) {
+ vn_finished_write(mp);
+ goto again1;
+ }
irflag = vn_irflag_read(fvp);
if (((irflag & VIRF_NAMEDATTR) != 0 && tdvp != fromnd.ni_dvp) ||
(irflag & VIRF_NAMEDDIR) != 0) {
@@ -3884,6 +3900,8 @@ out:
vrele(fromnd.ni_dvp);
vrele(fvp);
}
+ lockmgr(&tmp->mnt_renamelock, LK_RELEASE, 0);
+ vfs_rel(tmp);
vn_finished_write(mp);
out1:
if (error == ERESTART)
@@ -4296,10 +4314,6 @@ kern_getdirentries(struct thread *td, int fd, char *buf, size_t count,
vp = fp->f_vnode;
foffset = foffset_lock(fp, 0);
unionread:
- if (vp->v_type != VDIR) {
- error = EINVAL;
- goto fail;
- }
if (__predict_false((vp->v_vflag & VV_UNLINKED) != 0)) {
error = ENOENT;
goto fail;
@@ -4312,6 +4326,19 @@ unionread:
auio.uio_segflg = bufseg;
auio.uio_td = td;
vn_lock(vp, LK_SHARED | LK_RETRY);
+ /*
+ * We want to return ENOTDIR for anything that is not VDIR, but
+ * not for VBAD, and we can't check for VBAD while the vnode is
+ * unlocked.
+ */
+ if (vp->v_type != VDIR) {
+ if (vp->v_type == VBAD)
+ error = EBADF;
+ else
+ error = ENOTDIR;
+ VOP_UNLOCK(vp);
+ goto fail;
+ }
AUDIT_ARG_VNODE1(vp);
loff = auio.uio_offset = foffset;
#ifdef MAC
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 7487f93e4880..6451c9e07a60 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -52,6 +52,7 @@
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/filio.h>
+#include <sys/inotify.h>
#include <sys/ktr.h>
#include <sys/ktrace.h>
#include <sys/limits.h>
@@ -308,7 +309,8 @@ restart:
NDREINIT(ndp);
goto restart;
}
- if ((vn_open_flags & VN_OPEN_NAMECACHE) != 0)
+ if ((vn_open_flags & VN_OPEN_NAMECACHE) != 0 ||
+ (vn_irflag_read(ndp->ni_dvp) & VIRF_INOTIFY) != 0)
ndp->ni_cnd.cn_flags |= MAKEENTRY;
#ifdef MAC
error = mac_vnode_check_create(cred, ndp->ni_dvp,
@@ -484,6 +486,7 @@ vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred,
if (vp->v_type != VFIFO && vp->v_type != VSOCK &&
VOP_ACCESS(vp, VREAD, cred, td) == 0)
fp->f_flag |= FKQALLOWED;
+ INOTIFY(vp, IN_OPEN);
return (0);
}
@@ -1746,6 +1749,8 @@ vn_truncate_locked(struct vnode *vp, off_t length, bool sync,
vattr.va_vaflags |= VA_SYNC;
error = VOP_SETATTR(vp, &vattr, cred);
VOP_ADD_WRITECOUNT_CHECKED(vp, -1);
+ if (error == 0)
+ INOTIFY(vp, IN_MODIFY);
}
return (error);
}
diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src
index a2b6a7c8ff9f..38138a4af921 100644
--- a/sys/kern/vnode_if.src
+++ b/sys/kern/vnode_if.src
@@ -702,6 +702,7 @@ vop_vptocnp {
%% allocate vp E E E
+%! allocate post vop_allocate_post
vop_allocate {
IN struct vnode *vp;
@@ -786,6 +787,7 @@ vop_fdatasync {
%% copy_file_range invp U U U
%% copy_file_range outvp U U U
+%! copy_file_range post vop_copy_file_range_post
vop_copy_file_range {
IN struct vnode *invp;
@@ -810,6 +812,7 @@ vop_vput_pair {
%% deallocate vp L L L
+%! deallocate post vop_deallocate_post
vop_deallocate {
IN struct vnode *vp;
@@ -821,6 +824,27 @@ vop_deallocate {
};
+%% inotify vp - - -
+
+vop_inotify {
+ IN struct vnode *vp;
+ IN struct vnode *dvp;
+ IN struct componentname *cnp;
+ IN int event;
+ IN uint32_t cookie;
+};
+
+
+%% inotify_add_watch vp L L L
+
+vop_inotify_add_watch {
+ IN struct vnode *vp;
+ IN struct inotify_softc *sc;
+ IN uint32_t mask;
+ OUT uint32_t *wdp;
+ IN struct thread *td;
+};
+
# The VOPs below are spares at the end of the table to allow new VOPs to be
# added in stable branches without breaking the KBI. New VOPs in HEAD should
# be added above these spares. When merging a new VOP to a stable branch,
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 9922796f8a1d..7cb6e2124326 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -326,6 +326,7 @@ SUBDIR= \
proto \
pseudofs \
${_pst} \
+ ${_pt} \
pty \
puc \
pwm \
@@ -842,6 +843,7 @@ _iwx= iwx
_ixl= ixl
_nvdimm= nvdimm
_pms= pms
+_pt= pt
_qat= qat
.if ${MK_SOURCELESS_UCODE} != "no"
_qatfw= qatfw
diff --git a/sys/modules/efirt/Makefile b/sys/modules/efirt/Makefile
index 4738996fd4e6..c46484465b68 100644
--- a/sys/modules/efirt/Makefile
+++ b/sys/modules/efirt/Makefile
@@ -9,7 +9,7 @@ SRCS+= device_if.h bus_if.h clock_if.h
DPSRCS+= assym.inc
.if ${MACHINE_CPUARCH} == "amd64"
-SRCS+= opt_hwpmc_hooks.h opt_kstack_pages.h
+SRCS+= opt_acpi.h opt_hwpmc_hooks.h opt_kstack_pages.h
.endif
efirt_support.o: efirt_support.S assym.inc
diff --git a/sys/modules/ice/Makefile b/sys/modules/ice/Makefile
index 91f20193d878..9f9c9f602cda 100644
--- a/sys/modules/ice/Makefile
+++ b/sys/modules/ice/Makefile
@@ -13,6 +13,7 @@ SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_iflib.h
SRCS += ice_lib.c ice_osdep.c ice_resmgr.c ice_strings.c
SRCS += ice_iflib_recovery_txrx.c ice_iflib_txrx.c if_ice_iflib.c
SRCS += ice_fw_logging.c ice_ddp_common.c
+SRCS.PCI_IOV += pci_iov_if.h ice_iov.c ice_vf_mbx.c
# RDMA Client interface
# TODO: Is this the right way to compile this?
diff --git a/sys/modules/pt/Makefile b/sys/modules/pt/Makefile
new file mode 100644
index 000000000000..416b072face9
--- /dev/null
+++ b/sys/modules/pt/Makefile
@@ -0,0 +1,8 @@
+
+.PATH: ${SRCTOP}/sys/amd64/pt
+
+KMOD= pt
+SRCS= pt.c pt.h device_if.h bus_if.h
+SRCS+= opt_hwpmc_hooks.h opt_kstack_pages.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/qlnx/qlnxe/Makefile b/sys/modules/qlnx/qlnxe/Makefile
index 3d8415cf0e57..2a44ae6ddde5 100644
--- a/sys/modules/qlnx/qlnxe/Makefile
+++ b/sys/modules/qlnx/qlnxe/Makefile
@@ -58,6 +58,7 @@ SRCS+=qlnx_rdma.c
SRCS+=qlnx_ioctl.c
SRCS+=qlnx_os.c
+SRCS+=opt_inet.h
SRCS+= ${LINUXKPI_GENSRCS}
diff --git a/sys/modules/sound/sound/Makefile b/sys/modules/sound/sound/Makefile
index d2cfed2f4b6a..f3978e9bd9cc 100644
--- a/sys/modules/sound/sound/Makefile
+++ b/sys/modules/sound/sound/Makefile
@@ -13,11 +13,11 @@ SRCS+= feeder.c feeder_rate.c feeder_volume.c
SRCS+= feeder_chain.c feeder_eq.c feeder_format.c
SRCS+= feeder_matrix.c feeder_mixer.c
SRCS+= feeder_eq_gen.h feeder_rate_gen.h snd_fxdiv_gen.h
-SRCS+= mpu_if.h mpufoi_if.h synth_if.h
-SRCS+= mpu_if.c mpufoi_if.c synth_if.c
+SRCS+= mpu_if.h mpufoi_if.h
+SRCS+= mpu_if.c mpufoi_if.c
SRCS+= ac97.c buffer.c channel.c dsp.c
SRCS+= mixer.c sndstat.c sound.c vchan.c
-SRCS+= midi.c mpu401.c sequencer.c
+SRCS+= midi.c mpu401.c
feeder_eq_gen.h: ${SYSDIR}/tools/sound/feeder_eq_mkfilter.awk
${AWK} -f ${SYSDIR}/tools/sound/feeder_eq_mkfilter.awk -- ${FEEDER_EQ_PRESETS} > ${.TARGET}
diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h
index 6eefedba8775..01485cf26e06 100644
--- a/sys/net/ethernet.h
+++ b/sys/net/ethernet.h
@@ -62,6 +62,8 @@ struct ether_header {
u_char ether_shost[ETHER_ADDR_LEN];
u_short ether_type;
} __packed;
+_Static_assert(sizeof(struct ether_header) == ETHER_HDR_LEN,
+ "size of struct ether_header is wrong");
/*
* Structure of a 48-bit Ethernet address.
@@ -69,6 +71,8 @@ struct ether_header {
struct ether_addr {
u_char octet[ETHER_ADDR_LEN];
} __packed;
+_Static_assert(sizeof(struct ether_addr) == ETHER_ADDR_LEN,
+ "size of struct ether_addr is wrong");
#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */
#define ETHER_IS_IPV6_MULTICAST(addr) \
@@ -81,6 +85,23 @@ struct ether_addr {
(addr)[3] | (addr)[4] | (addr)[5]) == 0x00)
/*
+ * 802.1q VID constants from IEEE 802.1Q-2014, table 9-2.
+ */
+
+/* Null VID: The tag contains only PCP (priority) and DEI information. */
+#define DOT1Q_VID_NULL 0x0
+/* The default PVID for a bridge port. NB: bridge(4) does not honor this. */
+#define DOT1Q_VID_DEF_PVID 0x1
+/* The default SR_PVID for SRP Stream related traffic. */
+#define DOT1Q_VID_DEF_SR_PVID 0x2
+/* A VID reserved for implementation use, not permitted on the wire. */
+#define DOT1Q_VID_RSVD_IMPL 0xfff
+/* The lowest valid VID. */
+#define DOT1Q_VID_MIN 0x1
+/* The highest valid VID. */
+#define DOT1Q_VID_MAX 0xffe
+
+/*
* This is the type of the VLAN ID inside the tag, not the tag itself.
*/
typedef uint16_t ether_vlanid_t;
@@ -95,6 +116,8 @@ struct ether_vlan_header {
uint16_t evl_tag;
uint16_t evl_proto;
} __packed;
+_Static_assert(sizeof(struct ether_vlan_header) == ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN,
+ "size of struct ether_vlan_header is wrong");
#define EVL_VLID_MASK 0x0FFF
#define EVL_PRI_MASK 0xE000
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index bc421a8e156d..5b3ee740d75e 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -254,6 +254,8 @@ struct bridge_iflist {
uint32_t bif_addrcnt; /* cur. # of addresses */
uint32_t bif_addrexceeded;/* # of address violations */
struct epoch_context bif_epoch_ctx;
+ ether_vlanid_t bif_untagged; /* untagged vlan id */
+ ifbvlan_set_t bif_vlan_set; /* allowed tagged vlans */
};
/*
@@ -331,13 +333,12 @@ static void bridge_inject(struct ifnet *, struct mbuf *);
static int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
static int bridge_enqueue(struct bridge_softc *, struct ifnet *,
- struct mbuf *);
+ struct mbuf *, struct bridge_iflist *);
static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int);
static void bridge_forward(struct bridge_softc *, struct bridge_iflist *,
struct mbuf *m);
static bool bridge_member_ifaddrs(void);
-
static void bridge_timer(void *);
static void bridge_broadcast(struct bridge_softc *, struct ifnet *,
@@ -353,6 +354,9 @@ static void bridge_rtage(struct bridge_softc *);
static void bridge_rtflush(struct bridge_softc *, int);
static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *,
ether_vlanid_t);
+static bool bridge_vfilter_in(const struct bridge_iflist *, struct mbuf *);
+static bool bridge_vfilter_out(const struct bridge_iflist *,
+ const struct mbuf *);
static void bridge_rtable_init(struct bridge_softc *);
static void bridge_rtable_fini(struct bridge_softc *);
@@ -400,6 +404,9 @@ static int bridge_ioctl_sma(struct bridge_softc *, void *);
static int bridge_ioctl_sifprio(struct bridge_softc *, void *);
static int bridge_ioctl_sifcost(struct bridge_softc *, void *);
static int bridge_ioctl_sifmaxaddr(struct bridge_softc *, void *);
+static int bridge_ioctl_sifuntagged(struct bridge_softc *, void *);
+static int bridge_ioctl_sifvlanset(struct bridge_softc *, void *);
+static int bridge_ioctl_gifvlanset(struct bridge_softc *, void *);
static int bridge_ioctl_addspan(struct bridge_softc *, void *);
static int bridge_ioctl_delspan(struct bridge_softc *, void *);
static int bridge_ioctl_gbparam(struct bridge_softc *, void *);
@@ -618,6 +625,14 @@ static const struct bridge_control bridge_control_table[] = {
{ bridge_ioctl_sifmaxaddr, sizeof(struct ifbreq),
BC_F_COPYIN|BC_F_SUSER },
+ { bridge_ioctl_sifuntagged, sizeof(struct ifbreq),
+ BC_F_COPYIN|BC_F_SUSER },
+
+ { bridge_ioctl_sifvlanset, sizeof(struct ifbif_vlan_req),
+ BC_F_COPYIN|BC_F_SUSER },
+
+ { bridge_ioctl_gifvlanset, sizeof(struct ifbif_vlan_req),
+ BC_F_COPYIN|BC_F_COPYOUT },
};
static const int bridge_control_table_size = nitems(bridge_control_table);
@@ -832,6 +847,7 @@ bridge_clone_create(struct if_clone *ifc, char *name, size_t len,
ifp->if_softc = sc;
if_initname(ifp, bridge_name, ifd->unit);
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_capabilities = ifp->if_capenable = IFCAP_VLAN_HWTAGGING;
ifp->if_ioctl = bridge_ioctl;
#ifdef ALTQ
ifp->if_start = bridge_altq_start;
@@ -954,6 +970,7 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifbaconf ifbaconf;
struct ifbrparam ifbrparam;
struct ifbropreq ifbropreq;
+ struct ifbif_vlan_req ifvlanreq;
} args;
struct ifdrv *ifd = (struct ifdrv *) data;
const struct bridge_control *bc;
@@ -1495,6 +1512,7 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
req->ifbr_addrcnt = bif->bif_addrcnt;
req->ifbr_addrmax = bif->bif_addrmax;
req->ifbr_addrexceeded = bif->bif_addrexceeded;
+ req->ifbr_untagged = bif->bif_untagged;
/* Copy STP state options as flags */
if (bp->bp_operedge)
@@ -1873,6 +1891,84 @@ bridge_ioctl_sifmaxaddr(struct bridge_softc *sc, void *arg)
}
static int
+bridge_ioctl_sifuntagged(struct bridge_softc *sc, void *arg)
+{
+ struct ifbreq *req = arg;
+ struct bridge_iflist *bif;
+
+ bif = bridge_lookup_member(sc, req->ifbr_ifsname);
+ if (bif == NULL)
+ return (ENOENT);
+
+ if (req->ifbr_untagged > DOT1Q_VID_MAX)
+ return (EINVAL);
+
+ if (req->ifbr_untagged != DOT1Q_VID_NULL)
+ bif->bif_flags |= IFBIF_VLANFILTER;
+ bif->bif_untagged = req->ifbr_untagged;
+ return (0);
+}
+
+static int
+bridge_ioctl_sifvlanset(struct bridge_softc *sc, void *arg)
+{
+ struct ifbif_vlan_req *req = arg;
+ struct bridge_iflist *bif;
+
+ bif = bridge_lookup_member(sc, req->bv_ifname);
+ if (bif == NULL)
+ return (ENOENT);
+
+ /* Reject invalid VIDs. */
+ if (BRVLAN_TEST(&req->bv_set, DOT1Q_VID_NULL) ||
+ BRVLAN_TEST(&req->bv_set, DOT1Q_VID_RSVD_IMPL))
+ return (EINVAL);
+
+ switch (req->bv_op) {
+ /* Replace the existing vlan set with the new set */
+ case BRDG_VLAN_OP_SET:
+ BIT_COPY(BRVLAN_SETSIZE, &req->bv_set, &bif->bif_vlan_set);
+ break;
+
+ /* Modify the existing vlan set to add the given vlans */
+ case BRDG_VLAN_OP_ADD:
+ BIT_OR(BRVLAN_SETSIZE, &bif->bif_vlan_set, &req->bv_set);
+ break;
+
+ /* Modify the existing vlan set to remove the given vlans */
+ case BRDG_VLAN_OP_DEL:
+ BIT_ANDNOT(BRVLAN_SETSIZE, &bif->bif_vlan_set, &req->bv_set);
+ break;
+
+ /* Invalid or unknown operation */
+ default:
+ return (EINVAL);
+ }
+
+ /*
+ * The only reason to modify the VLAN access list is to use VLAN
+ * filtering on this interface, so enable it automatically.
+ */
+ bif->bif_flags |= IFBIF_VLANFILTER;
+
+ return (0);
+}
+
+static int
+bridge_ioctl_gifvlanset(struct bridge_softc *sc, void *arg)
+{
+ struct ifbif_vlan_req *req = arg;
+ struct bridge_iflist *bif;
+
+ bif = bridge_lookup_member(sc, req->bv_ifname);
+ if (bif == NULL)
+ return (ENOENT);
+
+ BIT_COPY(BRVLAN_SETSIZE, &bif->bif_vlan_set, &req->bv_set);
+ return (0);
+}
+
+static int
bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
{
struct ifbreq *req = arg;
@@ -2150,12 +2246,25 @@ bridge_stop(struct ifnet *ifp, int disable)
*
*/
static int
-bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
+bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m,
+ struct bridge_iflist *bif)
{
int len, err = 0;
short mflags;
struct mbuf *m0;
+ /*
+ * Find the bridge member port this packet is being sent on, if the
+ * caller didn't already provide it.
+ */
+ if (bif == NULL)
+ bif = bridge_lookup_member_if(sc, dst_ifp);
+ if (bif == NULL) {
+ /* Perhaps the interface was removed from the bridge */
+ m_freem(m);
+ return (EINVAL);
+ }
+
/* We may be sending a fragment so traverse the mbuf */
for (; m; m = m0) {
m0 = m->m_nextpkt;
@@ -2164,6 +2273,18 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
mflags = m->m_flags;
/*
+ * If VLAN filtering is enabled, and the native VLAN ID of the
+ * outgoing interface matches the VLAN ID of the frame, remove
+ * the VLAN header.
+ */
+ if ((bif->bif_flags & IFBIF_VLANFILTER) &&
+ bif->bif_untagged != DOT1Q_VID_NULL &&
+ VLANTAGOF(m) == bif->bif_untagged) {
+ m->m_flags &= ~M_VLANTAG;
+ m->m_pkthdr.ether_vtag = 0;
+ }
+
+ /*
* If underlying interface can not do VLAN tag insertion itself
* then attach a packet tag that holds it.
*/
@@ -2234,7 +2355,7 @@ bridge_dummynet(struct mbuf *m, struct ifnet *ifp)
return;
}
- bridge_enqueue(sc, ifp, m);
+ bridge_enqueue(sc, ifp, m, NULL);
}
/*
@@ -2329,7 +2450,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
}
}
- bridge_enqueue(sc, dst_if, mc);
+ bridge_enqueue(sc, dst_if, mc, bif);
}
if (used == 0)
m_freem(m);
@@ -2347,7 +2468,7 @@ sendunicast:
return (0);
}
- bridge_enqueue(sc, dst_if, m);
+ bridge_enqueue(sc, dst_if, m, NULL);
return (0);
}
@@ -2364,17 +2485,18 @@ bridge_transmit(struct ifnet *ifp, struct mbuf *m)
struct ether_header *eh;
struct ifnet *dst_if;
int error = 0;
+ ether_vlanid_t vlan;
sc = ifp->if_softc;
ETHER_BPF_MTAP(ifp, m);
eh = mtod(m, struct ether_header *);
+ vlan = VLANTAGOF(m);
if (((m->m_flags & (M_BCAST|M_MCAST)) == 0) &&
- (dst_if = bridge_rtlookup(sc, eh->ether_dhost, DOT1Q_VID_NULL)) !=
- NULL) {
- error = bridge_enqueue(sc, dst_if, m);
+ (dst_if = bridge_rtlookup(sc, eh->ether_dhost, vlan)) != NULL) {
+ error = bridge_enqueue(sc, dst_if, m, NULL);
} else
bridge_broadcast(sc, ifp, m, 0);
@@ -2435,18 +2557,18 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
struct bridge_iflist *dbif;
struct ifnet *src_if, *dst_if, *ifp;
struct ether_header *eh;
- uint16_t vlan;
uint8_t *dst;
int error;
+ ether_vlanid_t vlan;
NET_EPOCH_ASSERT();
src_if = m->m_pkthdr.rcvif;
ifp = sc->sc_ifp;
+ vlan = VLANTAGOF(m);
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
- vlan = VLANTAGOF(m);
if ((sbif->bif_flags & IFBIF_STP) &&
sbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
@@ -2555,6 +2677,10 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
if (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE)
goto drop;
+ /* Do VLAN filtering. */
+ if (!bridge_vfilter_out(dbif, m))
+ goto drop;
+
if ((dbif->bif_flags & IFBIF_STP) &&
dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
goto drop;
@@ -2566,7 +2692,7 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
return;
}
- bridge_enqueue(sc, dst_if, m);
+ bridge_enqueue(sc, dst_if, m, dbif);
return;
drop:
@@ -2636,6 +2762,15 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
return (NULL);
}
+ /* Do VLAN filtering. */
+ if (!bridge_vfilter_in(bif, m)) {
+ if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
+ m_freem(m);
+ return (NULL);
+ }
+ /* bridge_vfilter_in() may add a tag */
+ vlan = VLANTAGOF(m);
+
bridge_span(sc, m);
if (m->m_flags & (M_BCAST|M_MCAST)) {
@@ -2761,6 +2896,15 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
} \
if ((iface) != bifp) \
ETHER_BPF_MTAP(iface, m); \
+ /* Pass tagged packets to if_vlan, if it's loaded */ \
+ if (VLANTAGOF(m) != 0) { \
+ if (bifp->if_vlantrunk == NULL) { \
+ m_freem(m); \
+ return (NULL); \
+ } \
+ (*vlan_input_p)(bifp, m); \
+ return (NULL); \
+ } \
return (m); \
} \
\
@@ -2817,6 +2961,30 @@ bridge_inject(struct ifnet *ifp, struct mbuf *m)
{
struct bridge_softc *sc;
+ if (ifp->if_type == IFT_L2VLAN) {
+ /*
+ * vlan(4) gives us the vlan ifnet, so we need to get the
+ * bridge softc to get a pointer to ether_input to send the
+ * packet to.
+ */
+ struct ifnet *bifp = NULL;
+
+ if (vlan_trunkdev_p == NULL) {
+ m_freem(m);
+ return;
+ }
+
+ bifp = vlan_trunkdev_p(ifp);
+ if (bifp == NULL) {
+ m_freem(m);
+ return;
+ }
+
+ sc = if_getsoftc(bifp);
+ sc->sc_if_input(ifp, m);
+ return;
+ }
+
KASSERT((if_getcapenable(ifp) & IFCAP_NETMAP) != 0,
("%s: iface %s is not running in netmap mode",
__func__, if_name(ifp)));
@@ -2867,6 +3035,10 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
if (sbif && (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE))
continue;
+ /* Do VLAN filtering. */
+ if (!bridge_vfilter_out(dbif, m))
+ continue;
+
if ((dbif->bif_flags & IFBIF_STP) &&
dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
continue;
@@ -2910,7 +3082,7 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
continue;
}
- bridge_enqueue(sc, dst_if, mc);
+ bridge_enqueue(sc, dst_if, mc, dbif);
}
if (used == 0)
m_freem(m);
@@ -2946,11 +3118,116 @@ bridge_span(struct bridge_softc *sc, struct mbuf *m)
continue;
}
- bridge_enqueue(sc, dst_if, mc);
+ bridge_enqueue(sc, dst_if, mc, bif);
}
}
/*
+ * Incoming VLAN filtering. Given a frame and the member interface it was
+ * received on, decide whether the port configuration allows it.
+ */
+static bool
+bridge_vfilter_in(const struct bridge_iflist *sbif, struct mbuf *m)
+{
+ ether_vlanid_t vlan;
+
+ vlan = VLANTAGOF(m);
+ /* Make sure the vlan id is reasonable. */
+ if (vlan > DOT1Q_VID_MAX)
+ return (false);
+
+ /* If VLAN filtering isn't enabled, pass everything. */
+ if ((sbif->bif_flags & IFBIF_VLANFILTER) == 0)
+ return (true);
+
+ if (vlan == DOT1Q_VID_NULL) {
+ /*
+ * The frame doesn't have a tag. If the interface does not
+ * have an untagged vlan configured, drop the frame.
+ */
+ if (sbif->bif_untagged == DOT1Q_VID_NULL)
+ return (false);
+
+ /*
+ * Otherwise, insert a new tag based on the interface's
+ * untagged vlan id.
+ */
+ m->m_pkthdr.ether_vtag = sbif->bif_untagged;
+ m->m_flags |= M_VLANTAG;
+ } else {
+ /*
+ * The frame has a tag, so check it matches the interface's
+ * vlan access list. We explicitly do not accept tagged
+ * frames for the untagged vlan id here (unless it's also
+ * in the access list).
+ */
+ if (!BRVLAN_TEST(&sbif->bif_vlan_set, vlan))
+ return (false);
+ }
+
+ /* Accept the frame. */
+ return (true);
+}
+
+/*
+ * Outgoing VLAN filtering. Given a frame, its vlan, and the member interface
+ * we intend to send it to, decide whether the port configuration allows it to
+ * be sent.
+ */
+static bool
+bridge_vfilter_out(const struct bridge_iflist *dbif, const struct mbuf *m)
+{
+ struct ether_header *eh;
+ ether_vlanid_t vlan;
+
+ NET_EPOCH_ASSERT();
+
+ /* If VLAN filtering isn't enabled, pass everything. */
+ if ((dbif->bif_flags & IFBIF_VLANFILTER) == 0)
+ return (true);
+
+ vlan = VLANTAGOF(m);
+
+ /*
+ * Always allow untagged 802.1D STP frames, even if they would
+ * otherwise be dropped. This is required for STP to work on
+ * a filtering bridge.
+ *
+ * Tagged STP (Cisco PVST+) is a non-standard extension, so
+ * handle those frames via the normal filtering path.
+ */
+ eh = mtod(m, struct ether_header *);
+ if (vlan == DOT1Q_VID_NULL &&
+ memcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN) == 0)
+ return (true);
+
+ /*
+ * If the frame wasn't assigned to a vlan at ingress, drop it.
+ * We can't forward these frames to filtering ports because we
+ * don't know what VLAN they're supposed to be in.
+ */
+ if (vlan == DOT1Q_VID_NULL)
+ return (false);
+
+ /*
+ * If the frame's vlan matches the interfaces's untagged vlan,
+ * allow it.
+ */
+ if (vlan == dbif->bif_untagged)
+ return (true);
+
+ /*
+ * If the frame's vlan is on the interface's tagged access list,
+ * allow it.
+ */
+ if (BRVLAN_TEST(&dbif->bif_vlan_set, vlan))
+ return (true);
+
+ /* The frame was not permitted, so drop it. */
+ return (false);
+}
+
+/*
* bridge_rtupdate:
*
* Add a bridge routing entry.
diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h
index 90beb6c96d82..97b63e3d4416 100644
--- a/sys/net/if_bridgevar.h
+++ b/sys/net/if_bridgevar.h
@@ -78,6 +78,8 @@
#define _NET_IF_BRIDGEVAR_H_
#include <sys/types.h>
+#include <sys/_bitset.h>
+#include <sys/bitset.h>
#include <sys/callout.h>
#include <sys/queue.h>
#include <sys/condvar.h>
@@ -122,6 +124,9 @@
#define BRDGSPROTO 28 /* set protocol (ifbrparam) */
#define BRDGSTXHC 29 /* set tx hold count (ifbrparam) */
#define BRDGSIFAMAX 30 /* set max interface addrs (ifbreq) */
+#define BRDGSIFUNTAGGED 31 /* set if untagged vlan */
+#define BRDGSIFVLANSET 32 /* set if vlan set */
+#define BRDGGIFVLANSET 33 /* get if vlan set */
/*
* Generic bridge control request.
@@ -139,6 +144,7 @@ struct ifbreq {
uint32_t ifbr_addrcnt; /* member if addr number */
uint32_t ifbr_addrmax; /* member if addr max */
uint32_t ifbr_addrexceeded; /* member if addr violations */
+ ether_vlanid_t ifbr_untagged; /* member if untagged vlan */
uint8_t pad[32];
};
@@ -155,10 +161,11 @@ struct ifbreq {
#define IFBIF_BSTP_ADMEDGE 0x0200 /* member stp admin edge enabled */
#define IFBIF_BSTP_ADMCOST 0x0400 /* member stp admin path cost */
#define IFBIF_PRIVATE 0x0800 /* if is a private segment */
+#define IFBIF_VLANFILTER 0x1000 /* if does vlan filtering */
#define IFBIFBITS "\020\001LEARNING\002DISCOVER\003STP\004SPAN" \
"\005STICKY\014PRIVATE\006EDGE\007AUTOEDGE\010PTP" \
- "\011AUTOPTP"
+ "\011AUTOPTP\015VLANFILTER"
#define IFBIFMASK ~(IFBIF_BSTP_EDGE|IFBIF_BSTP_AUTOEDGE|IFBIF_BSTP_PTP| \
IFBIF_BSTP_AUTOPTP|IFBIF_BSTP_ADMEDGE| \
IFBIF_BSTP_ADMCOST) /* not saved */
@@ -304,6 +311,26 @@ struct ifbpstpconf {
eaddr[5] = pv >> 0; \
} while (0)
+/*
+ * Bridge VLAN access request.
+ */
+#define BRVLAN_SETSIZE 4096
+typedef __BITSET_DEFINE(ifbvlan_set, BRVLAN_SETSIZE) ifbvlan_set_t;
+
+#define BRVLAN_SET(set, bit) __BIT_SET(BRVLAN_SETSIZE, (bit), set)
+#define BRVLAN_CLR(set, bit) __BIT_CLR(BRVLAN_SETSIZE, (bit), set)
+#define BRVLAN_TEST(set, bit) __BIT_ISSET(BRVLAN_SETSIZE, (bit), set)
+
+#define BRDG_VLAN_OP_SET 1 /* replace current vlan set */
+#define BRDG_VLAN_OP_ADD 2 /* add vlans to current set */
+#define BRDG_VLAN_OP_DEL 3 /* remove vlans from current set */
+
+struct ifbif_vlan_req {
+ char bv_ifname[IFNAMSIZ];
+ uint8_t bv_op;
+ ifbvlan_set_t bv_set;
+};
+
#ifdef _KERNEL
#define BRIDGE_INPUT(_ifp, _m) do { \
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 7be4dfac23e7..3ae0c01c0efc 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -92,11 +92,6 @@
#include <crypto/sha1.h>
-#ifdef CTASSERT
-CTASSERT(sizeof (struct ether_header) == ETHER_ADDR_LEN * 2 + 2);
-CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN);
-#endif
-
VNET_DEFINE(pfil_head_t, link_pfil_head); /* Packet filter hooks */
/* netgraph node hooks for ng_ether(4) */
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index 3c1846b8f82a..c6692d3dd6bc 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -120,7 +120,8 @@ int in6_gif_setopts(struct gif_softc *, u_int);
#define GIFGOPTS _IOWR('i', 150, struct ifreq)
#define GIFSOPTS _IOW('i', 151, struct ifreq)
+#define GIF_NOCLAMP 0x0001
#define GIF_IGNORE_SOURCE 0x0002
-#define GIF_OPTMASK (GIF_IGNORE_SOURCE)
+#define GIF_OPTMASK (GIF_NOCLAMP|GIF_IGNORE_SOURCE)
#endif /* _NET_IF_GIF_H_ */
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index 9867a718e148..5b52bfa80e3b 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -718,6 +718,7 @@ lagg_capabilities(struct lagg_softc *sc)
sc->sc_ifp->if_capenable = ena;
sc->sc_ifp->if_capenable2 = ena2;
sc->sc_ifp->if_hwassist = hwa;
+ (void)if_hw_tsomax_update(sc->sc_ifp, &hw_tsomax);
getmicrotime(&sc->sc_ifp->if_lastchange);
if (sc->sc_ifflags & IFF_DEBUG)
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index e9e1c82cb688..22fcb7bf7c64 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -1673,6 +1673,7 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid,
*/
if (p->if_type != IFT_ETHER &&
p->if_type != IFT_L2VLAN &&
+ p->if_type != IFT_BRIDGE &&
(p->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
return (EPROTONOSUPPORT);
if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS)
diff --git a/sys/net/if_vlan_var.h b/sys/net/if_vlan_var.h
index f0b09445d04b..695bb81f77b3 100644
--- a/sys/net/if_vlan_var.h
+++ b/sys/net/if_vlan_var.h
@@ -126,13 +126,6 @@ struct vlanreq {
#define VLAN_PCP_MAX 7
-#define DOT1Q_VID_NULL 0x0
-#define DOT1Q_VID_DEF_PVID 0x1
-#define DOT1Q_VID_DEF_SR_PVID 0x2
-#define DOT1Q_VID_RSVD_IMPL 0xfff
-#define DOT1Q_VID_MIN 1 /* minimum valid vlan id */
-#define DOT1Q_VID_MAX 4094 /* maximum valid vlan id */
-
/*
* 802.1q full tag. Proto and vid are stored in host byte order.
*/
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 71cb1862aabf..452a8eb4024b 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -508,18 +508,6 @@ extern struct sx pf_end_lock;
(c == AF_INET6 && !(a)->addr32[0] && !(a)->addr32[1] && \
!(a)->addr32[2] && !(a)->addr32[3] )) \
-#define PF_MATCHA(n, a, m, b, f) \
- pf_match_addr(n, a, m, b, f)
-
-#define PF_ACPY(a, b, f) \
- pf_addrcpy(a, b, f)
-
-#define PF_AINC(a, f) \
- pf_addr_inc(a, f)
-
-#define PF_POOLMASK(a, b, c, d, f) \
- pf_poolmask(a, b, c, d, f)
-
#else
/* Just IPv6 */
@@ -544,18 +532,6 @@ extern struct sx pf_end_lock;
!(a)->addr32[2] && \
!(a)->addr32[3] ) \
-#define PF_MATCHA(n, a, m, b, f) \
- pf_match_addr(n, a, m, b, f)
-
-#define PF_ACPY(a, b, f) \
- pf_addrcpy(a, b, f)
-
-#define PF_AINC(a, f) \
- pf_addr_inc(a, f)
-
-#define PF_POOLMASK(a, b, c, d, f) \
- pf_poolmask(a, b, c, d, f)
-
#else
/* Just IPv4 */
@@ -570,29 +546,14 @@ extern struct sx pf_end_lock;
#define PF_AZERO(a, c) \
(!(a)->addr32[0])
-#define PF_MATCHA(n, a, m, b, f) \
- pf_match_addr(n, a, m, b, f)
-
-#define PF_ACPY(a, b, f) \
- (a)->v4.s_addr = (b)->v4.s_addr
-
-#define PF_AINC(a, f) \
- do { \
- (a)->addr32[0] = htonl(ntohl((a)->addr32[0]) + 1); \
- } while (0)
-
-#define PF_POOLMASK(a, b, c, d, f) \
- do { \
- (a)->addr32[0] = ((b)->addr32[0] & (c)->addr32[0]) | \
- (((c)->addr32[0] ^ 0xffffffff ) & (d)->addr32[0]); \
- } while (0)
-
#endif /* PF_INET_ONLY */
#endif /* PF_INET6_ONLY */
#endif /* PF_INET_INET6 */
#ifdef _KERNEL
-#ifdef INET6
+
+void unhandled_af(int) __dead2;
+
static void inline
pf_addrcpy(struct pf_addr *dst, const struct pf_addr *src, sa_family_t af)
{
@@ -602,12 +563,15 @@ pf_addrcpy(struct pf_addr *dst, const struct pf_addr *src, sa_family_t af)
memcpy(&dst->v4, &src->v4, sizeof(dst->v4));
break;
#endif /* INET */
+#ifdef INET6
case AF_INET6:
memcpy(&dst->v6, &src->v6, sizeof(dst->v6));
break;
+#endif /* INET6 */
+ default:
+ unhandled_af(af);
}
}
-#endif /* INET6 */
#endif
/*
@@ -629,7 +593,7 @@ pf_addrcpy(struct pf_addr *dst, const struct pf_addr *src, sa_family_t af)
&(aw)->v.a.mask, (x), (af))) || \
((aw)->type == PF_ADDR_ADDRMASK && \
!PF_AZERO(&(aw)->v.a.mask, (af)) && \
- !PF_MATCHA(0, &(aw)->v.a.addr, \
+ !pf_match_addr(0, &(aw)->v.a.addr, \
&(aw)->v.a.mask, (x), (af))))) != \
(neg) \
)
@@ -1406,7 +1370,6 @@ struct pf_kruleset {
struct pf_krulequeue queues[2];
struct {
struct pf_krulequeue *ptr;
- struct pf_krule **ptr_array;
u_int32_t rcount;
u_int32_t ticket;
int open;
@@ -2341,7 +2304,6 @@ VNET_DECLARE(struct pf_krule *, pf_rulemarker);
#define V_pf_rulemarker VNET(pf_rulemarker)
#endif
-void unhandled_af(int) __dead2;
int pf_start(void);
int pf_stop(void);
void pf_initialize(void);
@@ -2477,11 +2439,11 @@ int pf_test(sa_family_t, int, int, struct ifnet *, struct mbuf **, struct inpcb
int pf_normalize_ip(u_short *, struct pf_pdesc *);
#endif /* INET */
-#ifdef INET6
-int pf_normalize_ip6(int, u_short *, struct pf_pdesc *);
void pf_poolmask(struct pf_addr *, struct pf_addr*,
struct pf_addr *, struct pf_addr *, sa_family_t);
void pf_addr_inc(struct pf_addr *, sa_family_t);
+#ifdef INET6
+int pf_normalize_ip6(int, u_short *, struct pf_pdesc *);
int pf_max_frag_size(struct mbuf *);
int pf_refragment6(struct ifnet *, struct mbuf **, struct m_tag *,
struct ifnet *, bool);
@@ -2537,7 +2499,7 @@ int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t);
void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t,
u_int64_t, int, int, int);
int pfr_pool_get(struct pfr_ktable *, int *, struct pf_addr *, sa_family_t,
- pf_addr_filter_func_t);
+ pf_addr_filter_func_t, bool);
void pfr_dynaddr_update(struct pfr_ktable *, struct pfi_dynaddr *);
struct pfr_ktable *
pfr_attach_table(struct pf_kruleset *, char *);
@@ -2571,6 +2533,8 @@ int pfr_ina_rollback(struct pfr_table *, u_int32_t, int *, int);
int pfr_ina_commit(struct pfr_table *, u_int32_t, int *, int *, int);
int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
int *, u_int32_t, int);
+struct pfr_ktable
+ *pfr_ktable_select_active(struct pfr_ktable *);
MALLOC_DECLARE(PFI_MTYPE);
VNET_DECLARE(struct pfi_kkif *, pfi_all);
@@ -2674,11 +2638,10 @@ int pf_kanchor_copyout(const struct pf_kruleset *,
const struct pf_krule *, char *, size_t);
int pf_kanchor_nvcopyout(const struct pf_kruleset *,
const struct pf_krule *, nvlist_t *);
-void pf_kanchor_remove(struct pf_krule *);
+void pf_remove_kanchor(struct pf_krule *);
void pf_remove_if_empty_kruleset(struct pf_kruleset *);
struct pf_kruleset *pf_find_kruleset(const char *);
struct pf_kruleset *pf_get_leaf_kruleset(char *, char **);
-struct pf_kanchor *pf_create_kanchor(struct pf_kanchor *, const char *);
struct pf_kruleset *pf_find_or_create_kruleset(const char *);
void pf_rs_initialize(void);
@@ -2712,6 +2675,7 @@ int pf_ioctl_get_addrs(struct pf_nl_pooladdr *);
int pf_ioctl_get_addr(struct pf_nl_pooladdr *);
int pf_ioctl_get_rulesets(struct pfioc_ruleset *);
int pf_ioctl_get_ruleset(struct pfioc_ruleset *);
+int pf_ioctl_natlook(struct pfioc_natlook *);
void pf_krule_free(struct pf_krule *);
void pf_krule_clear_counters(struct pf_krule *);
@@ -2749,7 +2713,6 @@ u_short pf_map_addr(u_int8_t, struct pf_krule *,
u_short pf_map_addr_sn(u_int8_t, struct pf_krule *,
struct pf_addr *, struct pf_addr *,
struct pfi_kkif **nkif, struct pf_addr *,
- struct pf_ksrc_node **, struct pf_srchash **,
struct pf_kpool *, pf_sn_types_t);
int pf_get_transaddr_af(struct pf_krule *,
struct pf_pdesc *);
diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c
index c5a478533313..9074878e17e4 100644
--- a/sys/net80211/ieee80211_hostap.c
+++ b/sys/net80211/ieee80211_hostap.c
@@ -2214,12 +2214,9 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
/* VHT */
if (IEEE80211_IS_CHAN_VHT(ni->ni_chan) &&
- vhtcap != NULL &&
- vhtinfo != NULL) {
- /* XXX TODO; see below */
- net80211_vap_printf(vap, "%s: VHT TODO!\n", __func__);
+ vhtcap != NULL) {
ieee80211_vht_node_init(ni);
- ieee80211_vht_update_cap(ni, vhtcap, vhtinfo);
+ ieee80211_vht_update_cap(ni, vhtcap);
} else if (ni->ni_flags & IEEE80211_NODE_VHT)
ieee80211_vht_node_cleanup(ni);
diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c
index 5ec80e3646b8..c28f124648a1 100644
--- a/sys/net80211/ieee80211_ht.c
+++ b/sys/net80211/ieee80211_ht.c
@@ -1952,6 +1952,11 @@ do { \
_RETURN_CHAN_BITS(0);
/*
+ * TODO: should we bail out if there's no htinfo?
+ * Or just treat it as if we can't do the HT20/HT40 check?
+ */
+
+ /*
* The original code was based on
* 802.11ac-2013, Table 8-183x-VHT Operation Information subfields.
* 802.11-2020, Table 9-274-VHT Operation Information subfields
@@ -1962,8 +1967,12 @@ do { \
*/
htinfo = (const struct ieee80211_ie_htinfo *)ni->ni_ies.htinfo_ie;
- ht40 = ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH) ==
- IEEE80211_HTINFO_TXWIDTH_2040);
+ if (htinfo != NULL)
+ ht40 = ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH) ==
+ IEEE80211_HTINFO_TXWIDTH_2040);
+ else
+ ht40 = false;
+
can_vht160 = can_vht80p80 = can_vht80 = false;
/* 20 Mhz */
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index ad17af6778a1..a201d1b278f0 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -3138,6 +3138,36 @@ ieee80211_getsignal(struct ieee80211vap *vap, int8_t *rssi, int8_t *noise)
}
/**
+ * @brief Increment the given TID TX sequence, return the current one.
+ *
+ * @param ni ieee80211_node to operate on
+ * @param tid TID, or IEEE80211_NONQOS_TID
+ * @returns sequence number, from 0 .. 4095 inclusive, post increments
+ */
+ieee80211_seq ieee80211_tx_seqno_fetch_incr(struct ieee80211_node *ni,
+ uint8_t tid)
+{
+ ieee80211_seq seq;
+
+ seq = ni->ni_txseqs[tid];
+ ni->ni_txseqs[tid] = (ni->ni_txseqs[tid] + 1) % IEEE80211_SEQ_RANGE;
+ return (seq);
+}
+
+/**
+ * @brief Return the current sequence number for the given TID
+ *
+ * @param ni ieee80211_node to operate on
+ * @param tid TID, or IEEE80211_NONQOS_TID
+ * @returns sequence number, from 0 .. 4095 inclusive
+ */
+ieee80211_seq ieee80211_tx_seqno_fetch(const struct ieee80211_node *ni,
+ uint8_t tid)
+{
+ return (ni->ni_txseqs[tid]);
+}
+
+/**
* @brief return a dot11rate / ratecode representing the current transmit rate
*
* This is the API call for legacy / 802.11n drivers and rate control APIs
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index c83eee04a8dc..ef25fa0d7fdd 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -531,6 +531,12 @@ void ieee80211_node_leave(struct ieee80211_node *);
int8_t ieee80211_getrssi(struct ieee80211vap *);
void ieee80211_getsignal(struct ieee80211vap *, int8_t *, int8_t *);
+/* TX sequence space related routines */
+ieee80211_seq ieee80211_tx_seqno_fetch_incr(struct ieee80211_node *,
+ uint8_t);
+ieee80211_seq ieee80211_tx_seqno_fetch(const struct ieee80211_node *,
+ uint8_t);
+
/*
* Node transmit rate specific manipulation.
*
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index a4151f807882..afe83ea0805c 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -4195,17 +4195,15 @@ ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status)
* Check the frame type and TID and assign a suitable sequence number
* from the correct sequence number space.
*
+ * This implements the components of 802.11-2020 10.3.2.14.2
+ * (Transmitter Requirements) that net80211 currently supports.
+ *
* It assumes the mbuf has been encapsulated, and has the TID assigned
* if it is a QoS frame.
*
* Note this also clears any existing fragment ID in the header, so it
* must be called first before assigning fragment IDs.
*
- * For now this implements parts of 802.11-2012; it doesn't do all of
- * the needed checks for full compliance (notably QoS-Data NULL frames).
- *
- * TODO: update to 802.11-2020 10.3.2.14.2 (Transmitter Requirements)
- *
* @param ni ieee80211_node this frame will be transmitted to
* @param arg_tid A temporary check, existing callers may set
* this to a TID variable they were using, and this routine
@@ -4239,16 +4237,30 @@ ieee80211_output_seqno_assign(struct ieee80211_node *ni, int arg_tid,
"%s: called; TID mismatch; tid=%u, arg_tid=%d\n",
__func__, tid, arg_tid);
- if (IEEE80211_HAS_SEQ(type, subtype)) {
- /*
- * 802.11-2012 9.3.2.10 - QoS multicast frames
- * come out of a different seqno space.
- */
- if (IEEE80211_IS_MULTICAST(wh->i_addr1))
- seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
- else
- seqno = ni->ni_txseqs[tid]++;
- } else
+
+ /* 802.11-2020 10.3.2.14.2 (Transmitter Requirements) sections */
+
+ /* SNS7 - unicast PV1 management frame */
+
+ /* SNS6 - unicast PV1 data frame */
+
+ /* SNS5 - QoS NULL frames */
+ if (IEEE80211_QOS_HAS_SEQ(wh) && IEEE80211_IS_QOS_NULL(wh))
+ seqno = ieee80211_tx_seqno_fetch_incr(ni, IEEE80211_NONQOS_TID);
+
+ /* SNS4 - QMF STA transmitting a QMF */
+
+ /* SNS3 - QoS STA; Time Priority Management frame */
+
+ /* SNS2 - unicast QoS STA, data frame, excluding SNS5 */
+ else if (IEEE80211_QOS_HAS_SEQ(wh) &&
+ !IEEE80211_IS_MULTICAST(wh->i_addr1))
+ seqno = ieee80211_tx_seqno_fetch_incr(ni, tid);
+
+ /* SNS1 - Baseline (everything else) */
+ else if (IEEE80211_HAS_SEQ(type, subtype))
+ seqno = ieee80211_tx_seqno_fetch_incr(ni, IEEE80211_NONQOS_TID);
+ else
seqno = 0;
/*
@@ -4276,7 +4288,7 @@ ieee80211_output_beacon_seqno_assign(struct ieee80211_node *ni, struct mbuf *m)
wh = mtod(m, struct ieee80211_frame *);
- seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
+ seqno = ieee80211_tx_seqno_fetch_incr(ni, IEEE80211_NONQOS_TID);
*(uint16_t *)&wh->i_seq[0] =
htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
M_SEQNO_SET(m, seqno);
diff --git a/sys/net80211/ieee80211_vht.c b/sys/net80211/ieee80211_vht.c
index e91977f1ef98..de0b691d4d2a 100644
--- a/sys/net80211/ieee80211_vht.c
+++ b/sys/net80211/ieee80211_vht.c
@@ -838,12 +838,10 @@ ieee80211_add_vhtinfo(uint8_t *frm, struct ieee80211_node *ni)
}
void
-ieee80211_vht_update_cap(struct ieee80211_node *ni, const uint8_t *vhtcap_ie,
- const uint8_t *vhtop_ie)
+ieee80211_vht_update_cap(struct ieee80211_node *ni, const uint8_t *vhtcap_ie)
{
ieee80211_parse_vhtcap(ni, vhtcap_ie);
- ieee80211_parse_vhtopmode(ni, vhtop_ie);
}
static struct ieee80211_channel *
diff --git a/sys/net80211/ieee80211_vht.h b/sys/net80211/ieee80211_vht.h
index 2964de63c343..a1529df4a85b 100644
--- a/sys/net80211/ieee80211_vht.h
+++ b/sys/net80211/ieee80211_vht.h
@@ -52,8 +52,7 @@ uint8_t * ieee80211_add_vhtinfo(uint8_t *frm, struct ieee80211_node *);
uint8_t *ieee80211_add_vhtcap_ch(uint8_t *, struct ieee80211vap *,
struct ieee80211_channel *);
-void ieee80211_vht_update_cap(struct ieee80211_node *,
- const uint8_t *, const uint8_t *);
+void ieee80211_vht_update_cap(struct ieee80211_node *, const uint8_t *);
struct ieee80211_channel *
ieee80211_vht_adjust_channel(struct ieee80211com *,
diff --git a/sys/netinet/icmp_var.h b/sys/netinet/icmp_var.h
index b1f2b0ebf911..d6b75e482e35 100644
--- a/sys/netinet/icmp_var.h
+++ b/sys/netinet/icmp_var.h
@@ -104,11 +104,10 @@ extern int badport_bandlim(int);
#define BANDLIM_ICMP_UNREACH 0
#define BANDLIM_ICMP_ECHO 1
#define BANDLIM_ICMP_TSTAMP 2
-#define BANDLIM_RST_CLOSEDPORT 3 /* No connection, and no listeners */
-#define BANDLIM_RST_OPENPORT 4 /* No connection, listener */
-#define BANDLIM_ICMP6_UNREACH 5
-#define BANDLIM_SCTP_OOTB 6
-#define BANDLIM_MAX 7
+#define BANDLIM_TCP_RST 3
+#define BANDLIM_ICMP6_UNREACH 4
+#define BANDLIM_SCTP_OOTB 5
+#define BANDLIM_MAX 6
#endif
#endif
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index bccd4b84561a..dbe48242381d 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1745,6 +1745,23 @@ in_pcbrele(struct inpcb *inp, const inp_lookup_t lock)
}
/*
+ * Dereference and rlock inp, for which the caller must own the
+ * reference. Returns true if inp no longer usable, false otherwise.
+ */
+bool
+in_pcbrele_rlock(struct inpcb *inp)
+{
+ INP_RLOCK(inp);
+ if (in_pcbrele_rlocked(inp))
+ return (true);
+ if ((inp->inp_flags & INP_FREED) != 0) {
+ INP_RUNLOCK(inp);
+ return (true);
+ }
+ return (false);
+}
+
+/*
* Unconditionally schedule an inpcb to be freed by decrementing its
* reference count, which should occur only after the inpcb has been detached
* from its socket. If another thread holds a temporary reference (acquired
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 57cf15ca37fc..9e0618e87601 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -681,6 +681,7 @@ void in_pcbref(struct inpcb *);
bool in_pcbrele(struct inpcb *, inp_lookup_t);
bool in_pcbrele_rlocked(struct inpcb *);
bool in_pcbrele_wlocked(struct inpcb *);
+bool in_pcbrele_rlock(struct inpcb *inp);
typedef bool inp_match_t(const struct inpcb *, void *);
struct inpcb_iterator {
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index cb4b6df57c57..71b75d18efd0 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -1097,8 +1097,7 @@ static const char *icmp_rate_descrs[BANDLIM_MAX] = {
[BANDLIM_ICMP_UNREACH] = "icmp unreach",
[BANDLIM_ICMP_ECHO] = "icmp ping",
[BANDLIM_ICMP_TSTAMP] = "icmp tstamp",
- [BANDLIM_RST_CLOSEDPORT] = "closed port RST",
- [BANDLIM_RST_OPENPORT] = "open port RST",
+ [BANDLIM_TCP_RST] = "tcp reset",
[BANDLIM_ICMP6_UNREACH] = "icmp6 unreach",
[BANDLIM_SCTP_OOTB] = "sctp ootb",
};
diff --git a/sys/netinet/tcp_hpts.c b/sys/netinet/tcp_hpts.c
index 91f8251589e4..b60cdf45af52 100644
--- a/sys/netinet/tcp_hpts.c
+++ b/sys/netinet/tcp_hpts.c
@@ -433,38 +433,40 @@ static void
tcp_hpts_log(struct tcp_hpts_entry *hpts, struct tcpcb *tp, struct timeval *tv,
int slots_to_run, int idx, bool from_callout)
{
- union tcp_log_stackspecific log;
- /*
- * Unused logs are
- * 64 bit - delRate, rttProp, bw_inuse
- * 16 bit - cwnd_gain
- * 8 bit - bbr_state, bbr_substate, inhpts;
- */
- memset(&log, 0, sizeof(log));
- log.u_bbr.flex1 = hpts->p_nxt_slot;
- log.u_bbr.flex2 = hpts->p_cur_slot;
- log.u_bbr.flex3 = hpts->p_prev_slot;
- log.u_bbr.flex4 = idx;
- log.u_bbr.flex5 = hpts->p_curtick;
- log.u_bbr.flex6 = hpts->p_on_queue_cnt;
- log.u_bbr.flex7 = hpts->p_cpu;
- log.u_bbr.flex8 = (uint8_t)from_callout;
- log.u_bbr.inflight = slots_to_run;
- log.u_bbr.applimited = hpts->overidden_sleep;
- log.u_bbr.delivered = hpts->saved_curtick;
- log.u_bbr.timeStamp = tcp_tv_to_usectick(tv);
- log.u_bbr.epoch = hpts->saved_curslot;
- log.u_bbr.lt_epoch = hpts->saved_prev_slot;
- log.u_bbr.pkts_out = hpts->p_delayed_by;
- log.u_bbr.lost = hpts->p_hpts_sleep_time;
- log.u_bbr.pacing_gain = hpts->p_cpu;
- log.u_bbr.pkt_epoch = hpts->p_runningslot;
- log.u_bbr.use_lt_bw = 1;
- TCP_LOG_EVENTP(tp, NULL,
- &tptosocket(tp)->so_rcv,
- &tptosocket(tp)->so_snd,
- BBR_LOG_HPTSDIAG, 0,
- 0, &log, false, tv);
+ if (hpts_does_tp_logging && tcp_bblogging_on(tp)) {
+ union tcp_log_stackspecific log;
+ /*
+ * Unused logs are
+ * 64 bit - delRate, rttProp, bw_inuse
+ * 16 bit - cwnd_gain
+ * 8 bit - bbr_state, bbr_substate, inhpts;
+ */
+ memset(&log, 0, sizeof(log));
+ log.u_bbr.flex1 = hpts->p_nxt_slot;
+ log.u_bbr.flex2 = hpts->p_cur_slot;
+ log.u_bbr.flex3 = hpts->p_prev_slot;
+ log.u_bbr.flex4 = idx;
+ log.u_bbr.flex5 = hpts->p_curtick;
+ log.u_bbr.flex6 = hpts->p_on_queue_cnt;
+ log.u_bbr.flex7 = hpts->p_cpu;
+ log.u_bbr.flex8 = (uint8_t)from_callout;
+ log.u_bbr.inflight = slots_to_run;
+ log.u_bbr.applimited = hpts->overidden_sleep;
+ log.u_bbr.delivered = hpts->saved_curtick;
+ log.u_bbr.timeStamp = tcp_tv_to_usectick(tv);
+ log.u_bbr.epoch = hpts->saved_curslot;
+ log.u_bbr.lt_epoch = hpts->saved_prev_slot;
+ log.u_bbr.pkts_out = hpts->p_delayed_by;
+ log.u_bbr.lost = hpts->p_hpts_sleep_time;
+ log.u_bbr.pacing_gain = hpts->p_cpu;
+ log.u_bbr.pkt_epoch = hpts->p_runningslot;
+ log.u_bbr.use_lt_bw = 1;
+ TCP_LOG_EVENTP(tp, NULL,
+ &tptosocket(tp)->so_rcv,
+ &tptosocket(tp)->so_snd,
+ BBR_LOG_HPTSDIAG, 0,
+ 0, &log, false, tv);
+ }
}
static void
@@ -1353,10 +1355,7 @@ again:
}
CURVNET_SET(inp->inp_vnet);
/* Lets do any logging that we might want to */
- if (hpts_does_tp_logging && tcp_bblogging_on(tp)) {
- tcp_hpts_log(hpts, tp, &tv, slots_to_run, i,
- from_callout);
- }
+ tcp_hpts_log(hpts, tp, &tv, slots_to_run, i, from_callout);
if (tp->t_fb_ptr != NULL) {
kern_prefetch(tp->t_fb_ptr, &did_prefetch);
@@ -1487,7 +1486,7 @@ no_run:
}
void
-__tcp_set_hpts(struct tcpcb *tp, int32_t line)
+tcp_set_hpts(struct tcpcb *tp)
{
struct tcp_hpts_entry *hpts;
int failed;
diff --git a/sys/netinet/tcp_hpts.h b/sys/netinet/tcp_hpts.h
index b097a2b98db9..f5856ed8e688 100644
--- a/sys/netinet/tcp_hpts.h
+++ b/sys/netinet/tcp_hpts.h
@@ -149,8 +149,7 @@ uint32_t tcp_hpts_insert_diag(struct tcpcb *tp, uint32_t slot, int32_t line,
#define tcp_hpts_insert(inp, slot) \
tcp_hpts_insert_diag((inp), (slot), __LINE__, NULL)
-void __tcp_set_hpts(struct tcpcb *tp, int32_t line);
-#define tcp_set_hpts(a) __tcp_set_hpts(a, __LINE__)
+void tcp_set_hpts(struct tcpcb *tp);
void tcp_set_inp_to_drop(struct inpcb *inp, uint16_t reason);
@@ -165,25 +164,25 @@ extern int32_t tcp_min_hptsi_time;
* The following functions should also be available
* to userspace as well.
*/
-static __inline uint32_t
+static inline uint32_t
tcp_tv_to_hptstick(const struct timeval *sv)
{
return ((sv->tv_sec * 100000) + (sv->tv_usec / HPTS_TICKS_PER_SLOT));
}
-static __inline uint32_t
+static inline uint32_t
tcp_tv_to_usectick(const struct timeval *sv)
{
return ((uint32_t) ((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec));
}
-static __inline uint32_t
+static inline uint32_t
tcp_tv_to_mssectick(const struct timeval *sv)
{
return ((uint32_t) ((sv->tv_sec * HPTS_MSEC_IN_SEC) + (sv->tv_usec/HPTS_USEC_IN_MSEC)));
}
-static __inline uint64_t
+static inline uint64_t
tcp_tv_to_lusectick(const struct timeval *sv)
{
return ((uint64_t)((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec));
@@ -199,7 +198,7 @@ get_hpts_min_sleep_time(void)
return (tcp_min_hptsi_time + HPTS_TICKS_PER_SLOT);
}
-static __inline uint32_t
+static inline uint32_t
tcp_gethptstick(struct timeval *sv)
{
struct timeval tv;
@@ -210,7 +209,7 @@ tcp_gethptstick(struct timeval *sv)
return (tcp_tv_to_hptstick(sv));
}
-static __inline uint64_t
+static inline uint64_t
tcp_get_u64_usecs(struct timeval *tv)
{
struct timeval tvd;
@@ -221,7 +220,7 @@ tcp_get_u64_usecs(struct timeval *tv)
return (tcp_tv_to_lusectick(tv));
}
-static __inline uint32_t
+static inline uint32_t
tcp_get_usecs(struct timeval *tv)
{
struct timeval tvd;
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 7c032e13f37a..de428ae1af6f 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -621,6 +621,7 @@ tcp_input_with_port(struct mbuf **mp, int *offp, int proto, uint16_t port)
#endif /* INET6 */
struct tcpopt to; /* options in this segment */
char *s = NULL; /* address and port logging */
+ bool closed_port = false; /* segment is hitting a closed port */
NET_EPOCH_ASSERT();
@@ -907,7 +908,8 @@ findpcb:
log(LOG_INFO, "%s; %s: Connection attempt "
"to closed port\n", s, __func__);
}
- rstreason = BANDLIM_RST_CLOSEDPORT;
+ rstreason = BANDLIM_TCP_RST;
+ closed_port = true;
goto dropwithreset;
}
INP_LOCK_ASSERT(inp);
@@ -998,12 +1000,14 @@ findpcb:
* down or it is in the CLOSED state. Either way we drop the
* segment and send an appropriate response.
*/
- rstreason = BANDLIM_RST_CLOSEDPORT;
+ rstreason = BANDLIM_TCP_RST;
+ closed_port = true;
goto dropwithreset;
}
if ((tp->t_port != port) && (tp->t_state > TCPS_LISTEN)) {
- rstreason = BANDLIM_RST_CLOSEDPORT;
+ rstreason = BANDLIM_TCP_RST;
+ closed_port = true;
goto dropwithreset;
}
@@ -1055,6 +1059,8 @@ findpcb:
* socket appended to the listen queue in SYN_RECEIVED state.
*/
if ((thflags & (TH_RST|TH_ACK|TH_SYN)) == TH_ACK) {
+ int result;
+
/*
* Parse the TCP options here because
* syncookies need access to the reflected
@@ -1064,8 +1070,8 @@ findpcb:
/*
* NB: syncache_expand() doesn't unlock inp.
*/
- rstreason = syncache_expand(&inc, &to, th, &so, m, port);
- if (rstreason < 0) {
+ result = syncache_expand(&inc, &to, th, &so, m, port);
+ if (result < 0) {
/*
* A failing TCP MD5 signature comparison
* must result in the segment being dropped
@@ -1073,7 +1079,7 @@ findpcb:
* to the sender.
*/
goto dropunlock;
- } else if (rstreason == 0) {
+ } else if (result == 0) {
/*
* No syncache entry, or ACK was not for our
* SYN/ACK. Do our protection against double
@@ -1092,7 +1098,7 @@ findpcb:
* of the failure cause.
*/
INP_WUNLOCK(inp);
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
lookupflag &= ~INPLOOKUP_WILDCARD;
goto findpcb;
}
@@ -1183,7 +1189,7 @@ tfo_socket_result:
s, __func__);
syncache_badack(&inc, port); /* XXX: Not needed! */
TCPSTAT_INC(tcps_badsyn);
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
goto dropwithreset;
}
/*
@@ -1259,7 +1265,7 @@ tfo_socket_result:
"Connection attempt to deprecated "
"IPv6 address rejected\n",
s, __func__);
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
goto dropwithreset;
}
}
@@ -1380,9 +1386,10 @@ dropwithreset:
* When blackholing do not respond with a RST but
* completely ignore the segment and drop it.
*/
- if (((rstreason == BANDLIM_RST_OPENPORT && V_blackhole == 3) ||
- (rstreason == BANDLIM_RST_CLOSEDPORT &&
- ((V_blackhole == 1 && (thflags & TH_SYN)) || V_blackhole > 1))) &&
+ if (rstreason == BANDLIM_TCP_RST &&
+ ((!closed_port && V_blackhole == 3) ||
+ (closed_port &&
+ ((V_blackhole == 1 && (thflags & TH_SYN)) || V_blackhole > 1))) &&
(V_blackhole_local || (
#ifdef INET6
isipv6 ? !in6_localip(&ip6->ip6_src) :
@@ -1515,7 +1522,9 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
struct tcpopt to;
int tfo_syn;
u_int maxseg = 0;
+ bool no_data;
+ no_data = (tlen == 0);
thflags = tcp_get_flags(th);
tp->sackhint.last_sack_ack = 0;
sack_changed = SACK_NOCHANGE;
@@ -1754,7 +1763,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
tp->ts_recent = to.to_tsval;
}
- if (tlen == 0) {
+ if (no_data) {
if (SEQ_GT(th->th_ack, tp->snd_una) &&
SEQ_LEQ(th->th_ack, tp->snd_max) &&
!IN_RECOVERY(tp->t_flags) &&
@@ -1963,7 +1972,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
if ((thflags & TH_ACK) &&
(SEQ_LEQ(th->th_ack, tp->snd_una) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
goto dropwithreset;
}
@@ -1976,7 +1985,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
* FIN, or a RST.
*/
if ((thflags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
goto dropwithreset;
} else if (thflags & TH_SYN) {
@@ -2244,7 +2253,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
* for the "LAND" DoS attack.
*/
if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(th->th_seq, tp->irs)) {
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
goto dropwithreset;
}
@@ -2557,7 +2566,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
if (SEQ_LEQ(th->th_ack, tp->snd_una)) {
maxseg = tcp_maxseg(tp);
- if (tlen == 0 &&
+ if (no_data &&
(tiwin == tp->snd_wnd ||
(tp->t_flags & TF_SACK_PERMIT))) {
/*
@@ -3113,8 +3122,7 @@ step6:
(tp->snd_wl1 == th->th_seq && (SEQ_LT(tp->snd_wl2, th->th_ack) ||
(tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd))))) {
/* keep track of pure window updates */
- if (tlen == 0 &&
- tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
+ if (no_data && tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
TCPSTAT_INC(tcps_rcvwinupd);
tp->snd_wnd = tiwin;
tp->snd_wl1 = th->th_seq;
@@ -3424,7 +3432,7 @@ dropafterack:
if (tp->t_state == TCPS_SYN_RECEIVED && (thflags & TH_ACK) &&
(SEQ_GT(tp->snd_una, th->th_ack) ||
SEQ_GT(th->th_ack, tp->snd_max)) ) {
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
goto dropwithreset;
}
diff --git a/sys/netinet/tcp_log_buf.c b/sys/netinet/tcp_log_buf.c
index 75d693bc019b..e24790ece43d 100644
--- a/sys/netinet/tcp_log_buf.c
+++ b/sys/netinet/tcp_log_buf.c
@@ -2878,7 +2878,7 @@ tcp_log_sendfile(struct socket *so, off_t offset, size_t nbytes, int flags)
/* double check log state now that we have the lock */
if (inp->inp_flags & INP_DROPPED)
goto done;
- if (tp->_t_logstate != TCP_LOG_STATE_OFF) {
+ if (tcp_bblogging_on(tp)) {
struct timeval tv;
tcp_log_eventspecific_t log;
diff --git a/sys/netinet/tcp_log_buf.h b/sys/netinet/tcp_log_buf.h
index fef32e16b2e4..3e7eef8a1cda 100644
--- a/sys/netinet/tcp_log_buf.h
+++ b/sys/netinet/tcp_log_buf.h
@@ -539,12 +539,12 @@ struct tcpcb;
NULL, NULL, 0, NULL); \
} while (0)
#endif /* TCP_LOG_FORCEVERBOSE */
+/* Assumes/requires the caller has already checked tcp_bblogging_on(tp). */
#define TCP_LOG_EVENTP(tp, th, rxbuf, txbuf, eventid, errornum, len, stackinfo, th_hostorder, tv) \
do { \
- if (tcp_bblogging_on(tp)) \
- tcp_log_event(tp, th, rxbuf, txbuf, eventid, \
- errornum, len, stackinfo, th_hostorder, \
- NULL, NULL, 0, tv); \
+ KASSERT(tcp_bblogging_on(tp), ("bblogging is off")); \
+ tcp_log_event(tp, th, rxbuf, txbuf, eventid, errornum, len, \
+ stackinfo, th_hostorder, NULL, NULL, 0, tv); \
} while (0)
#ifdef TCP_BLACKBOX
diff --git a/sys/netinet/tcp_stacks/bbr.c b/sys/netinet/tcp_stacks/bbr.c
index e2cfec5c9275..d2636f01714e 100644
--- a/sys/netinet/tcp_stacks/bbr.c
+++ b/sys/netinet/tcp_stacks/bbr.c
@@ -8763,7 +8763,7 @@ bbr_do_syn_sent(struct mbuf *m, struct tcphdr *th, struct socket *so,
(SEQ_LEQ(th->th_ack, tp->iss) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if ((thflags & (TH_ACK | TH_RST)) == (TH_ACK | TH_RST)) {
@@ -8965,7 +8965,7 @@ bbr_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
(SEQ_LEQ(th->th_ack, tp->snd_una) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (tp->t_flags & TF_FASTOPEN) {
@@ -8977,7 +8977,7 @@ bbr_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
if ((thflags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
} else if (thflags & TH_SYN) {
/* non-initial SYN is ignored */
@@ -9010,7 +9010,7 @@ bbr_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
if (SEQ_LT(th->th_seq, tp->irs)) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
@@ -9288,7 +9288,7 @@ bbr_do_established(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9385,7 +9385,7 @@ bbr_do_close_wait(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9535,7 +9535,7 @@ bbr_do_fin_wait_1(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9637,7 +9637,7 @@ bbr_do_closing(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9739,7 +9739,7 @@ bbr_do_lastack(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9848,7 +9848,7 @@ bbr_do_fin_wait_2(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -11510,7 +11510,7 @@ bbr_do_segment_nounlock(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
if ((tp->t_state == TCPS_SYN_SENT) && (thflags & TH_ACK) &&
(SEQ_LEQ(th->th_ack, tp->iss) || SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (tiwin > bbr->r_ctl.rc_high_rwnd)
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index 8e05498863b9..834e1347a152 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -40,7 +40,6 @@
#endif
#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/mbuf.h>
#include <sys/proc.h> /* for proc0 declaration */
@@ -198,7 +197,7 @@ static uint32_t rack_pcm_blast = 0;
static uint32_t rack_pcm_is_enabled = 1;
static uint8_t rack_ssthresh_rest_rto_rec = 0; /* Do we restore ssthresh when we have rec -> rto -> rec */
-static uint32_t rack_gp_gain_req = 1200; /* Amount percent wise required to gain to record a round has "gaining" */
+static uint32_t rack_gp_gain_req = 1200; /* Amount percent wise required to gain to record a round as "gaining" */
static uint32_t rack_rnd_cnt_req = 0x10005; /* Default number of rounds if we are below rack_gp_gain_req where we exit ss */
@@ -938,7 +937,7 @@ rack_init_sysctls(void)
SYSCTL_ADD_U32(&rack_sysctl_ctx,
SYSCTL_CHILDREN(rack_probertt),
OID_AUTO, "time_between", CTLFLAG_RW,
- & rack_time_between_probertt, 96000000,
+ &rack_time_between_probertt, 96000000,
"How many useconds between the lowest rtt falling must past before we enter probertt");
SYSCTL_ADD_U32(&rack_sysctl_ctx,
SYSCTL_CHILDREN(rack_probertt),
@@ -3480,9 +3479,9 @@ static void
rack_free(struct tcp_rack *rack, struct rack_sendmap *rsm)
{
if (rsm->r_flags & RACK_APP_LIMITED) {
- if (rack->r_ctl.rc_app_limited_cnt > 0) {
- rack->r_ctl.rc_app_limited_cnt--;
- }
+ KASSERT((rack->r_ctl.rc_app_limited_cnt > 0),
+ ("app_cnt %u, rsm %p", rack->r_ctl.rc_app_limited_cnt, rsm));
+ rack->r_ctl.rc_app_limited_cnt--;
}
if (rsm->r_limit_type) {
/* currently there is only one limit type */
@@ -3554,8 +3553,7 @@ rack_get_measure_window(struct tcpcb *tp, struct tcp_rack *rack)
* earlier.
*
* So lets calculate the BDP with the "known" b/w using
- * the SRTT has our rtt and then multiply it by the
- * goal.
+ * the SRTT as our rtt and then multiply it by the goal.
*/
bw = rack_get_bw(rack);
srtt = (uint64_t)tp->t_srtt;
@@ -5793,7 +5791,7 @@ rack_cong_signal(struct tcpcb *tp, uint32_t type, uint32_t ack, int line)
tp->t_badrxtwin = 0;
break;
}
- if ((CC_ALGO(tp)->cong_signal != NULL) &&
+ if ((CC_ALGO(tp)->cong_signal != NULL) &&
(type != CC_RTO)){
tp->t_ccv.curack = ack;
CC_ALGO(tp)->cong_signal(&tp->t_ccv, type);
@@ -5904,7 +5902,7 @@ rack_calc_thresh_rack(struct tcp_rack *rack, uint32_t srtt, uint32_t cts, int li
*
* If reorder-fade is configured, then we track the last time we saw
* re-ordering occur. If we reach the point where enough time as
- * passed we no longer consider reordering has occuring.
+ * passed we no longer consider reordering as occurring.
*
* Or if reorder-face is 0, then once we see reordering we consider
* the connection to alway be subject to reordering and just set lro
@@ -7045,6 +7043,9 @@ rack_clone_rsm(struct tcp_rack *rack, struct rack_sendmap *nrsm,
/* Push bit must go to the right edge as well */
if (rsm->r_flags & RACK_HAD_PUSH)
rsm->r_flags &= ~RACK_HAD_PUSH;
+ /* Update the count if app limited */
+ if (nrsm->r_flags & RACK_APP_LIMITED)
+ rack->r_ctl.rc_app_limited_cnt++;
/* Clone over the state of the hw_tls flag */
nrsm->r_hw_tls = rsm->r_hw_tls;
/*
@@ -7096,7 +7097,7 @@ rack_merge_rsm(struct tcp_rack *rack,
l_rsm->r_flags |= RACK_TLP;
if (r_rsm->r_flags & RACK_RWND_COLLAPSED)
l_rsm->r_flags |= RACK_RWND_COLLAPSED;
- if ((r_rsm->r_flags & RACK_APP_LIMITED) &&
+ if ((r_rsm->r_flags & RACK_APP_LIMITED) &&
((l_rsm->r_flags & RACK_APP_LIMITED) == 0)) {
/*
* If both are app-limited then let the
@@ -8137,7 +8138,7 @@ rack_update_rsm(struct tcpcb *tp, struct tcp_rack *rack,
* remove the lost desgination and reduce the
* bytes considered lost.
*/
- rsm->r_flags &= ~RACK_WAS_LOST;
+ rsm->r_flags &= ~RACK_WAS_LOST;
KASSERT((rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start)),
("rsm:%p rack:%p rc_considered_lost goes negative", rsm, rack));
if (rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start))
@@ -8832,7 +8833,7 @@ rack_apply_updated_usrtt(struct tcp_rack *rack, uint32_t us_rtt, uint32_t us_cts
val = rack_probertt_lower_within * rack_time_between_probertt;
val /= 100;
- if ((rack->in_probe_rtt == 0) &&
+ if ((rack->in_probe_rtt == 0) &&
(rack->rc_skip_timely == 0) &&
((us_cts - rack->r_ctl.rc_lower_rtt_us_cts) >= (rack_time_between_probertt - val))) {
rack_enter_probertt(rack, us_cts);
@@ -10369,7 +10370,7 @@ more:
* and yet before retransmitting we get an ack
* which can happen due to reordering.
*/
- rsm->r_flags &= ~RACK_WAS_LOST;
+ rsm->r_flags &= ~RACK_WAS_LOST;
KASSERT((rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start)),
("rsm:%p rack:%p rc_considered_lost goes negative", rsm, rack));
if (rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start))
@@ -11065,7 +11066,7 @@ rack_strike_dupack(struct tcp_rack *rack, tcp_seq th_ack)
* We need to skip anything already set
* to be retransmitted.
*/
- if ((rsm->r_dupack >= DUP_ACK_THRESHOLD) ||
+ if ((rsm->r_dupack >= DUP_ACK_THRESHOLD) ||
(rsm->r_flags & RACK_MUST_RXT)) {
rsm = TAILQ_NEXT(rsm, r_tnext);
continue;
@@ -12875,7 +12876,7 @@ rack_do_syn_sent(struct mbuf *m, struct tcphdr *th, struct socket *so,
(SEQ_LEQ(th->th_ack, tp->iss) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if ((thflags & (TH_ACK | TH_RST)) == (TH_ACK | TH_RST)) {
@@ -13089,7 +13090,7 @@ rack_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
(SEQ_LEQ(th->th_ack, tp->snd_una) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (tp->t_flags & TF_FASTOPEN) {
@@ -13102,7 +13103,7 @@ rack_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
if ((thflags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
} else if (thflags & TH_SYN) {
/* non-initial SYN is ignored */
@@ -13136,7 +13137,7 @@ rack_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
if (SEQ_LT(th->th_seq, tp->irs)) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
@@ -13399,7 +13400,7 @@ rack_do_established(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event(rack, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13495,7 +13496,7 @@ rack_do_close_wait(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13645,7 +13646,7 @@ rack_do_fin_wait_1(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13746,7 +13747,7 @@ rack_do_closing(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13848,7 +13849,7 @@ rack_do_lastack(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13952,7 +13953,7 @@ rack_do_fin_wait_2(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -16655,7 +16656,7 @@ rack_do_segment_nounlock(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
if ((tp->t_state == TCPS_SYN_SENT) && (thflags & TH_ACK) &&
(SEQ_LEQ(th->th_ack, tp->iss) || SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
#ifdef TCP_ACCOUNTING
sched_unpin();
#endif
@@ -16919,7 +16920,7 @@ do_output_now:
} else if ((nxt_pkt == 0) && (tp->t_flags & TF_ACKNOW)) {
goto do_output_now;
} else if ((no_output == 1) &&
- (nxt_pkt == 0) &&
+ (nxt_pkt == 0) &&
(tcp_in_hpts(rack->rc_tp) == 0)) {
/*
* We are not in hpts and we had a pacing timer up. Use
@@ -17546,7 +17547,7 @@ rack_get_pacing_delay(struct tcp_rack *rack, struct tcpcb *tp, uint32_t len, str
rack->r_ctl.rc_last_us_rtt,
88, __LINE__, NULL, gain);
}
- if (((bw_est == 0) || (rate_wanted == 0) || (rack->gp_ready == 0)) &&
+ if (((bw_est == 0) || (rate_wanted == 0) || (rack->gp_ready == 0)) &&
(rack->use_fixed_rate == 0)) {
/*
* No way yet to make a b/w estimate or
@@ -17986,7 +17987,7 @@ start_set:
tp->gput_ack = tp->gput_seq + rack_get_measure_window(tp, rack);
rack->r_ctl.rc_gp_cumack_ts = 0;
if ((rack->r_ctl.cleared_app_ack == 1) &&
- (SEQ_GEQ(rack->r_ctl.cleared_app_ack, tp->gput_seq))) {
+ (SEQ_GEQ(tp->gput_seq, rack->r_ctl.cleared_app_ack_seq))) {
/*
* We just cleared an application limited period
* so the next seq out needs to skip the first
@@ -20043,7 +20044,7 @@ again:
rack->r_ctl.pcm_max_seg = ctf_fixed_maxseg(tp) * 10;
}
}
- if ((rack->r_ctl.pcm_max_seg != 0) && (rack->pcm_needed == 1)) {
+ if ((rack->r_ctl.pcm_max_seg != 0) && (rack->pcm_needed == 1)) {
uint32_t rw_avail, cwa;
if (tp->snd_wnd > ctf_outstanding(tp))
@@ -21031,7 +21032,7 @@ just_return_nolock:
} else
log = 1;
}
- /* Mark the last packet has app limited */
+ /* Mark the last packet as app limited */
rsm = tqhash_max(rack->r_ctl.tqh);
if (rsm && ((rsm->r_flags & RACK_APP_LIMITED) == 0)) {
if (rack->r_ctl.rc_app_limited_cnt == 0)
diff --git a/sys/netinet/tcp_stacks/rack_bbr_common.c b/sys/netinet/tcp_stacks/rack_bbr_common.c
index da26b8cb1f9b..d1c4ba58bf55 100644
--- a/sys/netinet/tcp_stacks/rack_bbr_common.c
+++ b/sys/netinet/tcp_stacks/rack_bbr_common.c
@@ -672,7 +672,7 @@ ctf_do_dropafterack(struct mbuf *m, struct tcpcb *tp, struct tcphdr *th, int32_t
(SEQ_GT(tp->snd_una, th->th_ack) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
*ret_val = 1;
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return;
} else
*ret_val = 0;
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index cd42a67294a6..db415f6bdf03 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -2720,9 +2720,15 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
ksr->snd_tag->sw->snd_tag_status_str !=
NULL) {
sz = SND_TAG_STATUS_MAXLEN;
- ksr->snd_tag->sw->snd_tag_status_str(
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
+ error = ksr->snd_tag->sw->
+ snd_tag_status_str(
ksr->snd_tag, NULL, &sz);
- len += sz;
+ if (in_pcbrele_rlock(inp))
+ return (EDEADLK);
+ if (error == 0)
+ len += sz;
}
}
kss = so->so_snd.sb_tls_info;
@@ -2739,9 +2745,15 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
kss->snd_tag->sw->snd_tag_status_str !=
NULL) {
sz = SND_TAG_STATUS_MAXLEN;
- kss->snd_tag->sw->snd_tag_status_str(
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
+ error = kss->snd_tag->sw->
+ snd_tag_status_str(
kss->snd_tag, NULL, &sz);
- len += sz;
+ if (in_pcbrele_rlock(inp))
+ return (EDEADLK);
+ if (error == 0)
+ len += sz;
}
}
if (p) {
@@ -2811,9 +2823,16 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
if (ksr->snd_tag != NULL &&
ksr->snd_tag->sw->snd_tag_status_str != NULL) {
sz = SND_TAG_STATUS_MAXLEN;
- ksr->snd_tag->sw->snd_tag_status_str(
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
+ error = ksr->snd_tag->sw->snd_tag_status_str(
ksr->snd_tag, buf + len, &sz);
- len += sz;
+ if (in_pcbrele_rlock(inp))
+ return (EDEADLK);
+ if (error == 0) {
+ xktls->rcv.drv_st_len = sz;
+ len += sz;
+ }
}
}
if (kss != NULL && kss->gen == xig.xig_gen) {
@@ -2828,9 +2847,16 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
if (kss->snd_tag != NULL &&
kss->snd_tag->sw->snd_tag_status_str != NULL) {
sz = SND_TAG_STATUS_MAXLEN;
- kss->snd_tag->sw->snd_tag_status_str(
+ in_pcbref(inp);
+ INP_RUNLOCK(inp);
+ error = kss->snd_tag->sw->snd_tag_status_str(
kss->snd_tag, buf + len, &sz);
- len += sz;
+ if (in_pcbrele_rlock(inp))
+ return (EDEADLK);
+ if (error == 0) {
+ xktls->snd.drv_st_len = sz;
+ len += sz;
+ }
}
}
len = roundup2(len, __alignof(*xktls));
@@ -2858,12 +2884,23 @@ tcp_ktlslist_locked(SYSCTL_HANDLER_ARGS, bool export_keys)
static int
tcp_ktlslist1(SYSCTL_HANDLER_ARGS, bool export_keys)
{
- int res;
-
- sx_xlock(&ktlslist_lock);
- res = tcp_ktlslist_locked(oidp, arg1, arg2, req, export_keys);
- sx_xunlock(&ktlslist_lock);
- return (res);
+ int repeats, error;
+
+ for (repeats = 0; repeats < 100; repeats++) {
+ if (sx_xlock_sig(&ktlslist_lock))
+ return (EINTR);
+ error = tcp_ktlslist_locked(oidp, arg1, arg2, req,
+ export_keys);
+ sx_xunlock(&ktlslist_lock);
+ if (error != EDEADLK)
+ break;
+ if (sig_intr() != 0) {
+ error = EINTR;
+ break;
+ }
+ req->oldidx = 0;
+ }
+ return (error);
}
static int
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 3ea561e63503..687b0d538666 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -1520,7 +1520,8 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr_in6 *sin6, struct thread *td)
INP_WLOCK_ASSERT(inp);
if (__predict_false((so->so_state &
- (SS_ISCONNECTING | SS_ISCONNECTED)) != 0))
+ (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING |
+ SS_ISDISCONNECTED)) != 0))
return (EISCONN);
if (__predict_false((so->so_options & SO_REUSEPORT_LB) != 0))
return (EOPNOTSUPP);
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index d476829e8e3b..2bab1c57ce2a 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -194,6 +194,11 @@ in6_gif_setopts(struct gif_softc *sc, u_int options)
sc->gif_options = options;
in6_gif_attach(sc);
}
+
+ if ((options & GIF_NOCLAMP) !=
+ (sc->gif_options & GIF_NOCLAMP)) {
+ sc->gif_options = options;
+ }
return (0);
}
@@ -289,6 +294,7 @@ in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
{
struct gif_softc *sc = ifp->if_softc;
struct ip6_hdr *ip6;
+ u_long mtu;
/* prepend new IP header */
NET_EPOCH_ASSERT();
@@ -304,11 +310,15 @@ in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
ip6->ip6_nxt = proto;
ip6->ip6_hlim = V_ip6_gif_hlim;
/*
- * force fragmentation to minimum MTU, to avoid path MTU discovery.
- * it is too painful to ask for resend of inner packet, to achieve
- * path MTU discovery for encapsulated packets.
+ * Enforce fragmentation to minimum MTU, even if the interface MTU
+ * is larger, to avoid path MTU discovery when NOCLAMP is not
+ * set (default). IPv6 does not allow fragmentation on intermediate
+ * router nodes, so it is too painful to ask for resend of inner
+ * packet, to achieve path MTU discovery for encapsulated packets.
*/
- return (ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL, NULL));
+ mtu = ((sc->gif_options & GIF_NOCLAMP) == 0) ? IPV6_MINMTU : 0;
+
+ return (ip6_output(m, 0, NULL, mtu, 0, NULL, NULL));
}
static int
diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c
index 06fe9e8820c9..a825658bd9ee 100644
--- a/sys/netinet6/mld6.c
+++ b/sys/netinet6/mld6.c
@@ -234,17 +234,20 @@ static SYSCTL_NODE(_net_inet6_mld, OID_AUTO, ifinfo,
CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_mld_ifinfo,
"Per-interface MLDv2 state");
-static int mld_v1enable = 1;
-SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RWTUN,
- &mld_v1enable, 0, "Enable fallback to MLDv1");
+VNET_DEFINE_STATIC(bool, mld_v1enable) = true;
+#define V_mld_v1enable VNET(mld_v1enable)
+SYSCTL_BOOL(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_VNET | CTLFLAG_RWTUN,
+ &VNET_NAME(mld_v1enable), 0, "Enable fallback to MLDv1");
-static int mld_v2enable = 1;
-SYSCTL_INT(_net_inet6_mld, OID_AUTO, v2enable, CTLFLAG_RWTUN,
- &mld_v2enable, 0, "Enable MLDv2");
+VNET_DEFINE_STATIC(bool, mld_v2enable) = true;
+#define V_mld_v2enable VNET(mld_v2enable)
+SYSCTL_BOOL(_net_inet6_mld, OID_AUTO, v2enable, CTLFLAG_VNET | CTLFLAG_RWTUN,
+ &VNET_NAME(mld_v2enable), 0, "Enable MLDv2");
-static int mld_use_allow = 1;
-SYSCTL_INT(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_RWTUN,
- &mld_use_allow, 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves");
+VNET_DEFINE_STATIC(bool, mld_use_allow) = true;
+#define V_mld_use_allow VNET(mld_use_allow)
+SYSCTL_BOOL(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_VNET | CTLFLAG_RWTUN,
+ &VNET_NAME(mld_use_allow), 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves");
/*
* Packed Router Alert option structure declaration.
@@ -481,7 +484,7 @@ mld_domifattach(struct ifnet *ifp)
mbufq_init(&mli->mli_gq, MLD_MAX_RESPONSE_PACKETS);
if ((ifp->if_flags & IFF_MULTICAST) == 0)
mli->mli_flags |= MLIF_SILENT;
- if (mld_use_allow)
+ if (V_mld_use_allow)
mli->mli_flags |= MLIF_USEALLOW;
MLD_LOCK();
@@ -614,7 +617,7 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
is_general_query = 0;
- if (!mld_v1enable) {
+ if (!V_mld_v1enable) {
CTR3(KTR_MLD, "ignore v1 query %s on ifp %p(%s)",
ip6_sprintf(ip6tbuf, &mld->mld_addr),
ifp, if_name(ifp));
@@ -790,7 +793,7 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
NET_EPOCH_ASSERT();
- if (!mld_v2enable) {
+ if (!V_mld_v2enable) {
CTR3(KTR_MLD, "ignore v2 query src %s on ifp %p(%s)",
ip6_sprintf(ip6tbuf, &ip6->ip6_src),
ifp, if_name(ifp));
@@ -1076,7 +1079,7 @@ mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6,
NET_EPOCH_ASSERT();
- if (!mld_v1enable) {
+ if (!V_mld_v1enable) {
CTR3(KTR_MLD, "ignore v1 report %s on ifp %p(%s)",
ip6_sprintf(ip6tbuf, &mld->mld_addr),
ifp, if_name(ifp));
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 0379ef7c789a..c90a1213bd66 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -765,8 +765,7 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
}
if (ifa != NULL &&
((struct in6_ifaddr *)ifa)->ia6_flags &
- (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
- IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
+ (IN6_IFF_NOTREADY|IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
NET_EPOCH_EXIT(et);
return (EADDRNOTAVAIL);
}
diff --git a/sys/netipsec/ipsec.c b/sys/netipsec/ipsec.c
index 6bacc68b7441..92d0201b398a 100644
--- a/sys/netipsec/ipsec.c
+++ b/sys/netipsec/ipsec.c
@@ -636,8 +636,10 @@ ipsec4_in_reject1(const struct mbuf *m, struct ip *ip1, struct inpcb *inp)
#ifdef IPSEC_OFFLOAD
tag = ipsec_accel_input_tag_lookup(m);
- if (tag != NULL)
- return (0);
+ if (tag != NULL) {
+ tag->tag.m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
+ __DECONST(struct mbuf *, m)->m_flags |= M_DECRYPTED;
+ }
#endif
if (ip1 == NULL) {
diff --git a/sys/netipsec/ipsec_offload.c b/sys/netipsec/ipsec_offload.c
index 467d5ded1d7a..8a09d5f37b4a 100644
--- a/sys/netipsec/ipsec_offload.c
+++ b/sys/netipsec/ipsec_offload.c
@@ -94,6 +94,7 @@ struct ifp_handle_sav {
size_t hdr_ext_size;
uint64_t cnt_octets;
uint64_t cnt_allocs;
+ struct xform_history xfh;
};
#define IFP_HS_HANDLED 0x00000001
@@ -159,6 +160,8 @@ static void ipsec_accel_drv_sa_lifetime_update_impl(struct secasvar *sav,
static int ipsec_accel_drv_sa_lifetime_fetch_impl(struct secasvar *sav,
if_t ifp, u_int drv_spi, uint64_t *octets, uint64_t *allocs);
static void ipsec_accel_ifdetach_event(void *arg, struct ifnet *ifp);
+static bool ipsec_accel_fill_xh_impl(if_t ifp, uint32_t drv_spi,
+ struct xform_history *xh);
static void
ipsec_accel_init(void *arg)
@@ -185,6 +188,7 @@ ipsec_accel_init(void *arg)
ipsec_accel_drv_sa_lifetime_update_impl;
ipsec_accel_drv_sa_lifetime_fetch_p =
ipsec_accel_drv_sa_lifetime_fetch_impl;
+ ipsec_accel_fill_xh_p = ipsec_accel_fill_xh_impl;
pctrie_init(&drv_spi_pctrie);
ipsec_accel_ifdetach_event_tag = EVENTHANDLER_REGISTER(
ifnet_departure_event, ipsec_accel_ifdetach_event, NULL,
@@ -209,6 +213,7 @@ ipsec_accel_fini(void *arg)
ipsec_accel_on_ifdown_p = NULL;
ipsec_accel_drv_sa_lifetime_update_p = NULL;
ipsec_accel_drv_sa_lifetime_fetch_p = NULL;
+ ipsec_accel_fill_xh_p = NULL;
ipsec_accel_sync_imp();
clean_unrhdr(drv_spi_unr); /* avoid panic, should go later */
clear_unrhdr(drv_spi_unr);
@@ -412,6 +417,10 @@ ipsec_accel_handle_sav(struct secasvar *sav, struct ifnet *ifp,
ihs->ifdata = priv;
ihs->flags = flags;
ihs->hdr_ext_size = esp_hdrsiz(sav);
+ memcpy(&ihs->xfh.dst, &sav->sah->saidx.dst, sizeof(ihs->xfh.dst));
+ ihs->xfh.spi = sav->spi;
+ ihs->xfh.proto = sav->sah->saidx.proto;
+ ihs->xfh.mode = sav->sah->saidx.mode;
mtx_lock(&ipsec_accel_sav_tmp);
CK_LIST_FOREACH(i, &sav->accel_ifps, sav_link) {
if (i->ifp == ifp) {
@@ -1162,4 +1171,20 @@ ipsec_accel_key_setaccelif_impl(struct secasvar *sav)
return (m);
}
+static bool
+ipsec_accel_fill_xh_impl(if_t ifp, uint32_t drv_spi, struct xform_history *xh)
+{
+ struct ifp_handle_sav *i;
+
+ if (drv_spi < IPSEC_ACCEL_DRV_SPI_MIN ||
+ drv_spi > IPSEC_ACCEL_DRV_SPI_MAX)
+ return (false);
+
+ i = DRVSPI_SA_PCTRIE_LOOKUP(&drv_spi_pctrie, drv_spi);
+ if (i == NULL)
+ return (false);
+ memcpy(xh, &i->xfh, sizeof(*xh));
+ return (true);
+}
+
#endif /* IPSEC_OFFLOAD */
diff --git a/sys/netipsec/ipsec_offload.h b/sys/netipsec/ipsec_offload.h
index 904fe6252396..ae60eaa8ae78 100644
--- a/sys/netipsec/ipsec_offload.h
+++ b/sys/netipsec/ipsec_offload.h
@@ -30,6 +30,7 @@
#include <sys/errno.h>
#include <net/if.h>
#include <net/if_var.h>
+#include <netipsec/xform.h>
struct secpolicy;
struct secasvar;
@@ -42,6 +43,7 @@ struct ipsec_accel_out_tag {
struct ipsec_accel_in_tag {
struct m_tag tag;
+ struct xform_history xh; /* Must be first to mimic IPSEC_IN_DONE */
uint16_t drv_spi;
};
@@ -66,6 +68,8 @@ extern void (*ipsec_accel_drv_sa_lifetime_update_p)(struct secasvar *sav,
if_t ifp, u_int drv_spi, uint64_t octets, uint64_t allocs);
extern int (*ipsec_accel_drv_sa_lifetime_fetch_p)(struct secasvar *sav,
if_t ifp, u_int drv_spi, uint64_t *octets, uint64_t *allocs);
+extern bool (*ipsec_accel_fill_xh_p)(if_t ifp, uint32_t drv_spi,
+ struct xform_history *xh);
#ifdef IPSEC_OFFLOAD
/*
@@ -158,6 +162,16 @@ ipsec_accel_key_setaccelif(struct secasvar *sav)
return (NULL);
}
+static inline bool
+ipsec_accel_fill_xh(if_t ifp, uint32_t drv_spi, struct xform_history *xh)
+{
+ bool (*p)(if_t ifp, uint32_t drv_spi, struct xform_history *xh);
+
+ p = atomic_load_ptr(&ipsec_accel_fill_xh_p);
+ if (p != NULL)
+ return (p(ifp, drv_spi, xh));
+ return (false);
+}
#else
#define ipsec_accel_sa_newkey(a)
@@ -168,6 +182,7 @@ ipsec_accel_key_setaccelif(struct secasvar *sav)
#define ipsec_accel_sync()
#define ipsec_accel_is_accel_sav(a)
#define ipsec_accel_key_setaccelif(a)
+#define ipsec_accel_fill_xh(a, b, c) (false)
#endif
void ipsec_accel_forget_sav_impl(struct secasvar *sav);
@@ -180,6 +195,7 @@ bool ipsec_accel_output(struct ifnet *ifp, struct mbuf *m,
struct inpcb *inp, struct secpolicy *sp, struct secasvar *sav, int af,
int mtu, int *hwassist);
void ipsec_accel_forget_sav(struct secasvar *sav);
+struct xform_history;
#else
#define ipsec_accel_input(a, b, c) (ENXIO)
#define ipsec_accel_output(a, b, c, d, e, f, g, h) ({ \
diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c
index ae67d83c6d13..4ba1b49c24f0 100644
--- a/sys/netipsec/key.c
+++ b/sys/netipsec/key.c
@@ -114,6 +114,8 @@ void (*ipsec_accel_drv_sa_lifetime_update_p)(struct secasvar *sav, if_t ifp,
u_int drv_spi, uint64_t octets, uint64_t allocs);
int (*ipsec_accel_drv_sa_lifetime_fetch_p)(struct secasvar *sav, if_t ifp,
u_int drv_spi, uint64_t *octets, uint64_t *allocs);
+bool (*ipsec_accel_fill_xh_p)(if_t ifp, uint32_t drv_spi,
+ struct xform_history *xh);
#endif
#define FULLMASK 0xff
diff --git a/sys/netlink/netlink_message_parser.h b/sys/netlink/netlink_message_parser.h
index 8492ecb3021b..720317ed74f3 100644
--- a/sys/netlink/netlink_message_parser.h
+++ b/sys/netlink/netlink_message_parser.h
@@ -209,7 +209,8 @@ int nlattr_get_nested(struct nlattr *nla, struct nl_pstate *npt,
int nlattr_get_nested_ptr(struct nlattr *nla, struct nl_pstate *npt,
const void *arg, void *target);
-bool nlmsg_report_err_msg(struct nl_pstate *npt, const char *fmt, ...);
+bool nlmsg_report_err_msg(struct nl_pstate *npt, const char *fmt, ...)
+ __printflike(2, 3);
#define NLMSG_REPORT_ERR_MSG(_npt, _fmt, ...) { \
nlmsg_report_err_msg(_npt, _fmt, ## __VA_ARGS__); \
diff --git a/sys/netpfil/ipfilter/netinet/fil.c b/sys/netpfil/ipfilter/netinet/fil.c
index 2a75190a3ec7..2fcea433295f 100644
--- a/sys/netpfil/ipfilter/netinet/fil.c
+++ b/sys/netpfil/ipfilter/netinet/fil.c
@@ -437,7 +437,7 @@ static inline void
ipf_pr_ipv6hdr(fr_info_t *fin)
{
ip6_t *ip6 = (ip6_t *)fin->fin_ip;
- int p, go = 1, i, hdrcount;
+ int p, go = 1, i;
fr_ip_t *fi = &fin->fin_fi;
fin->fin_off = 0;
@@ -464,7 +464,6 @@ ipf_pr_ipv6hdr(fr_info_t *fin)
if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
- hdrcount = 0;
while (go && !(fin->fin_flx & FI_SHORT)) {
switch (p)
{
@@ -542,7 +541,6 @@ ipf_pr_ipv6hdr(fr_info_t *fin)
go = 0;
break;
}
- hdrcount++;
/*
* It is important to note that at this point, for the
@@ -2590,14 +2588,13 @@ ipf_scanlist(fr_info_t *fin, u_32_t pass)
/* functions called from the IPFilter "mainline" in ipf_check(). */
/* ------------------------------------------------------------------------ */
frentry_t *
-ipf_acctpkt(fr_info_t *fin, u_32_t *passp)
+ipf_acctpkt(fr_info_t *fin, u_32_t *passp __unused)
{
ipf_main_softc_t *softc = fin->fin_main_soft;
char group[FR_GROUPLEN];
frentry_t *fr, *frsave;
u_32_t pass, rulen;
- passp = passp;
fr = softc->ipf_acct[fin->fin_out][softc->ipf_active];
if (fr != NULL) {
@@ -4200,7 +4197,7 @@ ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev)
(rev / 10000) % 100,
(rev / 100) % 100);
#else
- rev = rev;
+ (void)rev; /* UNUSED */
(void) strncpy(fiop->f_version, ipfilter_version,
sizeof(fiop->f_version));
#endif
@@ -4408,13 +4405,12 @@ frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data,
OP_ZERO /* zero statistics and counters */ }
addrem = OP_ADD;
frentry_t frd, *fp, *f, **fprev, **ftail;
- void *ptr, *uptr, *cptr;
+ void *ptr, *uptr;
u_int *p, *pp;
frgroup_t *fg;
char *group;
ptr = NULL;
- cptr = NULL;
fg = NULL;
fp = &frd;
if (makecopy != 0) {
@@ -4532,7 +4528,6 @@ frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data,
}
ptr = NULL;
- cptr = NULL;
if (FR_ISACCOUNT(fp->fr_flags))
unit = IPL_LOGCOUNT;
@@ -7314,11 +7309,10 @@ ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v)
/* for both IPv4 and IPv6 on the same physical NIC. */
/* ------------------------------------------------------------------------ */
void *
-ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v)
+ipf_resolvenic(ipf_main_softc_t *softc __unused, char *name, int v)
{
void *nic;
- softc = softc; /* gcc -Wextra */
if (name[0] == '\0')
return (NULL);
@@ -7455,6 +7449,10 @@ ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr)
{
ipftoken_t *it, *new;
+ KMALLOC(new, ipftoken_t *);
+ if (new != NULL)
+ bzero((char *)new, sizeof(*new));
+
WRITE_ENTER(&softc->ipf_tokens);
for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
if ((ptr == it->ipt_ctx) && (type == it->ipt_type) &&
@@ -7463,10 +7461,6 @@ ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr)
}
if (it == NULL) {
- KMALLOC(new, ipftoken_t *);
- if (new != NULL)
- bzero((char *)new, sizeof(*new));
-
it = new;
new = NULL;
if (it == NULL) {
@@ -7478,6 +7472,11 @@ ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr)
it->ipt_type = type;
it->ipt_ref = 1;
} else {
+ if (new != NULL) {
+ KFREE(new);
+ new = NULL;
+ }
+
if (it->ipt_complete > 0)
it = NULL;
else
diff --git a/sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c b/sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c
index 04850549db98..6eb6cf2a7a47 100644
--- a/sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c
+++ b/sys/netpfil/ipfilter/netinet/ip_fil_freebsd.c
@@ -463,13 +463,14 @@ ipf_send_ip(fr_info_t *fin, mb_t *m)
int
ipf_send_icmp_err(int type, fr_info_t *fin, int dst)
{
- int err, hlen, xtra, iclen, ohlen, avail, code;
+ int err, hlen, xtra, iclen, ohlen, avail;
struct in_addr dst4;
struct icmp *icmp;
struct mbuf *m;
i6addr_t dst6;
void *ifp;
#ifdef USE_INET6
+ int code;
ip6_t *ip6;
#endif
ip_t *ip, *ip2;
@@ -477,8 +478,8 @@ ipf_send_icmp_err(int type, fr_info_t *fin, int dst)
if ((type < 0) || (type >= ICMP_MAXTYPE))
return (-1);
- code = fin->fin_icode;
#ifdef USE_INET6
+ code = fin->fin_icode;
/* See NetBSD ip_fil_netbsd.c r1.4: */
if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
return (-1);
diff --git a/sys/netpfil/ipfilter/netinet/ip_ftp_pxy.c b/sys/netpfil/ipfilter/netinet/ip_ftp_pxy.c
index 482e0b456ae5..8c9317c38326 100644
--- a/sys/netpfil/ipfilter/netinet/ip_ftp_pxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_ftp_pxy.c
@@ -219,7 +219,7 @@ ipf_p_ftp_soft_destroy(ipf_main_softc_t *softc, void *arg)
int
-ipf_p_ftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_ftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused)
{
ftpinfo_t *ftp;
ftpside_t *f;
@@ -228,8 +228,6 @@ ipf_p_ftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
if (ftp == NULL)
return (-1);
- nat = nat; /* LINT */
-
aps->aps_data = ftp;
aps->aps_psiz = sizeof(ftpinfo_t);
aps->aps_sport = htons(fin->fin_sport);
@@ -1715,7 +1713,9 @@ ipf_p_ftp_eprt4(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat,
return (0);
if (c != delim)
return (0);
- addr |= addr;
+#if 0
+ addr |= (addr << 0);
+#endif
/*
* Get the port number
diff --git a/sys/netpfil/ipfilter/netinet/ip_htable.c b/sys/netpfil/ipfilter/netinet/ip_htable.c
index 22d427b87a71..91b375f80db1 100644
--- a/sys/netpfil/ipfilter/netinet/ip_htable.c
+++ b/sys/netpfil/ipfilter/netinet/ip_htable.c
@@ -343,6 +343,7 @@ ipf_htable_create(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
iph->iph_ref = 1;
iph->iph_list = NULL;
iph->iph_tail = &iph->iph_list;
+ iph->iph_unit = unit;
iph->iph_next = softh->ipf_htables[unit + 1];
iph->iph_pnext = &softh->ipf_htables[unit + 1];
if (softh->ipf_htables[unit + 1] != NULL)
@@ -603,7 +604,7 @@ ipf_htent_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph,
switch (iph->iph_type & ~IPHASH_ANON)
{
case IPHASH_GROUPMAP :
- if (ipe->ipe_group != NULL)
+ if (ipe->ipe_ptr != NULL)
ipf_group_del(softc, ipe->ipe_ptr, NULL);
break;
@@ -973,7 +974,6 @@ ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo)
{
iphtent_t ipe, *ent;
u_int hv;
- int bits;
bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
@@ -981,7 +981,6 @@ ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo)
ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
if (ipe.ipe_family == AF_INET) {
- bits = count4bits(ipe.ipe_mask.in4_addr);
ipe.ipe_addr.i6[1] = 0;
ipe.ipe_addr.i6[2] = 0;
ipe.ipe_addr.i6[3] = 0;
@@ -993,7 +992,6 @@ ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo)
} else
#ifdef USE_INET6
if (ipe.ipe_family == AF_INET6) {
- bits = count6bits(ipe.ipe_mask.i6);
hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
ipe.ipe_mask.i6, iph->iph_size);
} else
diff --git a/sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c b/sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c
index c6e4be17e22e..d5103c2944dc 100644
--- a/sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c
@@ -341,15 +341,13 @@ ipf_p_ipsec_inout(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
* UDP/TCP port numbers).
*/
int
-ipf_p_ipsec_match(fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_ipsec_match(fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused)
{
ipsec_pxy_t *ipsec;
u_32_t cookies[4];
mb_t *m;
int off;
- nat = nat; /* LINT */
-
if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG))
return (-1);
diff --git a/sys/netpfil/ipfilter/netinet/ip_irc_pxy.c b/sys/netpfil/ipfilter/netinet/ip_irc_pxy.c
index 026459299efd..aa9e84be19ed 100644
--- a/sys/netpfil/ipfilter/netinet/ip_irc_pxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_irc_pxy.c
@@ -221,7 +221,7 @@ ipf_p_irc_complete(ircinfo_t *ircp, char *buf, size_t len)
int
-ipf_p_irc_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_irc_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused)
{
ircinfo_t *irc;
@@ -232,8 +232,6 @@ ipf_p_irc_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
if (irc == NULL)
return (-1);
- nat = nat; /* LINT */
-
aps->aps_data = irc;
aps->aps_psiz = sizeof(ircinfo_t);
@@ -422,8 +420,7 @@ ipf_p_irc_send(fr_info_t *fin, nat_t *nat)
int
-ipf_p_irc_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_irc_out(void *arg, fr_info_t *fin, ap_session_t *aps __unused, nat_t *nat)
{
- aps = aps; /* LINT */
return (ipf_p_irc_send(fin, nat));
}
diff --git a/sys/netpfil/ipfilter/netinet/ip_lookup.c b/sys/netpfil/ipfilter/netinet/ip_lookup.c
index b46d1b875003..a52dbef00166 100644
--- a/sys/netpfil/ipfilter/netinet/ip_lookup.c
+++ b/sys/netpfil/ipfilter/netinet/ip_lookup.c
@@ -230,13 +230,11 @@ ipf_lookup_soft_destroy(ipf_main_softc_t *softc, void *arg)
/* ------------------------------------------------------------------------ */
int
ipf_lookup_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
- int mode, int uid, void *ctx)
+ int mode __unused, int uid, void *ctx)
{
int err;
SPL_INT(s);
- mode = mode; /* LINT */
-
SPL_NET(s);
switch (cmd)
diff --git a/sys/netpfil/ipfilter/netinet/ip_nat.c b/sys/netpfil/ipfilter/netinet/ip_nat.c
index a13c6129a287..972511f43bd5 100644
--- a/sys/netpfil/ipfilter/netinet/ip_nat.c
+++ b/sys/netpfil/ipfilter/netinet/ip_nat.c
@@ -3224,13 +3224,10 @@ ipf_nat_finalise(fr_info_t *fin, nat_t *nat)
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_32_t sum1, sum2, sumd;
frentry_t *fr;
- u_32_t flags;
#if SOLARIS && defined(_KERNEL) && defined(ICK_M_CTL_MAGIC)
qpktinfo_t *qpi = fin->fin_qpi;
#endif
- flags = nat->nat_flags;
-
switch (nat->nat_pr[0])
{
case IPPROTO_ICMP :
@@ -3538,8 +3535,8 @@ ipf_nat_icmperrorlookup(fr_info_t *fin, int dir)
{
ipf_main_softc_t *softc = fin->fin_main_soft;
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
- int flags = 0, type, minlen;
- icmphdr_t *icmp, *orgicmp;
+ int flags = 0, minlen;
+ icmphdr_t *orgicmp;
nat_stat_side_t *nside;
tcphdr_t *tcp = NULL;
u_short data[2];
@@ -3547,8 +3544,6 @@ ipf_nat_icmperrorlookup(fr_info_t *fin, int dir)
ip_t *oip;
u_int p;
- icmp = fin->fin_dp;
- type = icmp->icmp_type;
nside = &softn->ipf_nat_stats.ns_side[fin->fin_out];
/*
* Does it at least have the return (basic) IP header ?
@@ -3999,9 +3994,7 @@ ipf_nat_inlookup(fr_info_t *fin, u_int flags, u_int p,
ipf_main_softc_t *softc = fin->fin_main_soft;
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_short sport, dport;
- grehdr_t *gre;
ipnat_t *ipn;
- u_int sflags;
nat_t *nat;
int nflags;
u_32_t dst;
@@ -4009,9 +4002,7 @@ ipf_nat_inlookup(fr_info_t *fin, u_int flags, u_int p,
u_int hv, rhv;
ifp = fin->fin_ifp;
- gre = NULL;
dst = mapdst.s_addr;
- sflags = flags & NAT_TCPUDPICMP;
switch (p)
{
@@ -4330,14 +4321,12 @@ ipf_nat_outlookup(fr_info_t *fin, u_int flags, u_int p,
ipf_main_softc_t *softc = fin->fin_main_soft;
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_short sport, dport;
- u_int sflags;
ipnat_t *ipn;
nat_t *nat;
void *ifp;
u_int hv;
ifp = fin->fin_ifp;
- sflags = flags & IPN_TCPUDPICMP;
switch (p)
{
@@ -4756,7 +4745,6 @@ ipf_nat_checkout(fr_info_t *fin, u_32_t *passp)
struct ifnet *ifp, *sifp;
ipf_main_softc_t *softc;
ipf_nat_softc_t *softn;
- icmphdr_t *icmp = NULL;
tcphdr_t *tcp = NULL;
int rval, natfailed;
u_int nflags = 0;
@@ -4802,8 +4790,6 @@ ipf_nat_checkout(fr_info_t *fin, u_32_t *passp)
nflags = IPN_UDP;
break;
case IPPROTO_ICMP :
- icmp = fin->fin_dp;
-
/*
* This is an incoming packet, so the destination is
* the icmp_id and the source port equals 0
@@ -5463,7 +5449,10 @@ ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags)
{
ipf_main_softc_t *softc = fin->fin_main_soft;
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
- u_32_t sumd, ipsumd, sum1, sum2;
+ u_32_t sumd, sum1, sum2;
+#if !defined(_KERNEL) || SOLARIS
+ u_32_t ipsumd;
+#endif
icmphdr_t *icmp;
tcphdr_t *tcp;
ipnat_t *np;
@@ -5499,7 +5488,9 @@ ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags)
ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
+#if !defined(_KERNEL) || SOLARIS
ipsumd = nat->nat_ipsumd;
+#endif
/*
* Fix up checksums, not by recalculating them, but
* simply computing adjustments.
@@ -5521,7 +5512,9 @@ ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags)
sum1 = nat->nat_osrcaddr;
sum2 = nat->nat_nsrcaddr;
CALC_SUMD(sum1, sum2, sumd);
+#if !defined(_KERNEL) || SOLARIS
ipsumd -= sumd;
+#endif
}
fin->fin_ip->ip_dst = nat->nat_ndstip;
fin->fin_daddr = nat->nat_ndstaddr;
@@ -5538,7 +5531,9 @@ ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags)
sum1 = nat->nat_odstaddr;
sum2 = nat->nat_ndstaddr;
CALC_SUMD(sum1, sum2, sumd);
+#if !defined(_KERNEL) || SOLARIS
ipsumd -= sumd;
+#endif
}
fin->fin_ip->ip_dst = nat->nat_osrcip;
fin->fin_daddr = nat->nat_osrcaddr;
@@ -7352,30 +7347,18 @@ ipf_nat_nextaddr(fr_info_t *fin, nat_addr_t *na, u_32_t *old, u_32_t *dst)
{
ipf_main_softc_t *softc = fin->fin_main_soft;
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
- u_32_t amin, amax, new;
+ u_32_t new;
i6addr_t newip;
int error;
new = 0;
- amin = na->na_addr[0].in4.s_addr;
switch (na->na_atype)
{
case FRI_RANGE :
- amax = na->na_addr[1].in4.s_addr;
- break;
-
case FRI_NETMASKED :
case FRI_DYNAMIC :
case FRI_NORMAL :
- /*
- * Compute the maximum address by adding the inverse of the
- * netmask to the minimum address.
- */
- amax = ~na->na_addr[1].in4.s_addr;
- amax |= amin;
- break;
-
case FRI_LOOKUP :
break;
diff --git a/sys/netpfil/ipfilter/netinet/ip_nat6.c b/sys/netpfil/ipfilter/netinet/ip_nat6.c
index dbe19c40c2f2..6d5913177b90 100644
--- a/sys/netpfil/ipfilter/netinet/ip_nat6.c
+++ b/sys/netpfil/ipfilter/netinet/ip_nat6.c
@@ -1130,9 +1130,6 @@ ipf_nat6_finalise(fr_info_t *fin, nat_t *nat)
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_32_t sum1, sum2, sumd;
frentry_t *fr;
- u_32_t flags;
-
- flags = nat->nat_flags;
switch (fin->fin_p)
{
@@ -1355,8 +1352,8 @@ ipf_nat6_icmperrorlookup(fr_info_t *fin, int dir)
{
ipf_main_softc_t *softc = fin->fin_main_soft;
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
- struct icmp6_hdr *icmp6, *orgicmp;
- int flags = 0, type, minlen;
+ struct icmp6_hdr *orgicmp;
+ int flags = 0, minlen;
nat_stat_side_t *nside;
tcphdr_t *tcp = NULL;
u_short data[2];
@@ -1365,8 +1362,6 @@ ipf_nat6_icmperrorlookup(fr_info_t *fin, int dir)
u_int p;
minlen = 40;
- icmp6 = fin->fin_dp;
- type = icmp6->icmp6_type;
nside = &softn->ipf_nat_stats.ns_side6[fin->fin_out];
/*
* Does it at least have the return (basic) IP header ?
@@ -1500,9 +1495,8 @@ ipf_nat6_ip6subtract(i6addr_t *ip1, i6addr_t *ip2)
i6addr_t l1, l2, d;
u_short *s1, *s2, *ds;
u_32_t r;
- int i, neg;
+ int i;
- neg = 0;
l1 = *ip1;
l2 = *ip2;
s1 = (u_short *)&l1;
@@ -1519,7 +1513,6 @@ ipf_nat6_ip6subtract(i6addr_t *ip1, i6addr_t *ip2)
}
if (s2[0] > s1[0]) {
ds[0] = s2[0] + 0x10000 - s1[0];
- neg = 1;
} else {
ds[0] = s2[0] - s1[0];
}
@@ -1869,9 +1862,9 @@ ipf_nat6_inlookup(fr_info_t *fin, u_int flags, u_int p,
ipf_main_softc_t *softc = fin->fin_main_soft;
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_short sport, dport;
- grehdr_t *gre;
+#ifdef IPF_V6_PROXIES
ipnat_t *ipn;
- u_int sflags;
+#endif
nat_t *nat;
int nflags;
i6addr_t dst;
@@ -1881,10 +1874,7 @@ ipf_nat6_inlookup(fr_info_t *fin, u_int flags, u_int p,
ifp = fin->fin_ifp;
sport = 0;
dport = 0;
- gre = NULL;
dst.in6 = *mapdst;
- sflags = flags & NAT_TCPUDPICMP;
-
switch (p)
{
case IPPROTO_TCP :
@@ -1962,8 +1952,8 @@ ipf_nat6_inlookup(fr_info_t *fin, u_int flags, u_int p,
if ((nat->nat_flags & IPN_TCPUDP) != 0) {
- ipn = nat->nat_ptr;
#ifdef IPF_V6_PROXIES
+ ipn = nat->nat_ptr;
if ((ipn != NULL) && (nat->nat_aps != NULL))
if (appr_match(fin, nat) != 0)
continue;
@@ -2192,14 +2182,14 @@ ipf_nat6_outlookup(fr_info_t *fin, u_int flags, u_int p,
ipf_main_softc_t *softc = fin->fin_main_soft;
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_short sport, dport;
- u_int sflags;
+#ifdef IPF_V6_PROXIES
ipnat_t *ipn;
+#endif
nat_t *nat;
void *ifp;
u_int hv;
ifp = fin->fin_ifp;
- sflags = flags & IPN_TCPUDPICMP;
sport = 0;
dport = 0;
@@ -2280,8 +2270,8 @@ ipf_nat6_outlookup(fr_info_t *fin, u_int flags, u_int p,
break;
}
- ipn = nat->nat_ptr;
#ifdef IPF_V6_PROXIES
+ ipn = nat->nat_ptr;
if ((ipn != NULL) && (nat->nat_aps != NULL))
if (appr_match(fin, nat) != 0)
continue;
@@ -2568,7 +2558,6 @@ ipf_nat6_checkout(fr_info_t *fin, u_32_t *passp)
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
struct icmp6_hdr *icmp6 = NULL;
struct ifnet *ifp, *sifp;
- tcphdr_t *tcp = NULL;
int rval, natfailed;
ipnat_t *np = NULL;
u_int nflags = 0;
@@ -2621,9 +2610,6 @@ ipf_nat6_checkout(fr_info_t *fin, u_32_t *passp)
default :
break;
}
-
- if ((nflags & IPN_TCPUDP))
- tcp = fin->fin_dp;
}
ipa = fin->fin_src6;
@@ -2965,7 +2951,9 @@ ipf_nat6_checkin(fr_info_t *fin, u_32_t *passp)
int rval, natfailed;
struct ifnet *ifp;
i6addr_t ipa, iph;
- tcphdr_t *tcp;
+#ifdef IPF_V6_PROXIES
+ tcphdr_t *tcp = NULL;
+#endif
u_short dport;
ipnat_t *np;
nat_t *nat;
@@ -2973,7 +2961,6 @@ ipf_nat6_checkin(fr_info_t *fin, u_32_t *passp)
if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0)
return (0);
- tcp = NULL;
icmp6 = NULL;
dport = 0;
natadd = 1;
@@ -3014,7 +3001,9 @@ ipf_nat6_checkin(fr_info_t *fin, u_32_t *passp)
}
if ((nflags & IPN_TCPUDP)) {
+#ifdef IPF_V6_PROXIES
tcp = fin->fin_dp;
+#endif
dport = fin->fin_data[1];
}
}
@@ -3802,32 +3791,19 @@ ipf_nat6_nextaddr(fr_info_t *fin, nat_addr_t *na, i6addr_t *old, i6addr_t *dst)
ipf_main_softc_t *softc = fin->fin_main_soft;
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
i6addr_t newip, new;
- u_32_t amin, amax;
int error;
new.i6[0] = 0;
new.i6[1] = 0;
new.i6[2] = 0;
new.i6[3] = 0;
- amin = na->na_addr[0].in4.s_addr;
switch (na->na_atype)
{
case FRI_RANGE :
- amax = na->na_addr[1].in4.s_addr;
- break;
-
case FRI_NETMASKED :
case FRI_DYNAMIC :
case FRI_NORMAL :
- /*
- * Compute the maximum address by adding the inverse of the
- * netmask to the minimum address.
- */
- amax = ~na->na_addr[1].in4.s_addr;
- amax |= amin;
- break;
-
case FRI_LOOKUP :
break;
diff --git a/sys/netpfil/ipfilter/netinet/ip_netbios_pxy.c b/sys/netpfil/ipfilter/netinet/ip_netbios_pxy.c
index 2ad642adfbcd..f9c1ab50b8a2 100644
--- a/sys/netpfil/ipfilter/netinet/ip_netbios_pxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_netbios_pxy.c
@@ -67,7 +67,7 @@ ipf_p_netbios_main_unload(void)
int
-ipf_p_netbios_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_netbios_out(void *arg, fr_info_t *fin, ap_session_t *aps __unused, nat_t *nat __unused)
{
char dgmbuf[6];
int off, dlen;
@@ -75,9 +75,6 @@ ipf_p_netbios_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
ip_t *ip;
mb_t *m;
- aps = aps; /* LINT */
- nat = nat; /* LINT */
-
m = fin->fin_m;
dlen = fin->fin_dlen - sizeof(*udp);
/*
diff --git a/sys/netpfil/ipfilter/netinet/ip_pptp_pxy.c b/sys/netpfil/ipfilter/netinet/ip_pptp_pxy.c
index 0ac19b067d2d..dc4c67dc14f0 100644
--- a/sys/netpfil/ipfilter/netinet/ip_pptp_pxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_pptp_pxy.c
@@ -281,7 +281,6 @@ ipf_p_pptp_nextmessage(fr_info_t *fin, nat_t *nat, pptp_pxy_t *pptp, int rev)
tcphdr_t *tcp;
int dlen, off;
u_short len;
- char *msg;
tcp = fin->fin_dp;
dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
@@ -310,8 +309,6 @@ ipf_p_pptp_nextmessage(fr_info_t *fin, nat_t *nat, pptp_pxy_t *pptp, int rev)
return (-1);
}
- msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2);
-
while (dlen > 0) {
off += pptps->pptps_bytes;
if (pptps->pptps_gothdr == 0) {
@@ -337,7 +334,6 @@ ipf_p_pptp_nextmessage(fr_info_t *fin, nat_t *nat, pptp_pxy_t *pptp, int rev)
}
}
dlen -= len;
- msg += len;
off += len;
pptps->pptps_gothdr = 1;
@@ -381,7 +377,6 @@ ipf_p_pptp_nextmessage(fr_info_t *fin, nat_t *nat, pptp_pxy_t *pptp, int rev)
pptps->pptps_len = 0;
start += len;
- msg += len;
dlen -= len;
}
diff --git a/sys/netpfil/ipfilter/netinet/ip_proxy.c b/sys/netpfil/ipfilter/netinet/ip_proxy.c
index 9785fc37d3da..9fb6dbd2a9e1 100644
--- a/sys/netpfil/ipfilter/netinet/ip_proxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_proxy.c
@@ -679,14 +679,12 @@ ipf_proxy_ok(fr_info_t *fin, tcphdr_t *tcp, ipnat_t *np)
/* ------------------------------------------------------------------------ */
int
ipf_proxy_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
- int mode, void *ctx)
+ int mode __unused, void *ctx)
{
ap_ctl_t ctl;
caddr_t ptr;
int error;
- mode = mode; /* LINT */
-
switch (cmd)
{
case SIOCPROXY :
diff --git a/sys/netpfil/ipfilter/netinet/ip_raudio_pxy.c b/sys/netpfil/ipfilter/netinet/ip_raudio_pxy.c
index 2cfaaa58200f..94f0e3ada707 100644
--- a/sys/netpfil/ipfilter/netinet/ip_raudio_pxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_raudio_pxy.c
@@ -49,12 +49,10 @@ ipf_p_raudio_main_unload(void)
* Setup for a new proxy to handle Real Audio.
*/
int
-ipf_p_raudio_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_raudio_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused)
{
raudio_t *rap;
- nat = nat; /* LINT */
-
if (fin->fin_v != 4)
return (-1);
@@ -72,7 +70,7 @@ ipf_p_raudio_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
int
-ipf_p_raudio_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_raudio_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused)
{
raudio_t *rap = aps->aps_data;
unsigned char membuf[512 + 1], *s;
@@ -82,8 +80,6 @@ ipf_p_raudio_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
int len = 0;
mb_t *m;
- nat = nat; /* LINT */
-
/*
* If we've already processed the start messages, then nothing left
* for the proxy to do.
diff --git a/sys/netpfil/ipfilter/netinet/ip_rcmd_pxy.c b/sys/netpfil/ipfilter/netinet/ip_rcmd_pxy.c
index 778f14f442de..b85794e75499 100644
--- a/sys/netpfil/ipfilter/netinet/ip_rcmd_pxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_rcmd_pxy.c
@@ -63,18 +63,12 @@ ipf_p_rcmd_main_unload(void)
* Setup for a new RCMD proxy.
*/
int
-ipf_p_rcmd_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_rcmd_new(void *arg, fr_info_t *fin __unused, ap_session_t *aps, nat_t *nat)
{
tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
rcmdinfo_t *rc;
ipnat_t *ipn;
- ipnat_t *np;
- int size;
- fin = fin; /* LINT */
-
- np = nat->nat_ptr;
- size = np->in_size;
KMALLOC(rc, rcmdinfo_t *);
if (rc == NULL) {
#ifdef IP_RCMD_PROXY_DEBUG
diff --git a/sys/netpfil/ipfilter/netinet/ip_rpcb_pxy.c b/sys/netpfil/ipfilter/netinet/ip_rpcb_pxy.c
index f8f4d2d325e1..c608f84d7b3b 100644
--- a/sys/netpfil/ipfilter/netinet/ip_rpcb_pxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_rpcb_pxy.c
@@ -144,12 +144,10 @@ ipf_p_rpcb_main_unload(void)
/* Allocate resources for per-session proxy structures. */
/* -------------------------------------------------------------------- */
int
-ipf_p_rpcb_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_rpcb_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat __unused)
{
rpcb_session_t *rs;
- nat = nat; /* LINT */
-
if (fin->fin_v != 4)
return (-1);
@@ -1023,10 +1021,8 @@ ipf_p_rpcb_lookup(rpcb_session_t *rs, u_32_t xid)
/* Free the RPCB transaction record rx from the chain of entries. */
/* -------------------------------------------------------------------- */
static void
-ipf_p_rpcb_deref(rpcb_session_t *rs, rpcb_xact_t *rx)
+ipf_p_rpcb_deref(rpcb_session_t *rs __unused, rpcb_xact_t *rx)
{
- rs = rs; /* LINT */
-
if (rx == NULL)
return;
diff --git a/sys/netpfil/ipfilter/netinet/ip_state.c b/sys/netpfil/ipfilter/netinet/ip_state.c
index 8fe11e3f1215..36fdf23cd062 100644
--- a/sys/netpfil/ipfilter/netinet/ip_state.c
+++ b/sys/netpfil/ipfilter/netinet/ip_state.c
@@ -883,7 +883,7 @@ ipf_state_putent(ipf_main_softc_t *softc, ipf_state_softc_t *softs,
{
ipstate_t *is, *isn;
ipstate_save_t ips;
- int error, out, i;
+ int error, i;
frentry_t *fr;
char *name;
@@ -929,7 +929,6 @@ ipf_state_putent(ipf_main_softc_t *softc, ipf_state_softc_t *softs,
return (ENOMEM);
}
bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr));
- out = fr->fr_flags & FR_OUTQUE ? 1 : 0;
isn->is_rule = fr;
ips.ips_is.is_rule = fr;
MUTEX_NUKE(&fr->fr_lock);
@@ -2207,20 +2206,6 @@ ipf_state_tcpinwindow(fr_info_t *fin, tcpdata_t *fdata, tcpdata_t *tdata,
(ackskew >= -1) && (ackskew <= 1)) {
inseq = 1;
} else if (!(flags & IS_TCPFSM)) {
- int i;
-
- i = (fin->fin_rev << 1) + fin->fin_out;
-
-#if 0
- if (is_pkts[i]0 == 0) {
- /*
- * Picking up a connection in the middle, the "next"
- * packet seen from a direction that is new should be
- * accepted, even if it appears out of sequence.
- */
- inseq = 1;
- } else
-#endif
if (!(fdata->td_winflags &
(TCP_WSCALE_SEEN|TCP_WSCALE_FIRST))) {
/*
@@ -2616,7 +2601,7 @@ ipf_checkicmpmatchingstate(fr_info_t *fin)
icmphdr_t *icmp;
fr_info_t ofin;
tcphdr_t *tcp;
- int type, len;
+ int len;
u_char pr;
ip_t *oip;
u_int hv;
@@ -2634,7 +2619,6 @@ ipf_checkicmpmatchingstate(fr_info_t *fin)
return (NULL);
}
ic = fin->fin_dp;
- type = ic->icmp_type;
oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN);
/*
@@ -4362,7 +4346,6 @@ ipf_checkicmp6matchingstate(fr_info_t *fin)
ip6_t *oip6;
u_char pr;
u_int hv;
- int type;
/*
* Does it at least have the return (basic) IP header ?
@@ -4377,7 +4360,6 @@ ipf_checkicmp6matchingstate(fr_info_t *fin)
}
ic6 = fin->fin_dp;
- type = ic6->icmp6_type;
oip6 = (ip6_t *)((char *)ic6 + ICMPERR_ICMPHLEN);
if (fin->fin_plen < sizeof(*oip6)) {
diff --git a/sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c b/sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c
index d81de100120b..3c737b38aacc 100644
--- a/sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c
+++ b/sys/netpfil/ipfilter/netinet/ip_tftp_pxy.c
@@ -151,7 +151,7 @@ ipf_p_tftp_in(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
int
-ipf_p_tftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
+ipf_p_tftp_new(void *arg, fr_info_t *fin __unused, ap_session_t *aps, nat_t *nat)
{
udphdr_t *udp;
tftpinfo_t *ti;
@@ -159,8 +159,6 @@ ipf_p_tftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
ipnat_t *np;
int size;
- fin = fin; /* LINT */
-
np = nat->nat_ptr;
size = np->in_size;
diff --git a/sys/netpfil/ipfilter/netinet/ipf_rb.h b/sys/netpfil/ipfilter/netinet/ipf_rb.h
index e047c7f44a4a..334311502aab 100644
--- a/sys/netpfil/ipfilter/netinet/ipf_rb.h
+++ b/sys/netpfil/ipfilter/netinet/ipf_rb.h
@@ -305,13 +305,11 @@ _n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\
_t *prev; \
_t *next; \
_t *node = head->top._f.right; \
- _t *base; \
\
while (node != &_n##_rb_zero) \
node = node->_f.left; \
\
for (;;) { \
- base = node; \
prev = node; \
while ((node->_f.parent->_f.right == node) && \
(node != &_n##_rb_zero)) { \
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 923633d76df7..c129c8c49921 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -196,7 +196,7 @@ SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"Firewall");
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_one_pass), 0,
- "Only do a single pass through ipfw when using dummynet(4)");
+ "Only do a single pass through ipfw when using dummynet(4), ipfw_nat or other divert(4)-like interfaces");
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(autoinc_step), 0,
"Rule number auto-increment step");
diff --git a/sys/netpfil/pf/if_pflog.c b/sys/netpfil/pf/if_pflog.c
index 6a87ea2471cb..cb96d2fcc44c 100644
--- a/sys/netpfil/pf/if_pflog.c
+++ b/sys/netpfil/pf/if_pflog.c
@@ -284,12 +284,12 @@ pflog_packet(uint8_t action, u_int8_t reason,
* state lock, since this leads to unsafe LOR.
* These conditions are very very rare, however.
*/
- if (trigger->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done && lookupsafe)
+ if (trigger->log & PF_LOG_USER && !pd->lookup.done && lookupsafe)
pd->lookup.done = pf_socket_lookup(pd);
- if (pd->lookup.done > 0)
+ if (trigger->log & PF_LOG_USER && pd->lookup.done > 0)
hdr.uid = pd->lookup.uid;
else
- hdr.uid = UID_MAX;
+ hdr.uid = -1;
hdr.pid = NO_PID;
hdr.rule_uid = rm->cuid;
hdr.rule_pid = rm->cpid;
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index fdedb9424117..4e03584b8f85 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -532,6 +532,7 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
struct pf_kpooladdr *rpool_first;
int error;
uint8_t rt = 0;
+ int n = 0;
PF_RULES_RASSERT();
@@ -557,10 +558,12 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
*/
if (sp->pfs_1301.rule != htonl(-1) && sp->pfs_1301.anchor == htonl(-1) &&
(flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->pfs_1301.rule) <
- pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
- r = pf_main_ruleset.rules[
- PF_RULESET_FILTER].active.ptr_array[ntohl(sp->pfs_1301.rule)];
- else
+ pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) {
+ TAILQ_FOREACH(r, pf_main_ruleset.rules[
+ PF_RULESET_FILTER].active.ptr, entries)
+ if (ntohl(sp->pfs_1301.rule) == n++)
+ break;
+ } else
r = &V_pf_default_rule;
/*
@@ -763,6 +766,10 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
__func__, msg_version);
}
+ if (! (st->act.rtableid == -1 ||
+ (st->act.rtableid >= 0 && st->act.rtableid < rt_numfibs)))
+ goto cleanup;
+
st->id = sp->pfs_1301.id;
st->creatorid = sp->pfs_1301.creatorid;
pf_state_peer_ntoh(&sp->pfs_1301.src, &st->src);
@@ -1083,7 +1090,7 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action)
msg_version = PFSYNC_MSG_VERSION_1400;
break;
default:
- V_pfsyncstats.pfsyncs_badact++;
+ V_pfsyncstats.pfsyncs_badver++;
return (-1);
}
@@ -1110,9 +1117,8 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action)
continue;
}
- if (pfsync_state_import(sp, flags, msg_version) == ENOMEM)
- /* Drop out, but process the rest of the actions. */
- break;
+ if (pfsync_state_import(sp, flags, msg_version) != 0)
+ V_pfsyncstats.pfsyncs_badact++;
}
return (total_len);
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index accc811a12ba..009f7e4d78b1 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -682,7 +682,8 @@ pf_packet_rework_nat(struct pf_pdesc *pd, int off, struct pf_state_key *nk)
0);
break;
case AF_INET6:
- PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
+ pf_addrcpy(pd->src, &nk->addr[pd->sidx],
+ pd->af);
break;
default:
unhandled_af(pd->af);
@@ -696,7 +697,8 @@ pf_packet_rework_nat(struct pf_pdesc *pd, int off, struct pf_state_key *nk)
0);
break;
case AF_INET6:
- PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
+ pf_addrcpy(pd->dst, &nk->addr[pd->didx],
+ pd->af);
break;
default:
unhandled_af(pd->af);
@@ -1084,9 +1086,9 @@ pf_insert_src_node(struct pf_ksrc_node *sns[PF_SN_MAX],
(*sn)->af = af;
(*sn)->rule = r_track;
- PF_ACPY(&(*sn)->addr, src, af);
+ pf_addrcpy(&(*sn)->addr, src, af);
if (raddr != NULL)
- PF_ACPY(&(*sn)->raddr, raddr, af);
+ pf_addrcpy(&(*sn)->raddr, raddr, af);
(*sn)->rkif = rkif;
LIST_INSERT_HEAD(&(*sh)->nodes, *sn, entry);
(*sn)->creation = time_uptime;
@@ -1687,9 +1689,9 @@ pf_state_key_addr_setup(struct pf_pdesc *pd,
copy:
#endif /* INET6 */
if (saddr)
- PF_ACPY(&key->addr[pd->sidx], saddr, pd->af);
+ pf_addrcpy(&key->addr[pd->sidx], saddr, pd->af);
if (daddr)
- PF_ACPY(&key->addr[pd->didx], daddr, pd->af);
+ pf_addrcpy(&key->addr[pd->didx], daddr, pd->af);
return (0);
}
@@ -1734,13 +1736,17 @@ pf_state_key_setup(struct pf_pdesc *pd, u_int16_t sport, u_int16_t dport,
bzero(&(*nk)->addr[0], sizeof((*nk)->addr[0]));
bzero(&(*nk)->addr[1], sizeof((*nk)->addr[1]));
if (pd->dir == PF_IN) {
- PF_ACPY(&(*nk)->addr[pd->didx], &pd->nsaddr, pd->naf);
- PF_ACPY(&(*nk)->addr[pd->sidx], &pd->ndaddr, pd->naf);
+ pf_addrcpy(&(*nk)->addr[pd->didx], &pd->nsaddr,
+ pd->naf);
+ pf_addrcpy(&(*nk)->addr[pd->sidx], &pd->ndaddr,
+ pd->naf);
(*nk)->port[pd->didx] = pd->nsport;
(*nk)->port[pd->sidx] = pd->ndport;
} else {
- PF_ACPY(&(*nk)->addr[pd->sidx], &pd->nsaddr, pd->naf);
- PF_ACPY(&(*nk)->addr[pd->didx], &pd->ndaddr, pd->naf);
+ pf_addrcpy(&(*nk)->addr[pd->sidx], &pd->nsaddr,
+ pd->naf);
+ pf_addrcpy(&(*nk)->addr[pd->didx], &pd->ndaddr,
+ pd->naf);
(*nk)->port[pd->sidx] = pd->nsport;
(*nk)->port[pd->didx] = pd->ndport;
}
@@ -2053,11 +2059,11 @@ pf_udp_mapping_create(sa_family_t af, struct pf_addr *src_addr, uint16_t src_por
mapping = uma_zalloc(V_pf_udp_mapping_z, M_NOWAIT | M_ZERO);
if (mapping == NULL)
return (NULL);
- PF_ACPY(&mapping->endpoints[0].addr, src_addr, af);
+ pf_addrcpy(&mapping->endpoints[0].addr, src_addr, af);
mapping->endpoints[0].port = src_port;
mapping->endpoints[0].af = af;
mapping->endpoints[0].mapping = mapping;
- PF_ACPY(&mapping->endpoints[1].addr, nat_addr, af);
+ pf_addrcpy(&mapping->endpoints[1].addr, nat_addr, af);
mapping->endpoints[1].port = nat_port;
mapping->endpoints[1].af = af;
mapping->endpoints[1].mapping = mapping;
@@ -3295,9 +3301,9 @@ pf_change_ap(struct pf_pdesc *pd, struct pf_addr *a, u_int16_t *p,
MPASS(pd->ip_sum);
}
- PF_ACPY(&ao, a, pd->af);
+ pf_addrcpy(&ao, a, pd->af);
if (pd->af == pd->naf)
- PF_ACPY(a, an, pd->af);
+ pf_addrcpy(a, an, pd->af);
if (pd->m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6))
*pd->pcksum = ~*pd->pcksum;
@@ -3426,8 +3432,8 @@ pf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
{
struct pf_addr ao;
- PF_ACPY(&ao, a, AF_INET6);
- PF_ACPY(a, an, AF_INET6);
+ pf_addrcpy(&ao, a, AF_INET6);
+ pf_addrcpy(a, an, AF_INET6);
*c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
@@ -3450,9 +3456,9 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
{
struct pf_addr oia, ooa;
- PF_ACPY(&oia, ia, af);
+ pf_addrcpy(&oia, ia, af);
if (oa)
- PF_ACPY(&ooa, oa, af);
+ pf_addrcpy(&ooa, oa, af);
/* Change inner protocol port, fix inner protocol checksum. */
if (ip != NULL) {
@@ -3469,7 +3475,7 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
}
/* Change inner ip address, fix inner ip and icmp checksums. */
- PF_ACPY(ia, na, af);
+ pf_addrcpy(ia, na, af);
switch (af) {
#ifdef INET
case AF_INET: {
@@ -3503,7 +3509,7 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
}
/* Outer ip address, fix outer ip or icmpv6 checksum, if necessary. */
if (oa) {
- PF_ACPY(oa, na, af);
+ pf_addrcpy(oa, na, af);
switch (af) {
#ifdef INET
case AF_INET:
@@ -4299,8 +4305,8 @@ pf_undo_nat(struct pf_krule *nr, struct pf_pdesc *pd, uint16_t bip_sum)
{
/* undo NAT changes, if they have taken place */
if (nr != NULL) {
- PF_ACPY(pd->src, &pd->osrc, pd->af);
- PF_ACPY(pd->dst, &pd->odst, pd->af);
+ pf_addrcpy(pd->src, &pd->osrc, pd->af);
+ pf_addrcpy(pd->dst, &pd->odst, pd->af);
if (pd->sport)
*pd->sport = pd->osport;
if (pd->dport)
@@ -4573,7 +4579,7 @@ pf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
static int
pf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
{
- if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
+ if (u == -1 && op != PF_OP_EQ && op != PF_OP_NE)
return (0);
return (pf_match(op, a1, a2, u));
}
@@ -4581,7 +4587,7 @@ pf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
static int
pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
{
- if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
+ if (g == -1 && op != PF_OP_EQ && op != PF_OP_NE)
return (0);
return (pf_match(op, a1, a2, g));
}
@@ -4676,10 +4682,11 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct pf_krule *r)
} else {
rv = pf_match_rule(ctx, &r->anchor->ruleset);
/*
- * Unless there was an error inside the anchor,
- * retain its quick state.
+ * Unless errors occured, stop iff any rule matched
+ * within quick anchors.
*/
- if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK)
+ if (rv != PF_TEST_FAIL && r->quick == PF_TEST_QUICK &&
+ *ctx->am == r)
rv = PF_TEST_QUICK;
}
@@ -4790,7 +4797,6 @@ pf_step_out_of_keth_anchor(struct pf_keth_anchor_stackframe *stack, int *depth,
return (quick);
}
-#ifdef INET6
void
pf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
@@ -4802,6 +4808,7 @@ pf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
break;
#endif /* INET */
+#ifdef INET6
case AF_INET6:
naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
@@ -4812,6 +4819,7 @@ pf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
break;
+#endif /* INET6 */
}
}
@@ -4824,6 +4832,7 @@ pf_addr_inc(struct pf_addr *addr, sa_family_t af)
addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
break;
#endif /* INET */
+#ifdef INET6
case AF_INET6:
if (addr->addr32[3] == 0xffffffff) {
addr->addr32[3] = 0;
@@ -4843,9 +4852,9 @@ pf_addr_inc(struct pf_addr *addr, sa_family_t af)
addr->addr32[3] =
htonl(ntohl(addr->addr32[3]) + 1);
break;
+#endif /* INET6 */
}
}
-#endif /* INET6 */
void
pf_rule_to_actions(struct pf_krule *r, struct pf_rule_actions *a)
@@ -4905,8 +4914,8 @@ pf_socket_lookup(struct pf_pdesc *pd)
struct inpcbinfo *pi;
struct inpcb *inp;
- pd->lookup.uid = UID_MAX;
- pd->lookup.gid = GID_MAX;
+ pd->lookup.uid = -1;
+ pd->lookup.gid = -1;
switch (pd->proto) {
case IPPROTO_TCP:
@@ -5744,8 +5753,8 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
ctx.reason = *reason;
SLIST_INIT(&ctx.rules);
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ pf_addrcpy(&pd->nsaddr, pd->src, pd->af);
+ pf_addrcpy(&pd->ndaddr, pd->dst, pd->af);
if (inp != NULL) {
INP_LOCK_ASSERT(inp);
@@ -5892,18 +5901,17 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
M_SETFIB(pd->m, pd->act.rtableid);
if (r->rt) {
- struct pf_ksrc_node *sn = NULL;
- struct pf_srchash *snh = NULL;
/*
* Set act.rt here instead of in pf_rule_to_actions() because
* it is applied only from the last pass rule.
*/
pd->act.rt = r->rt;
- /* Don't use REASON_SET, pf_map_addr increases the reason counters */
- ctx.reason = pf_map_addr_sn(pd->af, r, pd->src, &pd->act.rt_addr,
- &pd->act.rt_kif, NULL, &sn, &snh, &(r->route), PF_SN_ROUTE);
- if (ctx.reason != 0)
+ if ((transerror = pf_map_addr_sn(pd->af, r, pd->src,
+ &pd->act.rt_addr, &pd->act.rt_kif, NULL, &(r->route),
+ PF_SN_ROUTE)) != PFRES_MATCH) {
+ REASON_SET(&ctx.reason, transerror);
goto cleanup;
+ }
}
if (pd->virtual_proto != PF_VPROTO_FRAGMENT &&
@@ -6047,9 +6055,16 @@ pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx,
/* src node for translation rule */
if (ctx->nr != NULL) {
KASSERT(ctx->nat_pool != NULL, ("%s: nat_pool is NULL", __func__));
+ /*
+ * The NAT addresses are chosen during ruleset parsing.
+ * The new afto code stores post-nat addresses in nsaddr.
+ * The old nat code (also used for new nat-to rules) creates
+ * state keys and stores addresses in them.
+ */
if ((ctx->nat_pool->opts & PF_POOL_STICKYADDR) &&
(sn_reason = pf_insert_src_node(sns, snhs, ctx->nr,
- &ctx->sk->addr[pd->sidx], pd->af, &ctx->nk->addr[1], NULL,
+ ctx->sk ? &(ctx->sk->addr[pd->sidx]) : pd->src, pd->af,
+ ctx->nk ? &(ctx->nk->addr[1]) : &(pd->nsaddr), NULL,
PF_SN_NAT)) != 0 ) {
REASON_SET(&ctx->reason, sn_reason);
goto csfailed;
@@ -6204,7 +6219,7 @@ pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx,
if (ctx->tag > 0)
s->tag = ctx->tag;
if (pd->proto == IPPROTO_TCP && (tcp_get_flags(th) & (TH_SYN|TH_ACK)) ==
- TH_SYN && r->keep_state == PF_STATE_SYNPROXY) {
+ TH_SYN && r->keep_state == PF_STATE_SYNPROXY && pd->dir == PF_IN) {
pf_set_protostate(s, PF_PEER_SRC, PF_TCPS_PROXY_SRC);
pf_undo_nat(ctx->nr, pd, bip_sum);
s->src.seqhi = arc4random();
@@ -6363,7 +6378,7 @@ pf_translate_compat(struct pf_test_ctx *ctx)
&nk->addr[pd->sidx], nk->port[pd->sidx]);
pd->sport = &th->th_sport;
pd->nsport = th->th_sport;
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ pf_addrcpy(&pd->nsaddr, pd->src, pd->af);
}
if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], pd->af) ||
@@ -6372,7 +6387,7 @@ pf_translate_compat(struct pf_test_ctx *ctx)
&nk->addr[pd->didx], nk->port[pd->didx]);
pd->dport = &th->th_dport;
pd->ndport = th->th_dport;
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ pf_addrcpy(&pd->ndaddr, pd->dst, pd->af);
}
rewrite++;
break;
@@ -6385,7 +6400,7 @@ pf_translate_compat(struct pf_test_ctx *ctx)
nk->port[pd->sidx]);
pd->sport = &pd->hdr.udp.uh_sport;
pd->nsport = pd->hdr.udp.uh_sport;
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ pf_addrcpy(&pd->nsaddr, pd->src, pd->af);
}
if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], pd->af) ||
@@ -6396,7 +6411,7 @@ pf_translate_compat(struct pf_test_ctx *ctx)
nk->port[pd->didx]);
pd->dport = &pd->hdr.udp.uh_dport;
pd->ndport = pd->hdr.udp.uh_dport;
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ pf_addrcpy(&pd->ndaddr, pd->dst, pd->af);
}
rewrite++;
break;
@@ -6409,7 +6424,7 @@ pf_translate_compat(struct pf_test_ctx *ctx)
nk->port[pd->sidx]);
pd->sport = &pd->hdr.sctp.src_port;
pd->nsport = pd->hdr.sctp.src_port;
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ pf_addrcpy(&pd->nsaddr, pd->src, pd->af);
}
if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], pd->af) ||
nk->port[pd->didx] != pd->ndport) {
@@ -6419,7 +6434,7 @@ pf_translate_compat(struct pf_test_ctx *ctx)
nk->port[pd->didx]);
pd->dport = &pd->hdr.sctp.dest_port;
pd->ndport = pd->hdr.sctp.dest_port;
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ pf_addrcpy(&pd->ndaddr, pd->dst, pd->af);
}
break;
}
@@ -6428,13 +6443,13 @@ pf_translate_compat(struct pf_test_ctx *ctx)
if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], AF_INET)) {
pf_change_a(&pd->src->v4.s_addr, pd->ip_sum,
nk->addr[pd->sidx].v4.s_addr, 0);
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ pf_addrcpy(&pd->nsaddr, pd->src, pd->af);
}
if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], AF_INET)) {
pf_change_a(&pd->dst->v4.s_addr, pd->ip_sum,
nk->addr[pd->didx].v4.s_addr, 0);
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ pf_addrcpy(&pd->ndaddr, pd->dst, pd->af);
}
if (ctx->virtual_type == htons(ICMP_ECHO) &&
@@ -6453,13 +6468,13 @@ pf_translate_compat(struct pf_test_ctx *ctx)
if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], AF_INET6)) {
pf_change_a6(pd->src, &pd->hdr.icmp6.icmp6_cksum,
&nk->addr[pd->sidx], 0);
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ pf_addrcpy(&pd->nsaddr, pd->src, pd->af);
}
if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], AF_INET6)) {
pf_change_a6(pd->dst, &pd->hdr.icmp6.icmp6_cksum,
&nk->addr[pd->didx], 0);
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ pf_addrcpy(&pd->ndaddr, pd->dst, pd->af);
}
rewrite++;
break;
@@ -6473,7 +6488,7 @@ pf_translate_compat(struct pf_test_ctx *ctx)
pf_change_a(&pd->src->v4.s_addr,
pd->ip_sum,
nk->addr[pd->sidx].v4.s_addr, 0);
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ pf_addrcpy(&pd->nsaddr, pd->src, pd->af);
}
if (PF_ANEQ(&pd->ndaddr,
@@ -6481,7 +6496,7 @@ pf_translate_compat(struct pf_test_ctx *ctx)
pf_change_a(&pd->dst->v4.s_addr,
pd->ip_sum,
nk->addr[pd->didx].v4.s_addr, 0);
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ pf_addrcpy(&pd->ndaddr, pd->dst, pd->af);
}
break;
#endif /* INET */
@@ -6489,14 +6504,17 @@ pf_translate_compat(struct pf_test_ctx *ctx)
case AF_INET6:
if (PF_ANEQ(&pd->nsaddr,
&nk->addr[pd->sidx], AF_INET6)) {
- PF_ACPY(&pd->nsaddr, &nk->addr[pd->sidx], pd->af);
- PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
+ pf_addrcpy(&pd->nsaddr, &nk->addr[pd->sidx],
+ pd->af);
+ pf_addrcpy(pd->src, &nk->addr[pd->sidx], pd->af);
}
if (PF_ANEQ(&pd->ndaddr,
&nk->addr[pd->didx], AF_INET6)) {
- PF_ACPY(&pd->ndaddr, &nk->addr[pd->didx], pd->af);
- PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
+ pf_addrcpy(&pd->ndaddr, &nk->addr[pd->didx],
+ pd->af);
+ pf_addrcpy(pd->dst, &nk->addr[pd->didx],
+ pd->af);
}
break;
#endif /* INET6 */
@@ -7015,8 +7033,8 @@ pf_test_state(struct pf_kstate **state, struct pf_pdesc *pd, u_short *reason)
bzero(&key, sizeof(key));
key.af = pd->af;
key.proto = pd->virtual_proto;
- PF_ACPY(&key.addr[pd->sidx], pd->src, key.af);
- PF_ACPY(&key.addr[pd->didx], pd->dst, key.af);
+ pf_addrcpy(&key.addr[pd->sidx], pd->src, key.af);
+ pf_addrcpy(&key.addr[pd->didx], pd->dst, key.af);
key.port[pd->sidx] = pd->osport;
key.port[pd->didx] = pd->odport;
@@ -7207,8 +7225,8 @@ pf_test_state(struct pf_kstate **state, struct pf_pdesc *pd, u_short *reason)
}
if (afto) {
- PF_ACPY(&pd->nsaddr, &nk->addr[sidx], nk->af);
- PF_ACPY(&pd->ndaddr, &nk->addr[didx], nk->af);
+ pf_addrcpy(&pd->nsaddr, &nk->addr[sidx], nk->af);
+ pf_addrcpy(&pd->ndaddr, &nk->addr[didx], nk->af);
pd->naf = nk->af;
action = PF_AFRT;
}
@@ -7502,13 +7520,13 @@ again:
key.af = j->pd.af;
key.proto = IPPROTO_SCTP;
if (j->pd.dir == PF_IN) { /* wire side, straight */
- PF_ACPY(&key.addr[0], j->pd.src, key.af);
- PF_ACPY(&key.addr[1], j->pd.dst, key.af);
+ pf_addrcpy(&key.addr[0], j->pd.src, key.af);
+ pf_addrcpy(&key.addr[1], j->pd.dst, key.af);
key.port[0] = j->pd.hdr.sctp.src_port;
key.port[1] = j->pd.hdr.sctp.dest_port;
} else { /* stack side, reverse */
- PF_ACPY(&key.addr[1], j->pd.src, key.af);
- PF_ACPY(&key.addr[0], j->pd.dst, key.af);
+ pf_addrcpy(&key.addr[1], j->pd.src, key.af);
+ pf_addrcpy(&key.addr[0], j->pd.dst, key.af);
key.port[1] = j->pd.hdr.sctp.src_port;
key.port[0] = j->pd.hdr.sctp.dest_port;
}
@@ -7904,8 +7922,10 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
#endif /* INET6 */
}
if (afto) {
- PF_ACPY(&pd->nsaddr, &nk->addr[sidx], nk->af);
- PF_ACPY(&pd->ndaddr, &nk->addr[didx], nk->af);
+ pf_addrcpy(&pd->nsaddr, &nk->addr[sidx],
+ nk->af);
+ pf_addrcpy(&pd->ndaddr, &nk->addr[didx],
+ nk->af);
pd->naf = nk->af;
return (PF_AFRT);
}
@@ -8037,8 +8057,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
key.af = pd2.af;
key.proto = IPPROTO_TCP;
- PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af);
- PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af);
+ pf_addrcpy(&key.addr[pd2.sidx], pd2.src, key.af);
+ pf_addrcpy(&key.addr[pd2.didx], pd2.dst, key.af);
key.port[pd2.sidx] = th->th_sport;
key.port[pd2.didx] = th->th_dport;
@@ -8141,9 +8161,9 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
&nk->addr[didx], pd->af,
nk->af))
return (PF_DROP);
- PF_ACPY(&pd->nsaddr, &nk->addr[pd2.sidx],
- nk->af);
- PF_ACPY(&pd->ndaddr,
+ pf_addrcpy(&pd->nsaddr,
+ &nk->addr[pd2.sidx], nk->af);
+ pf_addrcpy(&pd->ndaddr,
&nk->addr[pd2.didx], nk->af);
if (nk->af == AF_INET) {
pd->proto = IPPROTO_ICMP;
@@ -8232,8 +8252,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
key.af = pd2.af;
key.proto = IPPROTO_UDP;
- PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af);
- PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af);
+ pf_addrcpy(&key.addr[pd2.sidx], pd2.src, key.af);
+ pf_addrcpy(&key.addr[pd2.didx], pd2.dst, key.af);
key.port[pd2.sidx] = uh->uh_sport;
key.port[pd2.didx] = uh->uh_dport;
@@ -8276,9 +8296,9 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
&nk->addr[didx], pd->af,
nk->af))
return (PF_DROP);
- PF_ACPY(&pd->nsaddr,
+ pf_addrcpy(&pd->nsaddr,
&nk->addr[pd2.sidx], nk->af);
- PF_ACPY(&pd->ndaddr,
+ pf_addrcpy(&pd->ndaddr,
&nk->addr[pd2.didx], nk->af);
if (nk->af == AF_INET) {
pd->proto = IPPROTO_ICMP;
@@ -8364,8 +8384,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
key.af = pd2.af;
key.proto = IPPROTO_SCTP;
- PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af);
- PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af);
+ pf_addrcpy(&key.addr[pd2.sidx], pd2.src, key.af);
+ pf_addrcpy(&key.addr[pd2.didx], pd2.dst, key.af);
key.port[pd2.sidx] = sh->src_port;
key.port[pd2.didx] = sh->dest_port;
@@ -8431,9 +8451,9 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
sh->src_port = nk->port[sidx];
sh->dest_port = nk->port[didx];
m_copyback(pd2.m, pd2.off, sizeof(*sh), (c_caddr_t)sh);
- PF_ACPY(&pd->nsaddr,
+ pf_addrcpy(&pd->nsaddr,
&nk->addr[pd2.sidx], nk->af);
- PF_ACPY(&pd->ndaddr,
+ pf_addrcpy(&pd->ndaddr,
&nk->addr[pd2.didx], nk->af);
if (nk->af == AF_INET) {
pd->proto = IPPROTO_ICMP;
@@ -8574,9 +8594,9 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
iih->icmp_id = nk->port[iidx];
m_copyback(pd2.m, pd2.off, ICMP_MINLEN,
(c_caddr_t)iih);
- PF_ACPY(&pd->nsaddr,
+ pf_addrcpy(&pd->nsaddr,
&nk->addr[pd2.sidx], nk->af);
- PF_ACPY(&pd->ndaddr,
+ pf_addrcpy(&pd->ndaddr,
&nk->addr[pd2.didx], nk->af);
/*
* IPv4 becomes IPv6 so we must copy
@@ -8702,9 +8722,9 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
iih->icmp6_id = nk->port[iidx];
m_copyback(pd2.m, pd2.off,
sizeof(struct icmp6_hdr), (c_caddr_t)iih);
- PF_ACPY(&pd->nsaddr,
+ pf_addrcpy(&pd->nsaddr,
&nk->addr[pd2.sidx], nk->af);
- PF_ACPY(&pd->ndaddr,
+ pf_addrcpy(&pd->ndaddr,
&nk->addr[pd2.didx], nk->af);
pd->naf = nk->af;
return (PF_AFRT);
@@ -8746,8 +8766,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
key.af = pd2.af;
key.proto = pd2.proto;
- PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af);
- PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af);
+ pf_addrcpy(&key.addr[pd2.sidx], pd2.src, key.af);
+ pf_addrcpy(&key.addr[pd2.didx], pd2.dst, key.af);
key.port[0] = key.port[1] = 0;
action = pf_find_state(&pd2, &key, state);
@@ -9048,6 +9068,9 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
goto bad;
}
+ if (r->rt == PF_DUPTO)
+ skip_test = true;
+
if (pd->dir == PF_IN && !skip_test) {
if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp,
&pd->act) != PF_PASS) {
@@ -9283,7 +9306,8 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp,
bzero(&dst, sizeof(dst));
dst.sin6_family = AF_INET6;
dst.sin6_len = sizeof(dst);
- PF_ACPY((struct pf_addr *)&dst.sin6_addr, &pd->act.rt_addr, AF_INET6);
+ pf_addrcpy((struct pf_addr *)&dst.sin6_addr, &pd->act.rt_addr,
+ AF_INET6);
if (pd->dir == PF_IN) {
if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
@@ -9349,6 +9373,9 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp,
goto bad;
}
+ if (r->rt == PF_DUPTO)
+ skip_test = true;
+
if (pd->dir == PF_IN && !skip_test) {
if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT,
ifp, &m0, inp, &pd->act) != PF_PASS) {
@@ -10037,6 +10064,8 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
pd->didx = (dir == PF_IN) ? 1 : 0;
pd->af = pd->naf = af;
+ PF_RULES_ASSERT();
+
TAILQ_INIT(&pd->sctp_multihome_jobs);
if (default_actions != NULL)
memcpy(&pd->act, default_actions, sizeof(pd->act));
@@ -10083,8 +10112,8 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
pd->src = (struct pf_addr *)&h->ip_src;
pd->dst = (struct pf_addr *)&h->ip_dst;
- PF_ACPY(&pd->osrc, pd->src, af);
- PF_ACPY(&pd->odst, pd->dst, af);
+ pf_addrcpy(&pd->osrc, pd->src, af);
+ pf_addrcpy(&pd->odst, pd->dst, af);
pd->ip_sum = &h->ip_sum;
pd->tos = h->ip_tos & ~IPTOS_ECN_MASK;
pd->ttl = h->ip_ttl;
@@ -10112,6 +10141,12 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
}
h = mtod(pd->m, struct ip6_hdr *);
+ if (pd->m->m_pkthdr.len <
+ sizeof(struct ip6_hdr) + ntohs(h->ip6_plen)) {
+ *action = PF_DROP;
+ REASON_SET(reason, PFRES_SHORT);
+ return (-1);
+ }
if (pf_walk_header6(pd, h, reason) != PF_PASS) {
*action = PF_DROP;
@@ -10121,8 +10156,8 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
h = mtod(pd->m, struct ip6_hdr *);
pd->src = (struct pf_addr *)&h->ip6_src;
pd->dst = (struct pf_addr *)&h->ip6_dst;
- PF_ACPY(&pd->osrc, pd->src, af);
- PF_ACPY(&pd->odst, pd->dst, af);
+ pf_addrcpy(&pd->osrc, pd->src, af);
+ pf_addrcpy(&pd->odst, pd->dst, af);
pd->ip_sum = NULL;
pd->tos = IPV6_DSCP(h);
pd->ttl = h->ip6_hlim;
@@ -10450,35 +10485,30 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
PF_RULES_RLOCK_TRACKER;
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: bad direction %d\n", __func__, dir));
M_ASSERTPKTHDR(*m0);
+ NET_EPOCH_ASSERT();
if (!V_pf_status.running)
return (PF_PASS);
- PF_RULES_RLOCK();
-
kif = (struct pfi_kkif *)ifp->if_pf_kif;
if (__predict_false(kif == NULL)) {
DPFPRINTF(PF_DEBUG_URGENT,
("%s: kif == NULL, if_xname %s\n",
__func__, ifp->if_xname));
- PF_RULES_RUNLOCK();
return (PF_DROP);
}
if (kif->pfik_flags & PFI_IFLAG_SKIP) {
- PF_RULES_RUNLOCK();
return (PF_PASS);
}
if ((*m0)->m_flags & M_SKIP_FIREWALL) {
- PF_RULES_RUNLOCK();
return (PF_PASS);
}
if (__predict_false(! M_WRITABLE(*m0))) {
*m0 = m_unshare(*m0, M_NOWAIT);
if (*m0 == NULL) {
- PF_RULES_RUNLOCK();
return (PF_DROP);
}
}
@@ -10491,12 +10521,10 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
ifp = ifnet_byindexgen(pd.pf_mtag->if_index,
pd.pf_mtag->if_idxgen);
if (ifp == NULL || ifp->if_flags & IFF_DYING) {
- PF_RULES_RUNLOCK();
m_freem(*m0);
*m0 = NULL;
return (PF_PASS);
}
- PF_RULES_RUNLOCK();
(ifp->if_output)(ifp, *m0, sintosa(&pd.pf_mtag->dst), NULL);
*m0 = NULL;
return (PF_PASS);
@@ -10511,11 +10539,12 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
/* But only once. We may see the packet multiple times (e.g.
* PFIL_IN/PFIL_OUT). */
pf_dummynet_flag_remove(pd.m, pd.pf_mtag);
- PF_RULES_RUNLOCK();
return (PF_PASS);
}
+ PF_RULES_RLOCK();
+
if (pf_setup_pdesc(af, dir, &pd, m0, &action, &reason,
kif, default_actions) == -1) {
if (action != PF_PASS)
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
index 2009d2907985..cfff58064922 100644
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -140,7 +140,7 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
#define PF_LOG 0x01
#define PF_LOG_ALL 0x02
-#define PF_LOG_SOCKET_LOOKUP 0x04
+#define PF_LOG_USER 0x04
#define PF_LOG_FORCE 0x08
#define PF_LOG_MATCHES 0x10
@@ -490,6 +490,7 @@ struct pf_osfp_ioctl {
#define PF_ANCHOR_NAME_SIZE 64
#define PF_ANCHOR_MAXPATH (MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)
+#define PF_OPTIMIZER_TABLE_PFX "__automatic_"
struct pf_rule {
struct pf_rule_addr src;
diff --git a/sys/netpfil/pf/pf_if.c b/sys/netpfil/pf/pf_if.c
index 389b74d09d37..e2200c15c704 100644
--- a/sys/netpfil/pf/pf_if.c
+++ b/sys/netpfil/pf/pf_if.c
@@ -522,7 +522,7 @@ pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
case 0:
return (0);
case 1:
- return (PF_MATCHA(0, &dyn->pfid_addr4,
+ return (pf_match_addr(0, &dyn->pfid_addr4,
&dyn->pfid_mask4, a, AF_INET));
default:
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
@@ -535,7 +535,7 @@ pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
case 0:
return (0);
case 1:
- return (PF_MATCHA(0, &dyn->pfid_addr6,
+ return (pf_match_addr(0, &dyn->pfid_addr6,
&dyn->pfid_mask6, a, AF_INET6));
default:
return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 05a7e1311ad8..5c69c395c5fc 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -615,7 +615,7 @@ pf_free_rule(struct pf_krule *rule)
pfi_kkif_unref(rule->kif);
if (rule->rcv_kif)
pfi_kkif_unref(rule->rcv_kif);
- pf_kanchor_remove(rule);
+ pf_remove_kanchor(rule);
pf_empty_kpool(&rule->rdr.list);
pf_empty_kpool(&rule->nat.list);
pf_empty_kpool(&rule->route.list);
@@ -1274,7 +1274,9 @@ pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
PF_MD5_UPD(pfr, addr.iflags);
break;
case PF_ADDR_TABLE:
- PF_MD5_UPD(pfr, addr.v.tblname);
+ if (strncmp(pfr->addr.v.tblname, PF_OPTIMIZER_TABLE_PFX,
+ strlen(PF_OPTIMIZER_TABLE_PFX)))
+ PF_MD5_UPD(pfr, addr.v.tblname);
break;
case PF_ADDR_ADDRMASK:
/* XXX ignore af? */
@@ -1357,7 +1359,7 @@ static int
pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
{
struct pf_kruleset *rs;
- struct pf_krule *rule, **old_array, *old_rule;
+ struct pf_krule *rule, *old_rule;
struct pf_krulequeue *old_rules;
struct pf_krule_global *old_tree;
int error;
@@ -1382,13 +1384,10 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
/* Swap rules, keep the old. */
old_rules = rs->rules[rs_num].active.ptr;
old_rcount = rs->rules[rs_num].active.rcount;
- old_array = rs->rules[rs_num].active.ptr_array;
old_tree = rs->rules[rs_num].active.tree;
rs->rules[rs_num].active.ptr =
rs->rules[rs_num].inactive.ptr;
- rs->rules[rs_num].active.ptr_array =
- rs->rules[rs_num].inactive.ptr_array;
rs->rules[rs_num].active.tree =
rs->rules[rs_num].inactive.tree;
rs->rules[rs_num].active.rcount =
@@ -1418,7 +1417,6 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
}
rs->rules[rs_num].inactive.ptr = old_rules;
- rs->rules[rs_num].inactive.ptr_array = old_array;
rs->rules[rs_num].inactive.tree = NULL; /* important for pf_ioctl_addrule */
rs->rules[rs_num].inactive.rcount = old_rcount;
@@ -1431,9 +1429,6 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
while ((rule = TAILQ_FIRST(old_rules)) != NULL)
pf_unlink_rule_locked(old_rules, rule);
PF_UNLNKDRULES_UNLOCK();
- if (rs->rules[rs_num].inactive.ptr_array)
- free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
- rs->rules[rs_num].inactive.ptr_array = NULL;
rs->rules[rs_num].inactive.rcount = 0;
rs->rules[rs_num].inactive.open = 0;
pf_remove_if_empty_kruleset(rs);
@@ -1456,24 +1451,11 @@ pf_setup_pfsync_matching(struct pf_kruleset *rs)
if (rs_cnt == PF_RULESET_SCRUB)
continue;
- if (rs->rules[rs_cnt].inactive.ptr_array)
- free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
- rs->rules[rs_cnt].inactive.ptr_array = NULL;
-
if (rs->rules[rs_cnt].inactive.rcount) {
- rs->rules[rs_cnt].inactive.ptr_array =
- mallocarray(rs->rules[rs_cnt].inactive.rcount,
- sizeof(struct pf_rule **),
- M_TEMP, M_NOWAIT);
-
- if (!rs->rules[rs_cnt].inactive.ptr_array)
- return (ENOMEM);
- }
-
- TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
- entries) {
- pf_hash_rule_rolling(&ctx, rule);
- (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
+ TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
+ entries) {
+ pf_hash_rule_rolling(&ctx, rule);
+ }
}
}
@@ -2059,6 +2041,47 @@ pf_ioctl_getrules(struct pfioc_rule *pr)
return (0);
}
+static int
+pf_rule_checkaf(struct pf_krule *r)
+{
+ switch (r->af) {
+ case 0:
+ if (r->rule_flag & PFRULE_AFTO)
+ return (EPFNOSUPPORT);
+ break;
+ case AF_INET:
+ if ((r->rule_flag & PFRULE_AFTO) && r->naf != AF_INET6)
+ return (EPFNOSUPPORT);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if ((r->rule_flag & PFRULE_AFTO) && r->naf != AF_INET)
+ return (EPFNOSUPPORT);
+ break;
+#endif /* INET6 */
+ default:
+ return (EPFNOSUPPORT);
+ }
+
+ if ((r->rule_flag & PFRULE_AFTO) == 0 && r->naf != 0)
+ return (EPFNOSUPPORT);
+
+ return (0);
+}
+
+static int
+pf_validate_range(uint8_t op, uint16_t port[2])
+{
+ uint16_t a = ntohs(port[0]);
+ uint16_t b = ntohs(port[1]);
+
+ if ((op == PF_OP_RRG && a > b) || /* 34:12, i.e. none */
+ (op == PF_OP_IRG && a >= b) || /* 34><12, i.e. none */
+ (op == PF_OP_XRG && a > b)) /* 34<>22, i.e. all */
+ return 1;
+ return 0;
+}
+
int
pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
uint32_t pool_ticket, const char *anchor, const char *anchor_call,
@@ -2078,6 +2101,13 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
#define ERROUT(x) ERROUT_FUNCTION(errout, x)
+ if ((error = pf_rule_checkaf(rule)))
+ ERROUT(error);
+ if (pf_validate_range(rule->src.port_op, rule->src.port))
+ ERROUT(EINVAL);
+ if (pf_validate_range(rule->dst.port_op, rule->dst.port))
+ ERROUT(EINVAL);
+
if (rule->ifname[0])
kif = pf_kkif_create(M_WAITOK);
if (rule->rcv_ifname[0])
@@ -2155,51 +2185,51 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
rule->rcv_kif = NULL;
if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
- error = EBUSY;
+ ERROUT(EBUSY);
#ifdef ALTQ
/* set queue IDs */
if (rule->qname[0] != 0) {
if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
- error = EBUSY;
+ ERROUT(EBUSY);
else if (rule->pqname[0] != 0) {
if ((rule->pqid =
pf_qname2qid(rule->pqname)) == 0)
- error = EBUSY;
+ ERROUT(EBUSY);
} else
rule->pqid = rule->qid;
}
#endif
if (rule->tagname[0])
if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
- error = EBUSY;
+ ERROUT(EBUSY);
if (rule->match_tagname[0])
if ((rule->match_tag =
pf_tagname2tag(rule->match_tagname)) == 0)
- error = EBUSY;
+ ERROUT(EBUSY);
if (rule->rt && !rule->direction)
- error = EINVAL;
+ ERROUT(EINVAL);
if (!rule->log)
rule->logif = 0;
if (! pf_init_threshold(&rule->pktrate, rule->pktrate.limit,
rule->pktrate.seconds))
- error = ENOMEM;
+ ERROUT(ENOMEM);
if (pf_addr_setup(ruleset, &rule->src.addr, rule->af))
- error = ENOMEM;
+ ERROUT(ENOMEM);
if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af))
- error = ENOMEM;
+ ERROUT(ENOMEM);
if (pf_kanchor_setup(rule, ruleset, anchor_call))
- error = EINVAL;
+ ERROUT(EINVAL);
if (rule->scrub_flags & PFSTATE_SETPRIO &&
(rule->set_prio[0] > PF_PRIO_MAX ||
rule->set_prio[1] > PF_PRIO_MAX))
- error = EINVAL;
+ ERROUT(EINVAL);
for (int i = 0; i < 3; i++) {
TAILQ_FOREACH(pa, &V_pf_pabuf[i], entries)
if (pa->addr.type == PF_ADDR_TABLE) {
pa->addr.p.tbl = pfr_attach_table(ruleset,
pa->addr.v.tblname);
if (pa->addr.p.tbl == NULL)
- error = ENOMEM;
+ ERROUT(ENOMEM);
}
}
@@ -2207,7 +2237,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
if (rule->overload_tblname[0]) {
if ((rule->overload_tbl = pfr_attach_table(ruleset,
rule->overload_tblname)) == NULL)
- error = EINVAL;
+ ERROUT(EINVAL);
else
rule->overload_tbl->pfrkt_flags |=
PFR_TFLAG_ACTIVE;
@@ -2230,23 +2260,19 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
if (((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
(rule->action == PF_BINAT)) && rule->anchor == NULL &&
TAILQ_FIRST(&rule->rdr.list) == NULL) {
- error = EINVAL;
+ ERROUT(EINVAL);
}
if (rule->rt > PF_NOPFROUTE && (TAILQ_FIRST(&rule->route.list) == NULL)) {
- error = EINVAL;
+ ERROUT(EINVAL);
}
if (rule->action == PF_PASS && (rule->rdr.opts & PF_POOL_STICKYADDR ||
rule->nat.opts & PF_POOL_STICKYADDR) && !rule->keep_state) {
- error = EINVAL;
+ ERROUT(EINVAL);
}
- if (error) {
- pf_free_rule(rule);
- rule = NULL;
- ERROUT(error);
- }
+ MPASS(error == 0);
rule->nat.cur = TAILQ_FIRST(&rule->nat.list);
rule->rdr.cur = TAILQ_FIRST(&rule->rdr.list);
@@ -2350,15 +2376,17 @@ relock_DIOCKILLSTATES:
if (psk->psk_proto && psk->psk_proto != sk->proto)
continue;
- if (! PF_MATCHA(psk->psk_src.neg, &psk->psk_src.addr.v.a.addr,
+ if (! pf_match_addr(psk->psk_src.neg,
+ &psk->psk_src.addr.v.a.addr,
&psk->psk_src.addr.v.a.mask, srcaddr, sk->af))
continue;
- if (! PF_MATCHA(psk->psk_dst.neg, &psk->psk_dst.addr.v.a.addr,
+ if (! pf_match_addr(psk->psk_dst.neg,
+ &psk->psk_dst.addr.v.a.addr,
&psk->psk_dst.addr.v.a.mask, dstaddr, sk->af))
continue;
- if (! PF_MATCHA(psk->psk_rt_addr.neg,
+ if (! pf_match_addr(psk->psk_rt_addr.neg,
&psk->psk_rt_addr.addr.v.a.addr,
&psk->psk_rt_addr.addr.v.a.mask,
&s->act.rt_addr, sk->af))
@@ -2398,10 +2426,10 @@ relock_DIOCKILLSTATES:
match_key.af = s->key[idx]->af;
match_key.proto = s->key[idx]->proto;
- PF_ACPY(&match_key.addr[0],
+ pf_addrcpy(&match_key.addr[0],
&s->key[idx]->addr[1], match_key.af);
match_key.port[0] = s->key[idx]->port[1];
- PF_ACPY(&match_key.addr[1],
+ pf_addrcpy(&match_key.addr[1],
&s->key[idx]->addr[0], match_key.af);
match_key.port[1] = s->key[idx]->port[0];
}
@@ -2697,7 +2725,7 @@ pf_ioctl_get_addr(struct pf_nl_pooladdr *pp)
PF_RULES_RLOCK_TRACKER;
- pp->anchor[sizeof(pp->anchor) - 1] = 0;
+ pp->anchor[sizeof(pp->anchor) - 1] = '\0';
PF_RULES_RLOCK();
pool = pf_get_kpool(pp->anchor, pp->ticket, pp->r_action,
@@ -2730,7 +2758,7 @@ pf_ioctl_get_rulesets(struct pfioc_ruleset *pr)
PF_RULES_RLOCK_TRACKER;
- pr->path[sizeof(pr->path) - 1] = 0;
+ pr->path[sizeof(pr->path) - 1] = '\0';
PF_RULES_RLOCK();
if ((ruleset = pf_find_kruleset(pr->path)) == NULL) {
@@ -2738,7 +2766,7 @@ pf_ioctl_get_rulesets(struct pfioc_ruleset *pr)
return (ENOENT);
}
pr->nr = 0;
- if (ruleset->anchor == NULL) {
+ if (ruleset == &pf_main_ruleset) {
/* XXX kludge for pf_main_ruleset */
RB_FOREACH(anchor, pf_kanchor_global, &V_pf_anchors)
if (anchor->parent == NULL)
@@ -2769,8 +2797,8 @@ pf_ioctl_get_ruleset(struct pfioc_ruleset *pr)
return (ENOENT);
}
- pr->name[0] = 0;
- if (ruleset->anchor == NULL) {
+ pr->name[0] = '\0';
+ if (ruleset == &pf_main_ruleset) {
/* XXX kludge for pf_main_ruleset */
RB_FOREACH(anchor, pf_kanchor_global, &V_pf_anchors)
if (anchor->parent == NULL && nr++ == pr->nr) {
@@ -2794,6 +2822,78 @@ pf_ioctl_get_ruleset(struct pfioc_ruleset *pr)
return (error);
}
+int
+pf_ioctl_natlook(struct pfioc_natlook *pnl)
+{
+ struct pf_state_key *sk;
+ struct pf_kstate *state;
+ struct pf_state_key_cmp key;
+ int m = 0, direction = pnl->direction;
+ int sidx, didx;
+
+ /* NATLOOK src and dst are reversed, so reverse sidx/didx */
+ sidx = (direction == PF_IN) ? 1 : 0;
+ didx = (direction == PF_IN) ? 0 : 1;
+
+ if (!pnl->proto ||
+ PF_AZERO(&pnl->saddr, pnl->af) ||
+ PF_AZERO(&pnl->daddr, pnl->af) ||
+ ((pnl->proto == IPPROTO_TCP ||
+ pnl->proto == IPPROTO_UDP) &&
+ (!pnl->dport || !pnl->sport)))
+ return (EINVAL);
+
+ switch (pnl->direction) {
+ case PF_IN:
+ case PF_OUT:
+ case PF_INOUT:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ switch (pnl->af) {
+#ifdef INET
+ case AF_INET:
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ break;
+#endif /* INET6 */
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ bzero(&key, sizeof(key));
+ key.af = pnl->af;
+ key.proto = pnl->proto;
+ pf_addrcpy(&key.addr[sidx], &pnl->saddr, pnl->af);
+ key.port[sidx] = pnl->sport;
+ pf_addrcpy(&key.addr[didx], &pnl->daddr, pnl->af);
+ key.port[didx] = pnl->dport;
+
+ state = pf_find_state_all(&key, direction, &m);
+ if (state == NULL)
+ return (ENOENT);
+
+ if (m > 1) {
+ PF_STATE_UNLOCK(state);
+ return (E2BIG); /* more than one state */
+ }
+
+ sk = state->key[sidx];
+ pf_addrcpy(&pnl->rsaddr,
+ &sk->addr[sidx], sk->af);
+ pnl->rsport = sk->port[sidx];
+ pf_addrcpy(&pnl->rdaddr,
+ &sk->addr[didx], sk->af);
+ pnl->rdport = sk->port[didx];
+ PF_STATE_UNLOCK(state);
+
+ return (0);
+}
+
static int
pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
@@ -3497,10 +3597,10 @@ DIOCADDRULENV_error:
error = pf_rule_to_krule(&pr->rule, rule);
if (error != 0) {
pf_krule_free(rule);
- break;
+ goto fail;
}
- pr->anchor[sizeof(pr->anchor) - 1] = 0;
+ pr->anchor[sizeof(pr->anchor) - 1] = '\0';
/* Frees rule on error */
error = pf_ioctl_addrule(rule, pr->ticket, pr->pool_ticket,
@@ -3512,7 +3612,7 @@ DIOCADDRULENV_error:
case DIOCGETRULES: {
struct pfioc_rule *pr = (struct pfioc_rule *)addr;
- pr->anchor[sizeof(pr->anchor) - 1] = 0;
+ pr->anchor[sizeof(pr->anchor) - 1] = '\0';
error = pf_ioctl_getrules(pr);
@@ -3651,16 +3751,16 @@ DIOCGETRULENV_error:
u_int32_t nr = 0;
int rs_num;
- pcr->anchor[sizeof(pcr->anchor) - 1] = 0;
+ pcr->anchor[sizeof(pcr->anchor) - 1] = '\0';
if (pcr->action < PF_CHANGE_ADD_HEAD ||
pcr->action > PF_CHANGE_GET_TICKET) {
error = EINVAL;
- break;
+ goto fail;
}
if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
error = EINVAL;
- break;
+ goto fail;
}
if (pcr->action != PF_CHANGE_REMOVE) {
@@ -3668,9 +3768,13 @@ DIOCGETRULENV_error:
error = pf_rule_to_krule(&pcr->rule, newrule);
if (error != 0) {
pf_krule_free(newrule);
- break;
+ goto fail;
}
+ if ((error = pf_rule_checkaf(newrule))) {
+ pf_krule_free(newrule);
+ goto fail;
+ }
if (newrule->ifname[0])
kif = pf_kkif_create(M_WAITOK);
pf_counter_u64_init(&newrule->evaluations, M_WAITOK);
@@ -3818,7 +3922,7 @@ DIOCGETRULENV_error:
pf_free_rule(newrule);
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
- break;
+ goto fail;
}
newrule->nat.cur = TAILQ_FIRST(&newrule->nat.list);
@@ -3845,7 +3949,7 @@ DIOCGETRULENV_error:
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
}
@@ -3863,7 +3967,7 @@ DIOCGETRULENV_error:
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
error = EEXIST;
- break;
+ goto fail;
}
if (oldrule == NULL)
@@ -3919,7 +4023,7 @@ DIOCCHANGERULE_error:
if (sp->timeout >= PFTM_MAX) {
error = EINVAL;
- break;
+ goto fail;
}
if (V_pfsync_state_import_ptr != NULL) {
PF_RULES_RLOCK();
@@ -3939,7 +4043,7 @@ DIOCCHANGERULE_error:
s = pf_find_state_byid(ps->state.id, ps->state.creatorid);
if (s == NULL) {
error = ENOENT;
- break;
+ goto fail;
}
pfsync_state_export((union pfsync_state_union*)&ps->state,
@@ -4018,7 +4122,7 @@ DIOCGETSTATES_retry:
error = copyout(pstore, out,
sizeof(struct pfsync_state_1301) * count);
if (error)
- break;
+ goto fail;
out = ps->ps_states + nr;
}
DIOCGETSTATES_full:
@@ -4038,7 +4142,7 @@ DIOCGETSTATES_full:
if (ps->ps_req_version > PF_STATE_VERSION) {
error = ENOTSUP;
- break;
+ goto fail;
}
if (ps->ps_len <= 0) {
@@ -4096,7 +4200,7 @@ DIOCGETSTATESV2_retry:
error = copyout(pstore, out,
sizeof(struct pf_state_export) * count);
if (error)
- break;
+ goto fail;
out = ps->ps_states + nr;
}
DIOCGETSTATESV2_full:
@@ -4131,49 +4235,8 @@ DIOCGETSTATESV2_full:
case DIOCNATLOOK: {
struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr;
- struct pf_state_key *sk;
- struct pf_kstate *state;
- struct pf_state_key_cmp key;
- int m = 0, direction = pnl->direction;
- int sidx, didx;
-
- /* NATLOOK src and dst are reversed, so reverse sidx/didx */
- sidx = (direction == PF_IN) ? 1 : 0;
- didx = (direction == PF_IN) ? 0 : 1;
-
- if (!pnl->proto ||
- PF_AZERO(&pnl->saddr, pnl->af) ||
- PF_AZERO(&pnl->daddr, pnl->af) ||
- ((pnl->proto == IPPROTO_TCP ||
- pnl->proto == IPPROTO_UDP) &&
- (!pnl->dport || !pnl->sport)))
- error = EINVAL;
- else {
- bzero(&key, sizeof(key));
- key.af = pnl->af;
- key.proto = pnl->proto;
- PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af);
- key.port[sidx] = pnl->sport;
- PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af);
- key.port[didx] = pnl->dport;
-
- state = pf_find_state_all(&key, direction, &m);
- if (state == NULL) {
- error = ENOENT;
- } else {
- if (m > 1) {
- PF_STATE_UNLOCK(state);
- error = E2BIG; /* more than one state */
- } else {
- sk = state->key[sidx];
- PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af);
- pnl->rsport = sk->port[sidx];
- PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af);
- pnl->rdport = sk->port[didx];
- PF_STATE_UNLOCK(state);
- }
- }
- }
+
+ error = pf_ioctl_natlook(pnl);
break;
}
@@ -4243,12 +4306,12 @@ DIOCGETSTATESV2_full:
if (psp->ifname[0] == '\0') {
error = EINVAL;
- break;
+ goto fail;
}
error = pf_user_strcpy(ps.ifname, psp->ifname, IFNAMSIZ);
if (error != 0)
- break;
+ goto fail;
ifp = ifunit(ps.ifname);
if (ifp != NULL) {
psp->baudrate32 =
@@ -4309,7 +4372,7 @@ DIOCGETSTATESV2_full:
altq = malloc(sizeof(*altq), M_PFALTQ, M_WAITOK | M_ZERO);
error = pf_import_kaltq(pa, altq, IOCPARM_LEN(cmd));
if (error)
- break;
+ goto fail;
altq->local_flags = 0;
PF_RULES_WLOCK();
@@ -4317,7 +4380,7 @@ DIOCGETSTATESV2_full:
PF_RULES_WUNLOCK();
free(altq, M_PFALTQ);
error = EBUSY;
- break;
+ goto fail;
}
/*
@@ -4329,7 +4392,7 @@ DIOCGETSTATESV2_full:
PF_RULES_WUNLOCK();
error = EBUSY;
free(altq, M_PFALTQ);
- break;
+ goto fail;
}
altq->altq_disc = NULL;
TAILQ_FOREACH(a, V_pf_altq_ifs_inactive, entries) {
@@ -4349,7 +4412,7 @@ DIOCGETSTATESV2_full:
if (error) {
PF_RULES_WUNLOCK();
free(altq, M_PFALTQ);
- break;
+ goto fail;
}
if (altq->qname[0] != 0)
@@ -4387,13 +4450,13 @@ DIOCGETSTATESV2_full:
if (pa->ticket != V_ticket_altqs_active) {
PF_RULES_RUNLOCK();
error = EBUSY;
- break;
+ goto fail;
}
altq = pf_altq_get_nth_active(pa->nr);
if (altq == NULL) {
PF_RULES_RUNLOCK();
error = EBUSY;
- break;
+ goto fail;
}
pf_export_kaltq(altq, pa, IOCPARM_LEN(cmd));
PF_RULES_RUNLOCK();
@@ -4417,20 +4480,20 @@ DIOCGETSTATESV2_full:
if (pq->ticket != V_ticket_altqs_active) {
PF_RULES_RUNLOCK();
error = EBUSY;
- break;
+ goto fail;
}
nbytes = pq->nbytes;
altq = pf_altq_get_nth_active(pq->nr);
if (altq == NULL) {
PF_RULES_RUNLOCK();
error = EBUSY;
- break;
+ goto fail;
}
if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) {
PF_RULES_RUNLOCK();
error = ENXIO;
- break;
+ goto fail;
}
PF_RULES_RUNLOCK();
if (cmd == DIOCGETQSTATSV0)
@@ -4494,35 +4557,35 @@ DIOCGETSTATESV2_full:
struct pf_kruleset *ruleset;
struct pfi_kkif *kif = NULL;
- pca->anchor[sizeof(pca->anchor) - 1] = 0;
+ pca->anchor[sizeof(pca->anchor) - 1] = '\0';
if (pca->action < PF_CHANGE_ADD_HEAD ||
pca->action > PF_CHANGE_REMOVE) {
error = EINVAL;
- break;
+ goto fail;
}
if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
pca->addr.addr.type != PF_ADDR_DYNIFTL &&
pca->addr.addr.type != PF_ADDR_TABLE) {
error = EINVAL;
- break;
+ goto fail;
}
if (pca->addr.addr.p.dyn != NULL) {
error = EINVAL;
- break;
+ goto fail;
}
if (pca->action != PF_CHANGE_REMOVE) {
#ifndef INET
if (pca->af == AF_INET) {
error = EAFNOSUPPORT;
- break;
+ goto fail;
}
#endif /* INET */
#ifndef INET6
if (pca->af == AF_INET6) {
error = EAFNOSUPPORT;
- break;
+ goto fail;
}
#endif /* INET6 */
newpa = malloc(sizeof(*newpa), M_PFRULE, M_WAITOK);
@@ -4606,7 +4669,7 @@ DIOCGETSTATESV2_full:
}
pool->cur = TAILQ_FIRST(&pool->list);
- PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, pca->af);
+ pf_addrcpy(&pool->counter, &pool->cur->addr.v.a.addr, pca->af);
PF_RULES_WUNLOCK();
break;
@@ -4625,7 +4688,7 @@ DIOCCHANGEADDR_error:
case DIOCGETRULESETS: {
struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
- pr->path[sizeof(pr->path) - 1] = 0;
+ pr->path[sizeof(pr->path) - 1] = '\0';
error = pf_ioctl_get_rulesets(pr);
break;
@@ -4634,7 +4697,7 @@ DIOCCHANGEADDR_error:
case DIOCGETRULESET: {
struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
- pr->path[sizeof(pr->path) - 1] = 0;
+ pr->path[sizeof(pr->path) - 1] = '\0';
error = pf_ioctl_get_ruleset(pr);
break;
@@ -4645,7 +4708,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != 0) {
error = ENODEV;
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
@@ -4661,13 +4724,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) {
error = ENOMEM;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_table);
@@ -4676,7 +4739,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_add_tables(pfrts, io->pfrio_size,
@@ -4693,13 +4756,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) {
error = ENOMEM;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_table);
@@ -4708,7 +4771,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_del_tables(pfrts, io->pfrio_size,
@@ -4726,14 +4789,14 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
PF_RULES_RLOCK();
n = pfr_table_count(&io->pfrio_table, io->pfrio_flags);
if (n < 0) {
PF_RULES_RUNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
io->pfrio_size = min(io->pfrio_size, n);
@@ -4744,7 +4807,7 @@ DIOCCHANGEADDR_error:
if (pfrts == NULL) {
error = ENOMEM;
PF_RULES_RUNLOCK();
- break;
+ goto fail;
}
error = pfr_get_tables(&io->pfrio_table, pfrts,
&io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
@@ -4763,7 +4826,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
error = ENODEV;
- break;
+ goto fail;
}
PF_TABLE_STATS_LOCK();
PF_RULES_RLOCK();
@@ -4772,7 +4835,7 @@ DIOCCHANGEADDR_error:
PF_RULES_RUNLOCK();
PF_TABLE_STATS_UNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
io->pfrio_size = min(io->pfrio_size, n);
@@ -4783,7 +4846,7 @@ DIOCCHANGEADDR_error:
error = ENOMEM;
PF_RULES_RUNLOCK();
PF_TABLE_STATS_UNLOCK();
- break;
+ goto fail;
}
error = pfr_get_tstats(&io->pfrio_table, pfrtstats,
&io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
@@ -4802,7 +4865,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
@@ -4811,7 +4874,7 @@ DIOCCHANGEADDR_error:
* size, so we didn't fail on overly large requests.
* Keep doing so. */
io->pfrio_size = pf_ioctl_maxcount;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_table);
@@ -4820,7 +4883,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- break;
+ goto fail;
}
PF_TABLE_STATS_LOCK();
@@ -4841,7 +4904,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
PF_RULES_RLOCK();
@@ -4849,7 +4912,7 @@ DIOCCHANGEADDR_error:
if (n < 0) {
PF_RULES_RUNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
io->pfrio_size = min(io->pfrio_size, n);
@@ -4861,7 +4924,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_set_tflags(pfrts, io->pfrio_size,
@@ -4877,7 +4940,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != 0) {
error = ENODEV;
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
@@ -4893,13 +4956,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -4907,7 +4970,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_add_addrs(&io->pfrio_table, pfras,
@@ -4927,13 +4990,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -4941,7 +5004,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_del_addrs(&io->pfrio_table, pfras,
@@ -4961,17 +5024,17 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 || io->pfrio_size2 < 0) {
error = EINVAL;
- break;
+ goto fail;
}
count = max(io->pfrio_size, io->pfrio_size2);
if (count > pf_ioctl_maxcount ||
WOULD_OVERFLOW(count, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = count * sizeof(struct pfr_addr);
pfras = mallocarray(count, sizeof(struct pfr_addr), M_TEMP,
@@ -4979,7 +5042,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_set_addrs(&io->pfrio_table, pfras,
@@ -5000,13 +5063,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -5028,13 +5091,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_astats)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_astats))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_astats);
pfrastats = mallocarray(io->pfrio_size,
@@ -5056,13 +5119,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -5070,7 +5133,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_clr_astats(&io->pfrio_table, pfras,
@@ -5090,13 +5153,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -5104,7 +5167,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_RLOCK();
error = pfr_tst_addrs(&io->pfrio_table, pfras,
@@ -5124,13 +5187,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -5138,7 +5201,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_ina_define(&io->pfrio_table, pfras,
@@ -5173,13 +5236,13 @@ DIOCCHANGEADDR_error:
if (io->esize != sizeof(*ioe)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->size < 0 ||
io->size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = sizeof(struct pfioc_trans_e) * io->size;
ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
@@ -5187,7 +5250,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->array, ioes, totlen);
if (error) {
free(ioes, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
@@ -5254,13 +5317,13 @@ DIOCCHANGEADDR_error:
if (io->esize != sizeof(*ioe)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->size < 0 ||
io->size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = sizeof(struct pfioc_trans_e) * io->size;
ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
@@ -5268,7 +5331,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->array, ioes, totlen);
if (error) {
free(ioes, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
@@ -5337,14 +5400,14 @@ DIOCCHANGEADDR_error:
if (io->esize != sizeof(*ioe)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->size < 0 ||
io->size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = sizeof(struct pfioc_trans_e) * io->size;
@@ -5353,12 +5416,12 @@ DIOCCHANGEADDR_error:
error = copyin(io->array, ioes, totlen);
if (error) {
free(ioes, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
/* First makes sure everything will succeed. */
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
- ioe->anchor[sizeof(ioe->anchor) - 1] = 0;
+ ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
switch (ioe->rs_num) {
case PF_RULESET_ETH:
ers = pf_find_keth_ruleset(ioe->anchor);
@@ -5494,7 +5557,7 @@ DIOCCHANGEADDR_error:
if (psn->psn_len == 0) {
psn->psn_len = sizeof(struct pf_src_node) * nr;
- break;
+ goto fail;
}
nr = 0;
@@ -5519,7 +5582,7 @@ DIOCCHANGEADDR_error:
sizeof(struct pf_src_node) * nr);
if (error) {
free(pstore, M_TEMP);
- break;
+ goto fail;
}
psn->psn_len = sizeof(struct pf_src_node) * nr;
free(pstore, M_TEMP);
@@ -5575,14 +5638,14 @@ DIOCCHANGEADDR_error:
if (io->pfiio_esize != sizeof(struct pfi_kif)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfiio_size < 0 ||
io->pfiio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfiio_size, sizeof(struct pfi_kif))) {
error = EINVAL;
- break;
+ goto fail;
}
io->pfiio_name[sizeof(io->pfiio_name) - 1] = '\0';
@@ -6024,11 +6087,11 @@ pf_kill_srcnodes(struct pfioc_src_node_kill *psnk)
PF_HASHROW_LOCK(sh);
LIST_FOREACH_SAFE(sn, &sh->nodes, entry, tmp)
if (psnk == NULL ||
- (PF_MATCHA(psnk->psnk_src.neg,
+ (pf_match_addr(psnk->psnk_src.neg,
&psnk->psnk_src.addr.v.a.addr,
&psnk->psnk_src.addr.v.a.mask,
&sn->addr, sn->af) &&
- PF_MATCHA(psnk->psnk_dst.neg,
+ pf_match_addr(psnk->psnk_dst.neg,
&psnk->psnk_dst.addr.v.a.addr,
&psnk->psnk_dst.addr.v.a.mask,
&sn->raddr, sn->af))) {
@@ -6132,10 +6195,10 @@ relock_DIOCCLRSTATES:
match_key.af = s->key[idx]->af;
match_key.proto = s->key[idx]->proto;
- PF_ACPY(&match_key.addr[0],
+ pf_addrcpy(&match_key.addr[0],
&s->key[idx]->addr[1], match_key.af);
match_key.port[0] = s->key[idx]->port[1];
- PF_ACPY(&match_key.addr[1],
+ pf_addrcpy(&match_key.addr[1],
&s->key[idx]->addr[0], match_key.af);
match_key.port[1] = s->key[idx]->port[0];
}
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index 5e7865e4fac5..9c7863bb301e 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -80,7 +80,6 @@ static enum pf_test_status pf_step_into_translation_anchor(int, struct pf_test_c
struct pf_krule *);
static int pf_get_sport(struct pf_pdesc *, struct pf_krule *,
struct pf_addr *, uint16_t *, uint16_t, uint16_t,
- struct pf_ksrc_node **, struct pf_srchash **,
struct pf_kpool *, struct pf_udp_mapping **,
pf_sn_types_t);
static bool pf_islinklocal(const sa_family_t, const struct pf_addr *);
@@ -291,10 +290,8 @@ pf_match_translation(int rs_num, struct pf_test_ctx *ctx)
}
static int
-pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
- struct pf_addr *naddr, uint16_t *nport, uint16_t low,
- uint16_t high, struct pf_ksrc_node **sn,
- struct pf_srchash **sh, struct pf_kpool *rpool,
+pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r, struct pf_addr *naddr,
+ uint16_t *nport, uint16_t low, uint16_t high, struct pf_kpool *rpool,
struct pf_udp_mapping **udp_mapping, pf_sn_types_t sn_type)
{
struct pf_state_key_cmp key;
@@ -319,20 +316,27 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
bzero(&udp_source, sizeof(udp_source));
udp_source.af = pd->af;
- PF_ACPY(&udp_source.addr, &pd->nsaddr, pd->af);
+ pf_addrcpy(&udp_source.addr, &pd->nsaddr, pd->af);
udp_source.port = pd->nsport;
if (udp_mapping) {
+ struct pf_ksrc_node *sn = NULL;
+ struct pf_srchash *sh = NULL;
*udp_mapping = pf_udp_mapping_find(&udp_source);
if (*udp_mapping) {
- PF_ACPY(naddr, &(*udp_mapping)->endpoints[1].addr, pd->af);
+ pf_addrcpy(naddr,
+ &(*udp_mapping)->endpoints[1].addr,
+ pd->af);
*nport = (*udp_mapping)->endpoints[1].port;
- /* Try to find a src_node as per pf_map_addr(). */
- if (*sn == NULL && rpool->opts & PF_POOL_STICKYADDR &&
+ /*
+ * Try to find a src_node as per pf_map_addr().
+ * XXX: Why? This code seems to do nothing.
+ */
+ if (rpool->opts & PF_POOL_STICKYADDR &&
(rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE)
- *sn = pf_find_src_node(&pd->nsaddr, r,
- pd->af, sh, sn_type, false);
- if (*sn != NULL)
- PF_SRC_NODE_UNLOCK(*sn);
+ sn = pf_find_src_node(&pd->nsaddr, r,
+ pd->af, &sh, sn_type, false);
+ if (sn != NULL)
+ PF_SRC_NODE_UNLOCK(sn);
return (0);
} else {
*udp_mapping = pf_udp_mapping_create(pd->af, &pd->nsaddr,
@@ -344,7 +348,7 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
}
if (pf_map_addr_sn(pd->naf, r, &pd->nsaddr, naddr, NULL, &init_addr,
- sn, sh, rpool, sn_type))
+ rpool, sn_type))
goto failed;
if (pd->proto == IPPROTO_ICMP) {
@@ -369,12 +373,13 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
key.proto = pd->proto;
do {
- PF_ACPY(&key.addr[didx], &pd->ndaddr, key.af);
- PF_ACPY(&key.addr[sidx], naddr, key.af);
+ pf_addrcpy(&key.addr[didx], &pd->ndaddr, key.af);
+ pf_addrcpy(&key.addr[sidx], naddr, key.af);
key.port[didx] = pd->ndport;
if (udp_mapping && *udp_mapping)
- PF_ACPY(&(*udp_mapping)->endpoints[1].addr, naddr, pd->af);
+ pf_addrcpy(&(*udp_mapping)->endpoints[1].addr, naddr,
+ pd->af);
/*
* port search; start random, step;
@@ -467,9 +472,8 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
* pick a different source address since we're out
* of free port choices for the current one.
*/
- (*sn) = NULL;
if (pf_map_addr_sn(pd->naf, r, &pd->nsaddr, naddr, NULL,
- &init_addr, sn, sh, rpool, sn_type))
+ &init_addr, rpool, sn_type))
return (1);
break;
case PF_POOL_NONE:
@@ -500,7 +504,6 @@ pf_islinklocal(const sa_family_t af, const struct pf_addr *addr)
static int
pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r,
struct pf_addr *naddr, uint16_t *nport,
- struct pf_ksrc_node **sn, struct pf_srchash **sh,
struct pf_udp_mapping **udp_mapping, struct pf_kpool *rpool)
{
uint16_t psmask, low, highmask;
@@ -520,16 +523,14 @@ pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r,
for (i = cut; i <= ahigh; i++) {
low = (i << ashift) | psmask;
- if (!pf_get_sport(pd, r,
- naddr, nport, low, low | highmask, sn, sh, rpool,
- udp_mapping, PF_SN_NAT))
+ if (!pf_get_sport(pd, r, naddr, nport, low, low | highmask,
+ rpool, udp_mapping, PF_SN_NAT))
return (0);
}
for (i = cut - 1; i > 0; i--) {
low = (i << ashift) | psmask;
- if (!pf_get_sport(pd, r,
- naddr, nport, low, low | highmask, sn, sh, rpool,
- udp_mapping, PF_SN_NAT))
+ if (!pf_get_sport(pd, r, naddr, nport, low, low | highmask,
+ rpool, udp_mapping, PF_SN_NAT))
return (0);
}
return (1);
@@ -542,6 +543,7 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
{
u_short reason = PFRES_MATCH;
struct pf_addr *raddr = NULL, *rmask = NULL;
+ struct pfr_ktable *kt;
uint64_t hashidx;
int cnt;
@@ -591,39 +593,35 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
switch (rpool->opts & PF_POOL_TYPEMASK) {
case PF_POOL_NONE:
- PF_ACPY(naddr, raddr, af);
+ pf_addrcpy(naddr, raddr, af);
break;
case PF_POOL_BITMASK:
- PF_POOLMASK(naddr, raddr, rmask, saddr, af);
+ pf_poolmask(naddr, raddr, rmask, saddr, af);
break;
case PF_POOL_RANDOM:
- if (rpool->cur->addr.type == PF_ADDR_TABLE) {
- cnt = rpool->cur->addr.p.tbl->pfrkt_cnt;
- if (cnt == 0)
- rpool->tblidx = 0;
+ if (rpool->cur->addr.type == PF_ADDR_TABLE ||
+ rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
+ if (rpool->cur->addr.type == PF_ADDR_TABLE)
+ kt = rpool->cur->addr.p.tbl;
else
- rpool->tblidx = (int)arc4random_uniform(cnt);
- memset(&rpool->counter, 0, sizeof(rpool->counter));
- if (pfr_pool_get(rpool->cur->addr.p.tbl,
- &rpool->tblidx, &rpool->counter, af, NULL)) {
+ kt = rpool->cur->addr.p.dyn->pfid_kt;
+ kt = pfr_ktable_select_active(kt);
+ if (kt == NULL) {
reason = PFRES_MAPFAILED;
goto done_pool_mtx; /* unsupported */
}
- PF_ACPY(naddr, &rpool->counter, af);
- } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
- cnt = rpool->cur->addr.p.dyn->pfid_kt->pfrkt_cnt;
+ cnt = kt->pfrkt_cnt;
if (cnt == 0)
rpool->tblidx = 0;
else
rpool->tblidx = (int)arc4random_uniform(cnt);
memset(&rpool->counter, 0, sizeof(rpool->counter));
- if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
- &rpool->tblidx, &rpool->counter, af,
- pf_islinklocal)) {
+ if (pfr_pool_get(kt, &rpool->tblidx, &rpool->counter,
+ af, pf_islinklocal, false)) {
reason = PFRES_MAPFAILED;
goto done_pool_mtx; /* unsupported */
}
- PF_ACPY(naddr, &rpool->counter, af);
+ pf_addrcpy(naddr, &rpool->counter, af);
} else if (init_addr != NULL && PF_AZERO(init_addr, af)) {
switch (af) {
#ifdef INET
@@ -654,12 +652,12 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
break;
#endif /* INET6 */
}
- PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
- PF_ACPY(init_addr, naddr, af);
+ pf_poolmask(naddr, raddr, rmask, &rpool->counter, af);
+ pf_addrcpy(init_addr, naddr, af);
} else {
- PF_AINC(&rpool->counter, af);
- PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
+ pf_addr_inc(&rpool->counter, af);
+ pf_poolmask(naddr, raddr, rmask, &rpool->counter, af);
}
break;
case PF_POOL_SRCHASH:
@@ -668,35 +666,31 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
hashidx =
pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
- if (rpool->cur->addr.type == PF_ADDR_TABLE) {
- cnt = rpool->cur->addr.p.tbl->pfrkt_cnt;
- if (cnt == 0)
- rpool->tblidx = 0;
+ if (rpool->cur->addr.type == PF_ADDR_TABLE ||
+ rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
+ if (rpool->cur->addr.type == PF_ADDR_TABLE)
+ kt = rpool->cur->addr.p.tbl;
else
- rpool->tblidx = (int)(hashidx % cnt);
- memset(&rpool->counter, 0, sizeof(rpool->counter));
- if (pfr_pool_get(rpool->cur->addr.p.tbl,
- &rpool->tblidx, &rpool->counter, af, NULL)) {
+ kt = rpool->cur->addr.p.dyn->pfid_kt;
+ kt = pfr_ktable_select_active(kt);
+ if (kt == NULL) {
reason = PFRES_MAPFAILED;
goto done_pool_mtx; /* unsupported */
}
- PF_ACPY(naddr, &rpool->counter, af);
- } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
- cnt = rpool->cur->addr.p.dyn->pfid_kt->pfrkt_cnt;
+ cnt = kt->pfrkt_cnt;
if (cnt == 0)
rpool->tblidx = 0;
else
rpool->tblidx = (int)(hashidx % cnt);
memset(&rpool->counter, 0, sizeof(rpool->counter));
- if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
- &rpool->tblidx, &rpool->counter, af,
- pf_islinklocal)) {
+ if (pfr_pool_get(kt, &rpool->tblidx, &rpool->counter,
+ af, pf_islinklocal, false)) {
reason = PFRES_MAPFAILED;
goto done_pool_mtx; /* unsupported */
}
- PF_ACPY(naddr, &rpool->counter, af);
+ pf_addrcpy(naddr, &rpool->counter, af);
} else {
- PF_POOLMASK(naddr, raddr, rmask,
+ pf_poolmask(naddr, raddr, rmask,
(struct pf_addr *)&hash, af);
}
break;
@@ -707,11 +701,12 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
if (rpool->cur->addr.type == PF_ADDR_TABLE) {
if (!pfr_pool_get(rpool->cur->addr.p.tbl,
- &rpool->tblidx, &rpool->counter, af, NULL))
+ &rpool->tblidx, &rpool->counter, af, NULL, true))
goto get_addr;
} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
- &rpool->tblidx, &rpool->counter, af, pf_islinklocal))
+ &rpool->tblidx, &rpool->counter, af, pf_islinklocal,
+ true))
goto get_addr;
} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
goto get_addr;
@@ -721,9 +716,10 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
rpool->cur = TAILQ_FIRST(&rpool->list);
else
rpool->cur = TAILQ_NEXT(rpool->cur, entries);
+ rpool->tblidx = -1;
if (rpool->cur->addr.type == PF_ADDR_TABLE) {
if (pfr_pool_get(rpool->cur->addr.p.tbl,
- &rpool->tblidx, &rpool->counter, af, NULL)) {
+ &rpool->tblidx, &rpool->counter, af, NULL, true)) {
/* table contains no address of type 'af' */
if (rpool->cur != acur)
goto try_next;
@@ -731,9 +727,9 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
goto done_pool_mtx;
}
} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
- rpool->tblidx = -1;
if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
- &rpool->tblidx, &rpool->counter, af, pf_islinklocal)) {
+ &rpool->tblidx, &rpool->counter, af, pf_islinklocal,
+ true)) {
/* table contains no address of type 'af' */
if (rpool->cur != acur)
goto try_next;
@@ -743,14 +739,14 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
} else {
raddr = &rpool->cur->addr.v.a.addr;
rmask = &rpool->cur->addr.v.a.mask;
- PF_ACPY(&rpool->counter, raddr, af);
+ pf_addrcpy(&rpool->counter, raddr, af);
}
get_addr:
- PF_ACPY(naddr, &rpool->counter, af);
+ pf_addrcpy(naddr, &rpool->counter, af);
if (init_addr != NULL && PF_AZERO(init_addr, af))
- PF_ACPY(init_addr, naddr, af);
- PF_AINC(&rpool->counter, af);
+ pf_addrcpy(init_addr, naddr, af);
+ pf_addr_inc(&rpool->counter, af);
break;
}
}
@@ -761,48 +757,41 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
done_pool_mtx:
mtx_unlock(&rpool->mtx);
- if (reason) {
- counter_u64_add(V_pf_status.counters[reason], 1);
- }
-
return (reason);
}
u_short
pf_map_addr_sn(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr,
- struct pf_ksrc_node **sn, struct pf_srchash **sh, struct pf_kpool *rpool,
- pf_sn_types_t sn_type)
+ struct pf_kpool *rpool, pf_sn_types_t sn_type)
{
+ struct pf_ksrc_node *sn = NULL;
+ struct pf_srchash *sh = NULL;
u_short reason = 0;
- KASSERT(*sn == NULL, ("*sn not NULL"));
-
/*
* If this is a sticky-address rule, try to find an existing src_node.
- * Request the sh to be unlocked if sn was not found, as we never
- * insert a new sn when parsing the ruleset.
*/
if (rpool->opts & PF_POOL_STICKYADDR &&
(rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE)
- *sn = pf_find_src_node(saddr, r, af, sh, sn_type, false);
+ sn = pf_find_src_node(saddr, r, af, &sh, sn_type, false);
- if (*sn != NULL) {
- PF_SRC_NODE_LOCK_ASSERT(*sn);
+ if (sn != NULL) {
+ PF_SRC_NODE_LOCK_ASSERT(sn);
/* If the supplied address is the same as the current one we've
* been asked before, so tell the caller that there's no other
* address to be had. */
- if (PF_AEQ(naddr, &(*sn)->raddr, af)) {
+ if (PF_AEQ(naddr, &(sn->raddr), af)) {
reason = PFRES_MAPFAILED;
goto done;
}
- PF_ACPY(naddr, &(*sn)->raddr, af);
+ pf_addrcpy(naddr, &(sn->raddr), af);
if (nkif)
- *nkif = (*sn)->rkif;
+ *nkif = sn->rkif;
if (V_pf_status.debug >= PF_DEBUG_NOISY) {
- printf("pf_map_addr: src tracking maps ");
+ printf("%s: src tracking maps ", __func__);
pf_print_host(saddr, 0, af);
printf(" to ");
pf_print_host(naddr, 0, af);
@@ -817,14 +806,16 @@ pf_map_addr_sn(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
* Source node has not been found. Find a new address and store it
* in variables given by the caller.
*/
- if (pf_map_addr(af, r, saddr, naddr, nkif, init_addr, rpool) != 0) {
- /* pf_map_addr() sets reason counters on its own */
+ if ((reason = pf_map_addr(af, r, saddr, naddr, nkif, init_addr,
+ rpool)) != 0) {
+ if (V_pf_status.debug >= PF_DEBUG_MISC)
+ printf("%s: pf_map_addr has failed\n", __func__);
goto done;
}
if (V_pf_status.debug >= PF_DEBUG_NOISY &&
(rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
- printf("pf_map_addr: selected address ");
+ printf("%s: selected address ", __func__);
pf_print_host(naddr, 0, af);
if (nkif)
printf("@%s", (*nkif)->pfik_name);
@@ -832,12 +823,8 @@ pf_map_addr_sn(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
}
done:
- if ((*sn) != NULL)
- PF_SRC_NODE_UNLOCK(*sn);
-
- if (reason) {
- counter_u64_add(V_pf_status.counters[reason], 1);
- }
+ if (sn != NULL)
+ PF_SRC_NODE_UNLOCK(sn);
return (reason);
}
@@ -887,8 +874,6 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
{
struct pf_pdesc *pd = ctx->pd;
struct pf_addr *naddr;
- struct pf_ksrc_node *sn = NULL;
- struct pf_srchash *sh = NULL;
uint16_t *nportp;
uint16_t low, high;
u_short reason;
@@ -916,8 +901,8 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
high = rpool->proxy_port[1];
}
if (rpool->mape.offset > 0) {
- if (pf_get_mape_sport(pd, r, naddr, nportp, &sn,
- &sh, &ctx->udp_mapping, rpool)) {
+ if (pf_get_mape_sport(pd, r, naddr, nportp,
+ &ctx->udp_mapping, rpool)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: MAP-E port allocation (%u/%u/%u)"
" failed\n",
@@ -927,8 +912,8 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
reason = PFRES_MAPFAILED;
goto notrans;
}
- } else if (pf_get_sport(pd, r, naddr, nportp, low, high, &sn,
- &sh, rpool, &ctx->udp_mapping, PF_SN_NAT)) {
+ } else if (pf_get_sport(pd, r, naddr, nportp, low, high,
+ rpool, &ctx->udp_mapping, PF_SN_NAT)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: NAT proxy port allocation (%u-%u) failed\n",
rpool->proxy_port[0], rpool->proxy_port[1]));
@@ -948,7 +933,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
reason = PFRES_MAPFAILED;
goto notrans;
}
- PF_POOLMASK(naddr,
+ pf_poolmask(naddr,
&rpool->cur->addr.p.dyn->pfid_addr4,
&rpool->cur->addr.p.dyn->pfid_mask4,
&pd->nsaddr, AF_INET);
@@ -961,7 +946,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
reason = PFRES_MAPFAILED;
goto notrans;
}
- PF_POOLMASK(naddr,
+ pf_poolmask(naddr,
&rpool->cur->addr.p.dyn->pfid_addr6,
&rpool->cur->addr.p.dyn->pfid_mask6,
&pd->nsaddr, AF_INET6);
@@ -969,7 +954,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
#endif /* INET6 */
}
} else
- PF_POOLMASK(naddr,
+ pf_poolmask(naddr,
&rpool->cur->addr.v.a.addr,
&rpool->cur->addr.v.a.mask, &pd->nsaddr,
pd->af);
@@ -983,7 +968,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
reason = PFRES_MAPFAILED;
goto notrans;
}
- PF_POOLMASK(naddr,
+ pf_poolmask(naddr,
&r->src.addr.p.dyn->pfid_addr4,
&r->src.addr.p.dyn->pfid_mask4,
&pd->ndaddr, AF_INET);
@@ -995,7 +980,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
reason = PFRES_MAPFAILED;
goto notrans;
}
- PF_POOLMASK(naddr,
+ pf_poolmask(naddr,
&r->src.addr.p.dyn->pfid_addr6,
&r->src.addr.p.dyn->pfid_mask6,
&pd->ndaddr, AF_INET6);
@@ -1003,7 +988,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
#endif /* INET6 */
}
} else
- PF_POOLMASK(naddr, &r->src.addr.v.a.addr,
+ pf_poolmask(naddr, &r->src.addr.v.a.addr,
&r->src.addr.v.a.mask, &pd->ndaddr, pd->af);
break;
}
@@ -1014,11 +999,11 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
uint16_t cut, low, high, nport;
reason = pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL,
- NULL, &sn, &sh, rpool, PF_SN_NAT);
+ NULL, rpool, PF_SN_NAT);
if (reason != 0)
goto notrans;
if ((rpool->opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK)
- PF_POOLMASK(naddr, naddr, &rpool->cur->addr.v.a.mask,
+ pf_poolmask(naddr, naddr, &rpool->cur->addr.v.a.mask,
&pd->ndaddr, pd->af);
/* Do not change SCTP ports. */
@@ -1027,10 +1012,13 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
if (rpool->proxy_port[1]) {
uint32_t tmp_nport;
+ uint16_t div;
+
+ div = r->rdr.proxy_port[1] - r->rdr.proxy_port[0] + 1;
+ div = (div == 0) ? 1 : div;
- tmp_nport = ((ntohs(pd->ndport) - ntohs(r->dst.port[0])) %
- (rpool->proxy_port[1] - rpool->proxy_port[0] +
- 1)) + rpool->proxy_port[0];
+ tmp_nport = ((ntohs(pd->ndport) - ntohs(r->dst.port[0])) % div) +
+ rpool->proxy_port[0];
/* Wrap around if necessary. */
if (tmp_nport > 65535)
@@ -1056,9 +1044,9 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
key.af = pd->af;
key.proto = pd->proto;
key.port[0] = pd->nsport;
- PF_ACPY(&key.addr[0], &pd->nsaddr, key.af);
+ pf_addrcpy(&key.addr[0], &pd->nsaddr, key.af);
key.port[1] = nport;
- PF_ACPY(&key.addr[1], naddr, key.af);
+ pf_addrcpy(&key.addr[1], naddr, key.af);
if (!pf_find_state_all_exists(&key, PF_OUT))
break;
@@ -1131,8 +1119,6 @@ pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd)
struct pf_addr ndaddr, nsaddr, naddr;
u_int16_t nport = 0;
int prefixlen = 96;
- struct pf_srchash *sh = NULL;
- struct pf_ksrc_node *sns = NULL;
bzero(&nsaddr, sizeof(nsaddr));
bzero(&ndaddr, sizeof(ndaddr));
@@ -1151,9 +1137,8 @@ pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd)
panic("pf_get_transaddr_af: no nat pool for source address");
/* get source address and port */
- if (pf_get_sport(pd, r, &nsaddr, &nport,
- r->nat.proxy_port[0], r->nat.proxy_port[1], &sns, &sh, &r->nat,
- NULL, PF_SN_NAT)) {
+ if (pf_get_sport(pd, r, &nsaddr, &nport, r->nat.proxy_port[0],
+ r->nat.proxy_port[1], &r->nat, NULL, PF_SN_NAT)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: af-to NAT proxy port allocation (%u-%u) failed",
r->nat.proxy_port[0], r->nat.proxy_port[1]));
@@ -1179,7 +1164,7 @@ pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd)
/* get the destination address and port */
if (! TAILQ_EMPTY(&r->rdr.list)) {
if (pf_map_addr_sn(pd->naf, r, &nsaddr, &naddr, NULL, NULL,
- &sns, NULL, &r->rdr, PF_SN_NAT))
+ &r->rdr, PF_SN_NAT))
return (-1);
if (r->rdr.proxy_port[0])
pd->ndport = htons(r->rdr.proxy_port[0]);
@@ -1220,8 +1205,8 @@ pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd)
}
}
- PF_ACPY(&pd->nsaddr, &nsaddr, pd->naf);
- PF_ACPY(&pd->ndaddr, &ndaddr, pd->naf);
+ pf_addrcpy(&pd->nsaddr, &nsaddr, pd->naf);
+ pf_addrcpy(&pd->ndaddr, &ndaddr, pd->naf);
if (V_pf_status.debug >= PF_DEBUG_MISC) {
printf("pf: af-to %s done, prefixlen %d, ",
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index 381e966eacf1..73933c022ca2 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -1256,23 +1256,13 @@ pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
return (0);
}
-struct pf_nl_natlook {
- sa_family_t af;
- uint8_t direction;
- uint8_t proto;
- struct pf_addr src;
- struct pf_addr dst;
- uint16_t sport;
- uint16_t dport;
-};
-
-#define _OUT(_field) offsetof(struct pf_nl_natlook, _field)
+#define _OUT(_field) offsetof(struct pfioc_natlook, _field)
static const struct nlattr_parser nla_p_natlook[] = {
{ .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
{ .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
{ .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
- { .type = PF_NL_SRC_ADDR, .off = _OUT(src), .cb = nlattr_get_in6_addr },
- { .type = PF_NL_DST_ADDR, .off = _OUT(dst), .cb = nlattr_get_in6_addr },
+ { .type = PF_NL_SRC_ADDR, .off = _OUT(saddr), .cb = nlattr_get_in6_addr },
+ { .type = PF_NL_DST_ADDR, .off = _OUT(daddr), .cb = nlattr_get_in6_addr },
{ .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 },
{ .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 },
};
@@ -1282,63 +1272,31 @@ NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_empty, nla_p_natlook)
static int
pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt)
{
- struct pf_nl_natlook attrs = {};
- struct pf_state_key_cmp key = {};
+ struct pfioc_natlook attrs = {};
struct nl_writer *nw = npt->nw;
- struct pf_state_key *sk;
- struct pf_kstate *state;
struct genlmsghdr *ghdr_new;
- int error, m = 0;
- int sidx, didx;
+ int error;
error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs);
if (error != 0)
return (error);
- if (attrs.proto == 0 ||
- PF_AZERO(&attrs.src, attrs.af) ||
- PF_AZERO(&attrs.dst, attrs.af) ||
- ((attrs.proto == IPPROTO_TCP || attrs.proto == IPPROTO_UDP) &&
- (attrs.sport == 0 || attrs.dport == 0)))
- return (EINVAL);
-
- /* NATLOOK src and dst are reversed, so reverse sidx/didx */
- sidx = (attrs.direction == PF_IN) ? 1 : 0;
- didx = (attrs.direction == PF_IN) ? 0 : 1;
-
- key.af = attrs.af;
- key.proto = attrs.proto;
- PF_ACPY(&key.addr[sidx], &attrs.src, attrs.af);
- key.port[sidx] = attrs.sport;
- PF_ACPY(&key.addr[didx], &attrs.dst, attrs.af);
- key.port[didx] = attrs.dport;
-
- state = pf_find_state_all(&key, attrs.direction, &m);
- if (state == NULL)
- return (ENOENT);
- if (m > 1) {
- PF_STATE_UNLOCK(state);
- return (E2BIG);
- }
+ error = pf_ioctl_natlook(&attrs);
+ if (error != 0)
+ return (error);
- if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
- PF_STATE_UNLOCK(state);
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
return (ENOMEM);
- }
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
ghdr_new->cmd = PFNL_CMD_NATLOOK;
ghdr_new->version = 0;
ghdr_new->reserved = 0;
- sk = state->key[sidx];
-
- nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &sk->addr[sidx].v6);
- nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &sk->addr[didx].v6);
- nlattr_add_u16(nw, PF_NL_SRC_PORT, sk->port[sidx]);
- nlattr_add_u16(nw, PF_NL_DST_PORT, sk->port[didx]);
-
- PF_STATE_UNLOCK(state);
+ nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &attrs.rsaddr.v6);
+ nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &attrs.rdaddr.v6);
+ nlattr_add_u16(nw, PF_NL_SRC_PORT, attrs.rsport);
+ nlattr_add_u16(nw, PF_NL_DST_PORT, attrs.rdport);
if (!nlmsg_end(nw)) {
nlmsg_abort(nw);
diff --git a/sys/netpfil/pf/pf_ruleset.c b/sys/netpfil/pf/pf_ruleset.c
index 865c5ecd72d9..2e5165a9900c 100644
--- a/sys/netpfil/pf/pf_ruleset.c
+++ b/sys/netpfil/pf/pf_ruleset.c
@@ -232,7 +232,7 @@ pf_get_leaf_kruleset(char *path, char **path_remainder)
return (ruleset);
}
-struct pf_kanchor *
+static struct pf_kanchor *
pf_create_kanchor(struct pf_kanchor *parent, const char *aname)
{
struct pf_kanchor *anchor, *dup;
@@ -259,8 +259,8 @@ pf_create_kanchor(struct pf_kanchor *parent, const char *aname)
if ((dup = RB_INSERT(pf_kanchor_global, &V_pf_anchors, anchor)) !=
NULL) {
- printf("pf_find_or_create_ruleset: RB_INSERT1 "
- "'%s' '%s' collides with '%s' '%s'\n",
+ printf("%s: RB_INSERT1 "
+ "'%s' '%s' collides with '%s' '%s'\n", __func__,
anchor->path, anchor->name, dup->path, dup->name);
rs_free(anchor);
return (NULL);
@@ -270,10 +270,10 @@ pf_create_kanchor(struct pf_kanchor *parent, const char *aname)
anchor->parent = parent;
if ((dup = RB_INSERT(pf_kanchor_node, &parent->children,
anchor)) != NULL) {
- printf("pf_find_or_create_ruleset: "
+ printf("%s: "
"RB_INSERT2 '%s' '%s' collides with "
- "'%s' '%s'\n", anchor->path, anchor->name,
- dup->path, dup->name);
+ "'%s' '%s'\n", __func__, anchor->path,
+ anchor->name, dup->path, dup->name);
RB_REMOVE(pf_kanchor_global, &V_pf_anchors,
anchor);
rs_free(anchor);
@@ -339,7 +339,7 @@ pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
int i;
while (ruleset != NULL) {
- if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
+ if (ruleset == &pf_main_ruleset ||
!RB_EMPTY(&ruleset->anchor->children) ||
ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
ruleset->topen)
@@ -407,7 +407,7 @@ pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
}
ruleset = pf_find_or_create_kruleset(path);
rs_free(path);
- if (ruleset == NULL || ruleset->anchor == NULL) {
+ if (ruleset == NULL || ruleset == &pf_main_ruleset) {
DPFPRINTF("%s: ruleset\n", __func__);
return (1);
}
@@ -432,7 +432,7 @@ pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
char a[MAXPATHLEN];
char *p;
int i;
- if (rs->anchor == NULL)
+ if (rs == &pf_main_ruleset)
a[0] = 0;
else
strlcpy(a, rs->anchor->path, MAXPATHLEN);
@@ -444,7 +444,7 @@ pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
anchor_call_len);
}
if (strncmp(a, r->anchor->path, strlen(a))) {
- printf("pf_anchor_copyout: '%s' '%s'\n", a,
+ printf("%s: '%s' '%s'\n", __func__, a,
r->anchor->path);
return (1);
}
@@ -525,16 +525,13 @@ done:
}
void
-pf_kanchor_remove(struct pf_krule *r)
+pf_remove_kanchor(struct pf_krule *r)
{
if (r->anchor == NULL)
return;
- if (r->anchor->refcnt <= 0) {
- printf("pf_anchor_remove: broken refcount\n");
- r->anchor = NULL;
- return;
- }
- if (!--r->anchor->refcnt)
+ if (r->anchor->refcnt <= 0)
+ printf("%s: broken refcount\n", __func__);
+ else if (!--r->anchor->refcnt)
pf_remove_if_empty_kruleset(&r->anchor->ruleset);
r->anchor = NULL;
}
diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c
index d5874df3df66..9c0151b7da2b 100644
--- a/sys/netpfil/pf/pf_table.c
+++ b/sys/netpfil/pf/pf_table.c
@@ -704,7 +704,7 @@ pfr_validate_addr(struct pfr_addr *ad)
return (-1);
if (ad->pfra_not && ad->pfra_not != 1)
return (-1);
- if (ad->pfra_fback)
+ if (ad->pfra_fback != PFR_FB_NONE)
return (-1);
return (0);
}
@@ -819,10 +819,10 @@ pfr_create_kentry(struct pfr_addr *ad, bool counters)
static void
pfr_destroy_kentries(struct pfr_kentryworkq *workq)
{
- struct pfr_kentry *p, *q;
+ struct pfr_kentry *p;
- for (p = SLIST_FIRST(workq); p != NULL; p = q) {
- q = SLIST_NEXT(p, pfrke_workq);
+ while ((p = SLIST_FIRST(workq)) != NULL) {
+ SLIST_REMOVE_HEAD(workq, pfrke_workq);
pfr_destroy_kentry(p);
}
}
@@ -1680,8 +1680,7 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
}
if (!(flags & PFR_FLAG_DUMMY)) {
- for (p = SLIST_FIRST(&workq); p != NULL; p = q) {
- q = SLIST_NEXT(p, pfrkt_workq);
+ SLIST_FOREACH_SAFE(p, &workq, pfrkt_workq, q) {
pfr_commit_ktable(p, tzero);
}
rs->topen = 0;
@@ -1710,7 +1709,7 @@ pfr_commit_ktable(struct pfr_ktable *kt, time_t tzero)
} else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) {
/* kt might contain addresses */
struct pfr_kentryworkq addrq, addq, changeq, delq, garbageq;
- struct pfr_kentry *p, *q, *next;
+ struct pfr_kentry *p, *q;
struct pfr_addr ad;
pfr_enqueue_addrs(shadow, &addrq, NULL, 0);
@@ -1720,7 +1719,8 @@ pfr_commit_ktable(struct pfr_ktable *kt, time_t tzero)
SLIST_INIT(&delq);
SLIST_INIT(&garbageq);
pfr_clean_node_mask(shadow, &addrq);
- SLIST_FOREACH_SAFE(p, &addrq, pfrke_workq, next) {
+ while ((p = SLIST_FIRST(&addrq)) != NULL) {
+ SLIST_REMOVE_HEAD(&addrq, pfrke_workq);
pfr_copyout_addr(&ad, p);
q = pfr_lookup_addr(kt, &ad, 1);
if (q != NULL) {
@@ -1864,8 +1864,7 @@ pfr_setflags_ktables(struct pfr_ktableworkq *workq)
{
struct pfr_ktable *p, *q;
- for (p = SLIST_FIRST(workq); p; p = q) {
- q = SLIST_NEXT(p, pfrkt_workq);
+ SLIST_FOREACH_SAFE(p, workq, pfrkt_workq, q) {
pfr_setflags_ktable(p, p->pfrkt_nflags);
}
}
@@ -2015,10 +2014,10 @@ pfr_create_ktable(struct pfr_table *tbl, time_t tzero, int attachruleset)
static void
pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr)
{
- struct pfr_ktable *p, *q;
+ struct pfr_ktable *p;
- for (p = SLIST_FIRST(workq); p; p = q) {
- q = SLIST_NEXT(p, pfrkt_workq);
+ while ((p = SLIST_FIRST(workq)) != NULL) {
+ SLIST_REMOVE_HEAD(workq, pfrkt_workq);
pfr_destroy_ktable(p, flushaddr);
}
}
@@ -2074,17 +2073,16 @@ pfr_lookup_table(struct pfr_table *tbl)
(struct pfr_ktable *)tbl));
}
-int
-pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
+static struct pfr_kentry *
+pfr_kentry_byaddr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
+ int exact)
{
struct pfr_kentry *ke = NULL;
- int match;
PF_RULES_RASSERT();
- if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
- kt = kt->pfrkt_root;
- if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
+ kt = pfr_ktable_select_active(kt);
+ if (kt == NULL)
return (0);
switch (af) {
@@ -2121,11 +2119,26 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
default:
unhandled_af(af);
}
+ if (exact && ke && KENTRY_NETWORK(ke))
+ ke = NULL;
+
+ return (ke);
+}
+
+int
+pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
+{
+ struct pfr_kentry *ke = NULL;
+ int match;
+
+ ke = pfr_kentry_byaddr(kt, a, af, 0);
+
match = (ke && !ke->pfrke_not);
if (match)
pfr_kstate_counter_add(&kt->pfrkt_match, 1);
else
pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1);
+
return (match);
}
@@ -2135,9 +2148,8 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
{
struct pfr_kentry *ke = NULL;
- if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
- kt = kt->pfrkt_root;
- if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
+ kt = pfr_ktable_select_active(kt);
+ if (kt == NULL)
return;
switch (af) {
@@ -2281,7 +2293,7 @@ pfr_detach_table(struct pfr_ktable *kt)
int
pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
- sa_family_t af, pf_addr_filter_func_t filter)
+ sa_family_t af, pf_addr_filter_func_t filter, bool loop_once)
{
struct pf_addr *addr, cur, mask, umask_addr;
union sockaddr_union uaddr, umask;
@@ -2306,9 +2318,8 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
unhandled_af(af);
}
- if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
- kt = kt->pfrkt_root;
- if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
+ kt = pfr_ktable_select_active(kt);
+ if (kt == NULL)
return (-1);
idx = *pidx;
@@ -2327,7 +2338,7 @@ _next_block:
ke = pfr_kentry_byidx(kt, idx, af);
if (ke == NULL) {
/* we don't have this idx, try looping */
- if (loop || (ke = pfr_kentry_byidx(kt, 0, af)) == NULL) {
+ if ((loop || loop_once) || (ke = pfr_kentry_byidx(kt, 0, af)) == NULL) {
pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1);
return (1);
}
@@ -2340,16 +2351,16 @@ _next_block:
if (use_counter && !PF_AZERO(counter, af)) {
/* is supplied address within block? */
- if (!PF_MATCHA(0, &cur, &mask, counter, af)) {
+ if (!pf_match_addr(0, &cur, &mask, counter, af)) {
/* no, go to next block in table */
idx++;
use_counter = 0;
goto _next_block;
}
- PF_ACPY(addr, counter, af);
+ pf_addrcpy(addr, counter, af);
} else {
/* use first address of block */
- PF_ACPY(addr, &cur, af);
+ pf_addrcpy(addr, &cur, af);
}
if (!KENTRY_NETWORK(ke)) {
@@ -2358,7 +2369,7 @@ _next_block:
idx++;
goto _next_block;
}
- PF_ACPY(counter, addr, af);
+ pf_addrcpy(counter, addr, af);
*pidx = idx;
pfr_kstate_counter_add(&kt->pfrkt_match, 1);
return (0);
@@ -2382,7 +2393,7 @@ _next_block:
/* lookup return the same block - perfect */
if (filter && filter(af, addr))
goto _next_entry;
- PF_ACPY(counter, addr, af);
+ pf_addrcpy(counter, addr, af);
*pidx = idx;
pfr_kstate_counter_add(&kt->pfrkt_match, 1);
return (0);
@@ -2392,9 +2403,9 @@ _next_entry:
/* we need to increase the counter past the nested block */
pfr_prepare_network(&umask, AF_INET, ke2->pfrke_net);
pfr_sockaddr_to_pf_addr(&umask, &umask_addr);
- PF_POOLMASK(addr, addr, &umask_addr, &pfr_ffaddr, af);
- PF_AINC(addr, af);
- if (!PF_MATCHA(0, &cur, &mask, addr, af)) {
+ pf_poolmask(addr, addr, &umask_addr, &pfr_ffaddr, af);
+ pf_addr_inc(addr, af);
+ if (!pf_match_addr(0, &cur, &mask, addr, af)) {
/* ok, we reached the end of our main block */
/* go to next block in table */
idx++;
@@ -2455,3 +2466,14 @@ pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn)
unhandled_af(dyn->pfid_af);
}
}
+
+struct pfr_ktable *
+pfr_ktable_select_active(struct pfr_ktable *kt)
+{
+ if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
+ kt = kt->pfrkt_root;
+ if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
+ return (NULL);
+
+ return (kt);
+}
diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c
index 7746b668265d..ae17b3289593 100644
--- a/sys/powerpc/aim/mmu_oea.c
+++ b/sys/powerpc/aim/mmu_oea.c
@@ -1469,6 +1469,9 @@ moea_page_set_memattr(vm_page_t m, vm_memattr_t ma)
pmap_t pmap;
u_int lo;
+ if (m->md.mdpg_cache_attrs == ma)
+ return;
+
if ((m->oflags & VPO_UNMANAGED) != 0) {
m->md.mdpg_cache_attrs = ma;
return;
diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c
index 79cea408bb5f..796b1719b8ba 100644
--- a/sys/powerpc/aim/mmu_oea64.c
+++ b/sys/powerpc/aim/mmu_oea64.c
@@ -2134,6 +2134,9 @@ moea64_page_set_memattr(vm_page_t m, vm_memattr_t ma)
CTR3(KTR_PMAP, "%s: pa=%#jx, ma=%#x",
__func__, (uintmax_t)VM_PAGE_TO_PHYS(m), ma);
+ if (m->md.mdpg_cache_attrs == ma)
+ return;
+
if ((m->oflags & VPO_UNMANAGED) != 0) {
m->md.mdpg_cache_attrs = ma;
return;
diff --git a/sys/powerpc/aim/mmu_radix.c b/sys/powerpc/aim/mmu_radix.c
index 45f7bef8bcc9..a12142fc2d7b 100644
--- a/sys/powerpc/aim/mmu_radix.c
+++ b/sys/powerpc/aim/mmu_radix.c
@@ -5937,6 +5937,10 @@ mmu_radix_page_set_memattr(vm_page_t m, vm_memattr_t ma)
{
CTR3(KTR_PMAP, "%s(%p, %#x)", __func__, m, ma);
+
+ if (m->md.mdpg_cache_attrs == ma)
+ return;
+
m->md.mdpg_cache_attrs = ma;
/*
diff --git a/sys/powerpc/include/pcb.h b/sys/powerpc/include/pcb.h
index 050ada6b0f64..0230cf78aba7 100644
--- a/sys/powerpc/include/pcb.h
+++ b/sys/powerpc/include/pcb.h
@@ -66,16 +66,8 @@ struct pcb {
#define PCB_VECREGS 0x200 /* Process had Altivec registers initialized */
struct fpu {
union {
-#if _BYTE_ORDER == _BIG_ENDIAN
- double fpr;
- uint32_t vsr[4];
-#else
uint32_t vsr[4];
- struct {
- double padding;
- double fpr;
- };
-#endif
+ double fpr;
} fpr[32];
double fpscr; /* FPSCR stored as double for easier access */
} pcb_fpu; /* Floating point processor */
diff --git a/sys/powerpc/include/ucontext.h b/sys/powerpc/include/ucontext.h
index d35c6c773fe0..dc87edd578bc 100644
--- a/sys/powerpc/include/ucontext.h
+++ b/sys/powerpc/include/ucontext.h
@@ -41,6 +41,7 @@ typedef struct __mcontext {
int mc_flags;
#define _MC_FP_VALID 0x01
#define _MC_AV_VALID 0x02
+#define _MC_VS_VALID 0x04
int mc_onstack; /* saved onstack flag */
int mc_len; /* sizeof(__mcontext) */
__uint64_t mc_avec[32*2]; /* vector register file */
@@ -56,6 +57,7 @@ typedef struct __mcontext32 {
int mc_flags;
#define _MC_FP_VALID 0x01
#define _MC_AV_VALID 0x02
+#define _MC_VS_VALID 0x04
int mc_onstack; /* saved onstack flag */
int mc_len; /* sizeof(__mcontext) */
uint64_t mc_avec[32*2]; /* vector register file */
diff --git a/sys/powerpc/mpc85xx/mpc85xx_gpio.c b/sys/powerpc/mpc85xx/mpc85xx_gpio.c
index 0f333feb747f..cb96d768adef 100644
--- a/sys/powerpc/mpc85xx/mpc85xx_gpio.c
+++ b/sys/powerpc/mpc85xx/mpc85xx_gpio.c
@@ -226,14 +226,14 @@ mpc85xx_gpio_attach(device_t dev)
return (ENOMEM);
}
+ OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
+
sc->busdev = gpiobus_attach_bus(dev);
if (sc->busdev == NULL) {
mpc85xx_gpio_detach(dev);
return (ENOMEM);
}
- OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
-
return (0);
}
diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c
index 1893d79f29a8..8a33d0f589a7 100644
--- a/sys/powerpc/powerpc/exec_machdep.c
+++ b/sys/powerpc/powerpc/exec_machdep.c
@@ -214,10 +214,10 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
sfpsize = sizeof(sf);
#ifdef __powerpc64__
/*
- * 64-bit PPC defines a 288 byte scratch region
- * below the stack.
+ * 64-bit PPC defines a 512 byte red zone below
+ * the existing stack (ELF ABI v2 §2.2.2.4)
*/
- rndfsize = 288 + roundup(sizeof(sf), 48);
+ rndfsize = 512 + roundup(sizeof(sf), 48);
#else
rndfsize = roundup(sizeof(sf), 16);
#endif
@@ -349,13 +349,6 @@ sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
if (error != 0)
return (error);
- /*
- * Save FPU state if needed. User may have changed it on
- * signal handler
- */
- if (uc.uc_mcontext.mc_srr1 & PSL_FP)
- save_fpu(td);
-
kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
CTR3(KTR_SIG, "sigreturn: return td=%p pc=%#x sp=%#x",
@@ -432,6 +425,7 @@ grab_mcontext(struct thread *td, mcontext_t *mcp, int flags)
}
if (pcb->pcb_flags & PCB_VSX) {
+ mcp->mc_flags |= _MC_VS_VALID;
for (i = 0; i < 32; i++)
memcpy(&mcp->mc_vsxfpreg[i],
&pcb->pcb_fpu.fpr[i].vsr[2], sizeof(double));
@@ -481,6 +475,7 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
struct pcb *pcb;
struct trapframe *tf;
register_t tls;
+ register_t msr;
int i;
pcb = td->td_pcb;
@@ -531,6 +526,22 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
tf->srr1 &= ~(PSL_FP | PSL_VSX | PSL_VEC);
pcb->pcb_flags &= ~(PCB_FPU | PCB_VSX | PCB_VEC);
+ /*
+ * Ensure the FPU is also disabled in hardware.
+ *
+ * Without this, it's possible for the register reload to fail if we
+ * don't switch to a FPU disabled context before resuming the original
+ * thread. Specifically, if the FPU/VSX unavailable exception is never
+ * hit, then whatever data is still in the FP/VSX registers when
+ * sigresume is callled will used by the resumed thread, instead of the
+ * previously saved data from the mcontext.
+ */
+ critical_enter();
+ msr = mfmsr() & ~(PSL_FP | PSL_VSX | PSL_VEC);
+ isync();
+ mtmsr(msr);
+ critical_exit();
+
if (mcp->mc_flags & _MC_FP_VALID) {
/* enable_fpu() will happen lazily on a fault */
pcb->pcb_flags |= PCB_FPREGS;
@@ -539,8 +550,12 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
for (i = 0; i < 32; i++) {
memcpy(&pcb->pcb_fpu.fpr[i].fpr, &mcp->mc_fpreg[i],
sizeof(double));
- memcpy(&pcb->pcb_fpu.fpr[i].vsr[2],
- &mcp->mc_vsxfpreg[i], sizeof(double));
+ }
+ if (mcp->mc_flags & _MC_VS_VALID) {
+ for (i = 0; i < 32; i++) {
+ memcpy(&pcb->pcb_fpu.fpr[i].vsr[2],
+ &mcp->mc_vsxfpreg[i], sizeof(double));
+ }
}
}
diff --git a/sys/powerpc/powerpc/fpu.c b/sys/powerpc/powerpc/fpu.c
index 0eaff2ea4932..cc8f22f7dda3 100644
--- a/sys/powerpc/powerpc/fpu.c
+++ b/sys/powerpc/powerpc/fpu.c
@@ -64,8 +64,19 @@ save_fpu_int(struct thread *td)
* Save the floating-point registers and FPSCR to the PCB
*/
if (pcb->pcb_flags & PCB_VSX) {
- #define SFP(n) __asm ("stxvw4x " #n ", 0,%0" \
+#if _BYTE_ORDER == _BIG_ENDIAN
+ #define SFP(n) __asm("stxvw4x " #n ", 0,%0" \
:: "b"(&pcb->pcb_fpu.fpr[n]));
+#else
+ /*
+ * stxvw2x will swap words within the FP double word on LE systems,
+ * leading to corruption if VSX is used to store state and FP is
+ * subsequently used to restore state.
+ * Use stxvd2x instead.
+ */
+ #define SFP(n) __asm("stxvd2x " #n ", 0,%0" \
+ :: "b"(&pcb->pcb_fpu.fpr[n]));
+#endif
SFP(0); SFP(1); SFP(2); SFP(3);
SFP(4); SFP(5); SFP(6); SFP(7);
SFP(8); SFP(9); SFP(10); SFP(11);
@@ -76,7 +87,7 @@ save_fpu_int(struct thread *td)
SFP(28); SFP(29); SFP(30); SFP(31);
#undef SFP
} else {
- #define SFP(n) __asm ("stfd " #n ", 0(%0)" \
+ #define SFP(n) __asm("stfd " #n ", 0(%0)" \
:: "b"(&pcb->pcb_fpu.fpr[n].fpr));
SFP(0); SFP(1); SFP(2); SFP(3);
SFP(4); SFP(5); SFP(6); SFP(7);
@@ -149,8 +160,19 @@ enable_fpu(struct thread *td)
:: "b"(&pcb->pcb_fpu.fpscr));
if (pcb->pcb_flags & PCB_VSX) {
- #define LFP(n) __asm ("lxvw4x " #n ", 0,%0" \
+#if _BYTE_ORDER == _BIG_ENDIAN
+ #define LFP(n) __asm("lxvw4x " #n ", 0,%0" \
+ :: "b"(&pcb->pcb_fpu.fpr[n]));
+#else
+ /*
+ * lxvw4x will swap words within the FP double word on LE systems,
+ * leading to corruption if FP is used to store state and VSX is
+ * subsequently used to restore state.
+ * Use lxvd2x instead.
+ */
+ #define LFP(n) __asm("lxvd2x " #n ", 0,%0" \
:: "b"(&pcb->pcb_fpu.fpr[n]));
+#endif
LFP(0); LFP(1); LFP(2); LFP(3);
LFP(4); LFP(5); LFP(6); LFP(7);
LFP(8); LFP(9); LFP(10); LFP(11);
@@ -161,7 +183,7 @@ enable_fpu(struct thread *td)
LFP(28); LFP(29); LFP(30); LFP(31);
#undef LFP
} else {
- #define LFP(n) __asm ("lfd " #n ", 0(%0)" \
+ #define LFP(n) __asm("lfd " #n ", 0(%0)" \
:: "b"(&pcb->pcb_fpu.fpr[n].fpr));
LFP(0); LFP(1); LFP(2); LFP(3);
LFP(4); LFP(5); LFP(6); LFP(7);
diff --git a/sys/riscv/allwinner/files.allwinner b/sys/riscv/allwinner/files.allwinner
index 423a89c10c78..7a4ff6b9c62e 100644
--- a/sys/riscv/allwinner/files.allwinner
+++ b/sys/riscv/allwinner/files.allwinner
@@ -1,5 +1,7 @@
arm/allwinner/aw_gpio.c optional gpio aw_gpio fdt
+arm/allwinner/aw_mmc.c optional mmc aw_mmc fdt | mmccam aw_mmc fdt
+arm/allwinner/aw_rtc.c optional aw_rtc fdt
arm/allwinner/aw_syscon.c optional syscon
arm/allwinner/aw_sid.c optional aw_sid nvmem
arm/allwinner/aw_timer.c optional aw_timer fdt
diff --git a/sys/riscv/conf/std.allwinner b/sys/riscv/conf/std.allwinner
index 1bf6b027a4cb..34fe195b01ba 100644
--- a/sys/riscv/conf/std.allwinner
+++ b/sys/riscv/conf/std.allwinner
@@ -7,6 +7,8 @@ options SOC_ALLWINNER_D1
device aw_ccu # Allwinner clock controller
device aw_gpio # Allwinner GPIO controller
+device aw_mmc # Allwinner SD/MMC controller
+device aw_rtc # Allwinner Real-time Clock
device aw_sid # Allwinner Secure ID EFUSE
device aw_timer # Allwinner Timer
device aw_usbphy # Allwinner USB PHY
diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c
index 5d15bd671285..26efaecc64d1 100644
--- a/sys/riscv/riscv/pmap.c
+++ b/sys/riscv/riscv/pmap.c
@@ -4838,6 +4838,8 @@ pmap_unmapbios(void *p, vm_size_t size)
void
pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma)
{
+ if (m->md.pv_memattr == ma)
+ return;
m->md.pv_memattr = ma;
diff --git a/sys/rpc/clnt_rc.c b/sys/rpc/clnt_rc.c
index 9e87af578885..44b63e38a8e6 100644
--- a/sys/rpc/clnt_rc.c
+++ b/sys/rpc/clnt_rc.c
@@ -198,6 +198,12 @@ clnt_reconnect_connect(CLIENT *cl)
newclient = clnt_vc_create(so,
(struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
rc->rc_sendsz, rc->rc_recvsz, rc->rc_intr);
+ /*
+ * CLSET_FD_CLOSE must be done now, in case rpctls_connect()
+ * fails just below.
+ */
+ if (newclient != NULL)
+ CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0);
if (rc->rc_tls && newclient != NULL) {
CURVNET_SET(so->so_vnet);
stat = rpctls_connect(newclient, rc->rc_tlscertname, so,
@@ -236,7 +242,6 @@ clnt_reconnect_connect(CLIENT *cl)
goto out;
}
- CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0);
CLNT_CONTROL(newclient, CLSET_CONNECT, &one);
CLNT_CONTROL(newclient, CLSET_TIMEOUT, &rc->rc_timeout);
CLNT_CONTROL(newclient, CLSET_RETRY_TIMEOUT, &rc->rc_retry);
diff --git a/sys/rpc/rpcsec_gss/rpcsec_gss.c b/sys/rpc/rpcsec_gss/rpcsec_gss.c
index 62c71937a185..983dd251f81f 100644
--- a/sys/rpc/rpcsec_gss/rpcsec_gss.c
+++ b/sys/rpc/rpcsec_gss/rpcsec_gss.c
@@ -67,6 +67,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/hash.h>
+#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/kobj.h>
#include <sys/lock.h>
@@ -772,6 +773,17 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
gd->gd_cred.gc_seq = 0;
/*
+ * XXX Threads from inside jails can get here via calls
+ * to clnt_vc_call()->AUTH_REFRESH()->rpc_gss_refresh()
+ * but the NFS mount is always done outside of the
+ * jails in vnet0. Since the thread credentials won't
+ * necessarily have cr_prison == vnet0 and this function
+ * has no access to the socket, using vnet0 seems the
+ * only option. This is broken if NFS mounts are enabled
+ * within vnet prisons.
+ */
+ KGSS_CURVNET_SET_QUIET(vnet0);
+ /*
* For KerberosV, if there is a client principal name, that implies
* that this is a host based initiator credential in the default
* keytab file. For this case, it is necessary to do a
@@ -994,12 +1006,14 @@ out:
gss_delete_sec_context(&min_stat, &gd->gd_ctx,
GSS_C_NO_BUFFER);
}
+ KGSS_CURVNET_RESTORE();
mtx_lock(&gd->gd_lock);
gd->gd_state = RPCSEC_GSS_START;
wakeup(gd);
mtx_unlock(&gd->gd_lock);
return (FALSE);
}
+ KGSS_CURVNET_RESTORE();
mtx_lock(&gd->gd_lock);
gd->gd_state = RPCSEC_GSS_ESTABLISHED;
diff --git a/sys/rpc/rpcsec_tls/rpctls_impl.c b/sys/rpc/rpcsec_tls/rpctls_impl.c
index 93fe283e65fd..51fe270b13d9 100644
--- a/sys/rpc/rpcsec_tls/rpctls_impl.c
+++ b/sys/rpc/rpcsec_tls/rpctls_impl.c
@@ -240,6 +240,14 @@ rpctls_rpc_failed(struct upsock *ups, struct socket *so)
* failed to do the handshake.
*/
mtx_unlock(&rpctls_lock);
+ /*
+ * Do a shutdown on the socket, since the daemon is
+ * probably stuck in SSL_accept() or SSL_connect() trying to
+ * read the socket. Do not soclose() the socket, since the
+ * daemon will close() the socket after SSL_accept()
+ * returns an error.
+ */
+ soshutdown(so, SHUT_RD);
}
}
diff --git a/sys/sys/caprights.h b/sys/sys/caprights.h
index 48c75afc62a0..6a5a17eda5ee 100644
--- a/sys/sys/caprights.h
+++ b/sys/sys/caprights.h
@@ -79,6 +79,8 @@ extern const cap_rights_t cap_futimes_rights;
extern const cap_rights_t cap_getpeername_rights;
extern const cap_rights_t cap_getsockopt_rights;
extern const cap_rights_t cap_getsockname_rights;
+extern const cap_rights_t cap_inotify_add_rights;
+extern const cap_rights_t cap_inotify_rm_rights;
extern const cap_rights_t cap_ioctl_rights;
extern const cap_rights_t cap_linkat_source_rights;
extern const cap_rights_t cap_linkat_target_rights;
diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h
index d493535454e9..3847c4c73e75 100644
--- a/sys/sys/capsicum.h
+++ b/sys/sys/capsicum.h
@@ -279,11 +279,15 @@
#define CAP_KQUEUE (CAP_KQUEUE_EVENT | CAP_KQUEUE_CHANGE)
+/* Allows operations on inotify descriptors. */
+#define CAP_INOTIFY_ADD CAPRIGHT(1, 0x0000000000200000ULL)
+#define CAP_INOTIFY_RM CAPRIGHT(1, 0x0000000000400000ULL)
+
/* All used bits for index 1. */
-#define CAP_ALL1 CAPRIGHT(1, 0x00000000001FFFFFULL)
+#define CAP_ALL1 CAPRIGHT(1, 0x00000000007FFFFFULL)
/* Available bits for index 1. */
-#define CAP_UNUSED1_22 CAPRIGHT(1, 0x0000000000200000ULL)
+#define CAP_UNUSED1_22 CAPRIGHT(1, 0x0000000000800000ULL)
/* ... */
#define CAP_UNUSED1_57 CAPRIGHT(1, 0x0100000000000000ULL)
diff --git a/sys/sys/efi.h b/sys/sys/efi.h
index 95a433a950db..89c8b15519de 100644
--- a/sys/sys/efi.h
+++ b/sys/sys/efi.h
@@ -42,6 +42,8 @@
{0xb122a263,0x3661,0x4f68,{0x99,0x29,0x78,0xf8,0xb0,0xd6,0x21,0x80}}
#define EFI_PROPERTIES_TABLE \
{0x880aaca3,0x4adc,0x4a04,{0x90,0x79,0xb7,0x47,0x34,0x08,0x25,0xe5}}
+#define EFI_MEMORY_ATTRIBUTES_TABLE \
+ {0xdcfa911d,0x26eb,0x469f,{0xa2,0x20,0x38,0xb7,0xdc,0x46,0x12,0x20}}
#define LINUX_EFI_MEMRESERVE_TABLE \
{0x888eb0c6,0x8ede,0x4ff5,{0xa8,0xf0,0x9a,0xee,0x5c,0xb9,0x77,0xc2}}
@@ -166,6 +168,22 @@ struct efi_prop_table {
uint64_t memory_protection_attribute;
};
+struct efi_memory_descriptor {
+ uint32_t type;
+ caddr_t phy_addr;
+ caddr_t virt_addr;
+ uint64_t pages;
+ uint64_t attrs;
+};
+
+struct efi_memory_attribute_table {
+ uint32_t version;
+ uint32_t num_ents;
+ uint32_t descriptor_size;
+ uint32_t flags;
+ struct efi_memory_descriptor tables[];
+};
+
#ifdef _KERNEL
#ifdef EFIABI_ATTR
diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h
index 87460aae2dd4..efda38279848 100644
--- a/sys/sys/elf_common.h
+++ b/sys/sys/elf_common.h
@@ -306,7 +306,7 @@ typedef struct {
and MPRC of Peking University */
#define EM_AARCH64 183 /* AArch64 (64-bit ARM) */
#define EM_RISCV 243 /* RISC-V */
-#define EM_LOONGARCH 258 /* Loongson LoongArch */
+#define EM_LOONGARCH 258 /* Loongson LoongArch */
/* Non-standard or deprecated. */
#define EM_486 6 /* Intel i486. */
@@ -392,15 +392,15 @@ typedef struct {
*/
/* LoongArch Base ABI Modifiers */
-#define EF_LOONGARCH_ABI_SOFT_FLOAT 0x00000001
-#define EF_LOONGARCH_ABI_SINGLE_FLOAT 0x00000002
-#define EF_LOONGARCH_ABI_DOUBLE_FLOAT 0x00000003
-#define EF_LOONGARCH_ABI_MODIFIER_MASK 0x00000007
+#define EF_LOONGARCH_ABI_SOFT_FLOAT 0x00000001
+#define EF_LOONGARCH_ABI_SINGLE_FLOAT 0x00000002
+#define EF_LOONGARCH_ABI_DOUBLE_FLOAT 0x00000003
+#define EF_LOONGARCH_ABI_MODIFIER_MASK 0x00000007
/* LoongArch Object file ABI versions */
-#define EF_LOONGARCH_OBJABI_V0 0x00000000
-#define EF_LOONGARCH_OBJABI_V1 0x00000040
-#define EF_LOONGARCH_OBJABI_MASK 0x000000C0
+#define EF_LOONGARCH_OBJABI_V0 0x00000000
+#define EF_LOONGARCH_OBJABI_V1 0x00000040
+#define EF_LOONGARCH_OBJABI_MASK 0x000000C0
#define EF_SPARC_EXT_MASK 0x00ffff00
#define EF_SPARC_32PLUS 0x00000100
@@ -470,12 +470,12 @@ typedef struct {
#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
#define SHT_X86_64_UNWIND 0x70000001 /* unwind information */
-#define SHT_AMD64_UNWIND SHT_X86_64_UNWIND
+#define SHT_AMD64_UNWIND SHT_X86_64_UNWIND
#define SHT_ARM_EXIDX 0x70000001 /* Exception index table. */
-#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking
+#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking
pre-emption map. */
-#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility
+#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility
attributes. */
#define SHT_ARM_DEBUGOVERLAY 0x70000004 /* See DBGOVL for details. */
#define SHT_ARM_OVERLAYSECTION 0x70000005 /* See DBGOVL for details. */
@@ -791,7 +791,7 @@ typedef struct {
#define DF_1_NODELETE 0x00000008 /* Set the RTLD_NODELETE for object */
#define DF_1_LOADFLTR 0x00000010 /* Immediate loading of filtees */
#define DF_1_INITFIRST 0x00000020 /* Initialize DSO first at runtime */
-#define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */
+#define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */
#define DF_1_ORIGIN 0x00000080 /* Process $ORIGIN */
#define DF_1_INTERPOSE 0x00000400 /* Interpose all objects but main */
#define DF_1_NODEFLIB 0x00000800 /* Do not search default paths */
@@ -908,7 +908,7 @@ typedef struct {
#define STV_ELIMINATE 0x6
/* Architecture specific data - st_other */
-#define STO_AARCH64_VARIANT_PCS 0x80
+#define STO_AARCH64_VARIANT_PCS 0x80
/* Special symbol table indexes. */
#define STN_UNDEF 0 /* Undefined symbol index. */
@@ -1084,11 +1084,11 @@ typedef struct {
#define R_AARCH64_COPY 1024 /* Copy data from shared object */
#define R_AARCH64_GLOB_DAT 1025 /* Set GOT entry to data address */
#define R_AARCH64_JUMP_SLOT 1026 /* Set GOT entry to code address */
-#define R_AARCH64_RELATIVE 1027 /* Add load address of shared object */
+#define R_AARCH64_RELATIVE 1027 /* Add load address of shared object */
#define R_AARCH64_TLS_DTPREL64 1028
#define R_AARCH64_TLS_DTPMOD64 1029
-#define R_AARCH64_TLS_TPREL64 1030
-#define R_AARCH64_TLSDESC 1031 /* Identify the TLS descriptor */
+#define R_AARCH64_TLS_TPREL64 1030
+#define R_AARCH64_TLSDESC 1031 /* Identify the TLS descriptor */
#define R_AARCH64_IRELATIVE 1032
#define R_ARM_NONE 0 /* No relocation. */
@@ -1231,8 +1231,8 @@ typedef struct {
#define R_MIPS_GOT_HI16 22 /* GOT HI 16 bit */
#define R_MIPS_GOT_LO16 23 /* GOT LO 16 bit */
#define R_MIPS_SUB 24
-#define R_MIPS_CALLHI16 30 /* upper 16 bit GOT entry for function */
-#define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */
+#define R_MIPS_CALLHI16 30 /* upper 16 bit GOT entry for function */
+#define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */
#define R_MIPS_JALR 37
#define R_MIPS_TLS_GD 42
#define R_MIPS_COPY 126
@@ -1352,7 +1352,6 @@ typedef struct {
* RISC-V relocation types.
*/
-/* Relocation types used by the dynamic linker. */
#define R_RISCV_NONE 0
#define R_RISCV_32 1
#define R_RISCV_64 2
@@ -1365,8 +1364,7 @@ typedef struct {
#define R_RISCV_TLS_DTPREL64 9
#define R_RISCV_TLS_TPREL32 10
#define R_RISCV_TLS_TPREL64 11
-
-/* Relocation types not used by the dynamic linker. */
+#define R_RISCV_TLSDESC 12
#define R_RISCV_BRANCH 16
#define R_RISCV_JAL 17
#define R_RISCV_CALL 18
@@ -1392,10 +1390,10 @@ typedef struct {
#define R_RISCV_SUB16 38
#define R_RISCV_SUB32 39
#define R_RISCV_SUB64 40
+#define R_RISCV_GOT32_PCREL 41
#define R_RISCV_ALIGN 43
#define R_RISCV_RVC_BRANCH 44
#define R_RISCV_RVC_JUMP 45
-#define R_RISCV_RVC_LUI 46
#define R_RISCV_RELAX 51
#define R_RISCV_SUB6 52
#define R_RISCV_SET6 53
@@ -1404,6 +1402,14 @@ typedef struct {
#define R_RISCV_SET32 56
#define R_RISCV_32_PCREL 57
#define R_RISCV_IRELATIVE 58
+#define R_RISCV_PLT32 59
+#define R_RISCV_SET_ULEB128 60
+#define R_RISCV_SUB_ULEB128 61
+#define R_RISCV_TLSDESC_HI20 62
+#define R_RISCV_TLSDESC_LOAD_LO12 63
+#define R_RISCV_TLSDESC_ADD_LO12 64
+#define R_RISCV_TLSDESC_CALL 65
+#define R_RISCV_VENDOR 191
/*
* Loongson LoongArch relocation types.
@@ -1413,101 +1419,101 @@ typedef struct {
*/
/* Relocation types used by the dynamic linker */
-#define R_LARCH_NONE 0
-#define R_LARCH_32 1
-#define R_LARCH_64 2
-#define R_LARCH_RELATIVE 3
-#define R_LARCH_COPY 4
-#define R_LARCH_JUMP_SLOT 5
-#define R_LARCH_TLS_DTPMOD32 6
-#define R_LARCH_TLS_DTPMOD64 7
-#define R_LARCH_TLS_DTPREL32 8
-#define R_LARCH_TLS_DTPREL64 9
-#define R_LARCH_TLS_TPREL32 10
-#define R_LARCH_TLS_TPREL64 11
-#define R_LARCH_IRELATIVE 12
-#define R_LARCH_MARK_LA 20
-#define R_LARCH_MARK_PCREL 21
-#define R_LARCH_SOP_PUSH_PCREL 22
-#define R_LARCH_SOP_PUSH_ABSOLUTE 23
-#define R_LARCH_SOP_PUSH_DUP 24
-#define R_LARCH_SOP_PUSH_GPREL 25
-#define R_LARCH_SOP_PUSH_TLS_TPREL 26
-#define R_LARCH_SOP_PUSH_TLS_GOT 27
-#define R_LARCH_SOP_PUSH_TLS_GD 28
-#define R_LARCH_SOP_PUSH_PLT_PCREL 29
-#define R_LARCH_SOP_ASSERT 30
-#define R_LARCH_SOP_NOT 31
-#define R_LARCH_SOP_SUB 32
-#define R_LARCH_SOP_SL 33
-#define R_LARCH_SOP_SR 34
-#define R_LARCH_SOP_ADD 35
-#define R_LARCH_SOP_AND 36
-#define R_LARCH_SOP_IF_ELSE 37
-#define R_LARCH_SOP_POP_32_S_10_5 38
-#define R_LARCH_SOP_POP_32_U_10_12 39
-#define R_LARCH_SOP_POP_32_S_10_12 40
-#define R_LARCH_SOP_POP_32_S_10_16 41
-#define R_LARCH_SOP_POP_32_S_10_16_S2 42
-#define R_LARCH_SOP_POP_32_S_5_20 43
-#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44
-#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45
-#define R_LARCH_SOP_POP_32_U 46
-#define R_LARCH_ADD8 47
-#define R_LARCH_ADD16 48
-#define R_LARCH_ADD24 49
-#define R_LARCH_ADD32 50
-#define R_LARCH_ADD64 51
-#define R_LARCH_SUB8 52
-#define R_LARCH_SUB16 53
-#define R_LARCH_SUB24 54
-#define R_LARCH_SUB32 55
-#define R_LARCH_SUB64 56
-#define R_LARCH_GNU_VTINHERIT 57
-#define R_LARCH_GNU_VTENTRY 58
+#define R_LARCH_NONE 0
+#define R_LARCH_32 1
+#define R_LARCH_64 2
+#define R_LARCH_RELATIVE 3
+#define R_LARCH_COPY 4
+#define R_LARCH_JUMP_SLOT 5
+#define R_LARCH_TLS_DTPMOD32 6
+#define R_LARCH_TLS_DTPMOD64 7
+#define R_LARCH_TLS_DTPREL32 8
+#define R_LARCH_TLS_DTPREL64 9
+#define R_LARCH_TLS_TPREL32 10
+#define R_LARCH_TLS_TPREL64 11
+#define R_LARCH_IRELATIVE 12
+#define R_LARCH_MARK_LA 20
+#define R_LARCH_MARK_PCREL 21
+#define R_LARCH_SOP_PUSH_PCREL 22
+#define R_LARCH_SOP_PUSH_ABSOLUTE 23
+#define R_LARCH_SOP_PUSH_DUP 24
+#define R_LARCH_SOP_PUSH_GPREL 25
+#define R_LARCH_SOP_PUSH_TLS_TPREL 26
+#define R_LARCH_SOP_PUSH_TLS_GOT 27
+#define R_LARCH_SOP_PUSH_TLS_GD 28
+#define R_LARCH_SOP_PUSH_PLT_PCREL 29
+#define R_LARCH_SOP_ASSERT 30
+#define R_LARCH_SOP_NOT 31
+#define R_LARCH_SOP_SUB 32
+#define R_LARCH_SOP_SL 33
+#define R_LARCH_SOP_SR 34
+#define R_LARCH_SOP_ADD 35
+#define R_LARCH_SOP_AND 36
+#define R_LARCH_SOP_IF_ELSE 37
+#define R_LARCH_SOP_POP_32_S_10_5 38
+#define R_LARCH_SOP_POP_32_U_10_12 39
+#define R_LARCH_SOP_POP_32_S_10_12 40
+#define R_LARCH_SOP_POP_32_S_10_16 41
+#define R_LARCH_SOP_POP_32_S_10_16_S2 42
+#define R_LARCH_SOP_POP_32_S_5_20 43
+#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44
+#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45
+#define R_LARCH_SOP_POP_32_U 46
+#define R_LARCH_ADD8 47
+#define R_LARCH_ADD16 48
+#define R_LARCH_ADD24 49
+#define R_LARCH_ADD32 50
+#define R_LARCH_ADD64 51
+#define R_LARCH_SUB8 52
+#define R_LARCH_SUB16 53
+#define R_LARCH_SUB24 54
+#define R_LARCH_SUB32 55
+#define R_LARCH_SUB64 56
+#define R_LARCH_GNU_VTINHERIT 57
+#define R_LARCH_GNU_VTENTRY 58
/*
* Relocs whose processing do not require a stack machine.
*
* Spec addition: https://github.com/loongson/LoongArch-Documentation/pull/57
*/
-#define R_LARCH_B16 64
-#define R_LARCH_B21 65
-#define R_LARCH_B26 66
-#define R_LARCH_ABS_HI20 67
-#define R_LARCH_ABS_LO12 68
-#define R_LARCH_ABS64_LO20 69
-#define R_LARCH_ABS64_HI12 70
-#define R_LARCH_PCALA_HI20 71
-#define R_LARCH_PCALA_LO12 72
-#define R_LARCH_PCALA64_LO20 73
-#define R_LARCH_PCALA64_HI12 74
-#define R_LARCH_GOT_PC_HI20 75
-#define R_LARCH_GOT_PC_LO12 76
-#define R_LARCH_GOT64_PC_LO20 77
-#define R_LARCH_GOT64_PC_HI12 78
-#define R_LARCH_GOT_HI20 79
-#define R_LARCH_GOT_LO12 80
-#define R_LARCH_GOT64_LO20 81
-#define R_LARCH_GOT64_HI12 82
-#define R_LARCH_TLS_LE_HI20 83
-#define R_LARCH_TLS_LE_LO12 84
-#define R_LARCH_TLS_LE64_LO20 85
-#define R_LARCH_TLS_LE64_HI12 86
-#define R_LARCH_TLS_IE_PC_HI20 87
-#define R_LARCH_TLS_IE_PC_LO12 88
-#define R_LARCH_TLS_IE64_PC_LO20 89
-#define R_LARCH_TLS_IE64_PC_HI12 90
-#define R_LARCH_TLS_IE_HI20 91
-#define R_LARCH_TLS_IE_LO12 92
-#define R_LARCH_TLS_IE64_LO20 93
-#define R_LARCH_TLS_IE64_HI12 94
-#define R_LARCH_TLS_LD_PC_HI20 95
-#define R_LARCH_TLS_LD_HI20 96
-#define R_LARCH_TLS_GD_PC_HI20 97
-#define R_LARCH_TLS_GD_HI20 98
-#define R_LARCH_32_PCREL 99
-#define R_LARCH_RELAX 100
+#define R_LARCH_B16 64
+#define R_LARCH_B21 65
+#define R_LARCH_B26 66
+#define R_LARCH_ABS_HI20 67
+#define R_LARCH_ABS_LO12 68
+#define R_LARCH_ABS64_LO20 69
+#define R_LARCH_ABS64_HI12 70
+#define R_LARCH_PCALA_HI20 71
+#define R_LARCH_PCALA_LO12 72
+#define R_LARCH_PCALA64_LO20 73
+#define R_LARCH_PCALA64_HI12 74
+#define R_LARCH_GOT_PC_HI20 75
+#define R_LARCH_GOT_PC_LO12 76
+#define R_LARCH_GOT64_PC_LO20 77
+#define R_LARCH_GOT64_PC_HI12 78
+#define R_LARCH_GOT_HI20 79
+#define R_LARCH_GOT_LO12 80
+#define R_LARCH_GOT64_LO20 81
+#define R_LARCH_GOT64_HI12 82
+#define R_LARCH_TLS_LE_HI20 83
+#define R_LARCH_TLS_LE_LO12 84
+#define R_LARCH_TLS_LE64_LO20 85
+#define R_LARCH_TLS_LE64_HI12 86
+#define R_LARCH_TLS_IE_PC_HI20 87
+#define R_LARCH_TLS_IE_PC_LO12 88
+#define R_LARCH_TLS_IE64_PC_LO20 89
+#define R_LARCH_TLS_IE64_PC_HI12 90
+#define R_LARCH_TLS_IE_HI20 91
+#define R_LARCH_TLS_IE_LO12 92
+#define R_LARCH_TLS_IE64_LO20 93
+#define R_LARCH_TLS_IE64_HI12 94
+#define R_LARCH_TLS_LD_PC_HI20 95
+#define R_LARCH_TLS_LD_HI20 96
+#define R_LARCH_TLS_GD_PC_HI20 97
+#define R_LARCH_TLS_GD_HI20 98
+#define R_LARCH_32_PCREL 99
+#define R_LARCH_RELAX 100
/*
* Relocs added in ELF for the LoongArch™ Architecture v20230519, part of the
@@ -1520,13 +1526,13 @@ typedef struct {
* in psABI v2.20 because they were proved not necessary to be exposed outside
* of the linker.
*/
-#define R_LARCH_ALIGN 102
-#define R_LARCH_PCREL20_S2 103
-#define R_LARCH_ADD6 105
-#define R_LARCH_SUB6 106
-#define R_LARCH_ADD_ULEB128 107
-#define R_LARCH_SUB_ULEB128 108
-#define R_LARCH_64_PCREL 109
+#define R_LARCH_ALIGN 102
+#define R_LARCH_PCREL20_S2 103
+#define R_LARCH_ADD6 105
+#define R_LARCH_SUB6 106
+#define R_LARCH_ADD_ULEB128 107
+#define R_LARCH_SUB_ULEB128 108
+#define R_LARCH_64_PCREL 109
/*
* Relocs added in ELF for the LoongArch™ Architecture v20231102, part of the
@@ -1534,7 +1540,7 @@ typedef struct {
*
* Spec addition: https://github.com/loongson/la-abi-specs/pull/4
*/
-#define R_LARCH_CALL36 110
+#define R_LARCH_CALL36 110
/*
* Relocs added in ELF for the LoongArch™ Architecture v20231219, part of the
@@ -1542,24 +1548,24 @@ typedef struct {
*
* Spec addition: https://github.com/loongson/la-abi-specs/pull/5
*/
-#define R_LARCH_TLS_DESC32 13
-#define R_LARCH_TLS_DESC64 14
-#define R_LARCH_TLS_DESC_PC_HI20 111
-#define R_LARCH_TLS_DESC_PC_LO12 112
-#define R_LARCH_TLS_DESC64_PC_LO20 113
-#define R_LARCH_TLS_DESC64_PC_HI12 114
-#define R_LARCH_TLS_DESC_HI20 115
-#define R_LARCH_TLS_DESC_LO12 116
-#define R_LARCH_TLS_DESC64_LO20 117
-#define R_LARCH_TLS_DESC64_HI12 118
-#define R_LARCH_TLS_DESC_LD 119
-#define R_LARCH_TLS_DESC_CALL 120
-#define R_LARCH_TLS_LE_HI20_R 121
-#define R_LARCH_TLS_LE_ADD_R 122
-#define R_LARCH_TLS_LE_LO12_R 123
-#define R_LARCH_TLS_LD_PCREL20_S2 124
-#define R_LARCH_TLS_GD_PCREL20_S2 125
-#define R_LARCH_TLS_DESC_PCREL20_S2 126
+#define R_LARCH_TLS_DESC32 13
+#define R_LARCH_TLS_DESC64 14
+#define R_LARCH_TLS_DESC_PC_HI20 111
+#define R_LARCH_TLS_DESC_PC_LO12 112
+#define R_LARCH_TLS_DESC64_PC_LO20 113
+#define R_LARCH_TLS_DESC64_PC_HI12 114
+#define R_LARCH_TLS_DESC_HI20 115
+#define R_LARCH_TLS_DESC_LO12 116
+#define R_LARCH_TLS_DESC64_LO20 117
+#define R_LARCH_TLS_DESC64_HI12 118
+#define R_LARCH_TLS_DESC_LD 119
+#define R_LARCH_TLS_DESC_CALL 120
+#define R_LARCH_TLS_LE_HI20_R 121
+#define R_LARCH_TLS_LE_ADD_R 122
+#define R_LARCH_TLS_LE_LO12_R 123
+#define R_LARCH_TLS_LD_PCREL20_S2 124
+#define R_LARCH_TLS_GD_PCREL20_S2 125
+#define R_LARCH_TLS_DESC_PCREL20_S2 126
#define R_SPARC_NONE 0
#define R_SPARC_8 1
diff --git a/sys/sys/exterr_cat.h b/sys/sys/exterr_cat.h
index d770c274d7b7..cab94ac511a5 100644
--- a/sys/sys/exterr_cat.h
+++ b/sys/sys/exterr_cat.h
@@ -16,6 +16,8 @@
#define EXTERR_KTRACE 3 /* To allow inclusion of this
file into kern_ktrace.c */
#define EXTERR_CAT_FUSE 4
+#define EXTERR_CAT_INOTIFY 5
+#define EXTERR_CAT_GENIO 6
#endif
diff --git a/sys/sys/exterrvar.h b/sys/sys/exterrvar.h
index 15557c614f88..7bf1d264ff5e 100644
--- a/sys/sys/exterrvar.h
+++ b/sys/sys/exterrvar.h
@@ -21,6 +21,7 @@
#define EXTERRCTL_ENABLE 1
#define EXTERRCTL_DISABLE 2
+#define EXTERRCTL_UD 3
#define EXTERRCTLF_FORCE 0x00000001
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
index dd9fccf5cf38..18d3928e91c7 100644
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -144,6 +144,10 @@ typedef __pid_t pid_t;
#define O_XATTR O_NAMEDATTR /* Solaris compatibility */
#endif
+#if __POSIX_VISIBLE >= 202405
+#define O_CLOFORK 0x08000000
+#endif
+
/*
* !!! DANGER !!!
*
@@ -280,6 +284,16 @@ typedef __pid_t pid_t;
#define F_GET_SEALS 20
#define F_ISUNIONSTACK 21 /* Kludge for libc, don't use it. */
#define F_KINFO 22 /* Return kinfo_file for this fd */
+#endif /* __BSD_VISIBLE */
+
+#if __POSIX_VISIBLE >= 202405
+#define F_DUPFD_CLOFORK 23 /* Like F_DUPFD, but FD_CLOFORK is set */
+#endif
+
+#if __BSD_VISIBLE
+#define F_DUP3FD 24 /* Used with dup3() */
+
+#define F_DUP3FD_SHIFT 16 /* Shift used for F_DUP3FD */
/* Seals (F_ADD_SEALS, F_GET_SEALS). */
#define F_SEAL_SEAL 0x0001 /* Prevent adding sealings */
@@ -292,6 +306,9 @@ typedef __pid_t pid_t;
#define FD_CLOEXEC 1 /* close-on-exec flag */
#define FD_RESOLVE_BENEATH 2 /* all lookups relative to fd have
O_RESOLVE_BENEATH semantics */
+#if __POSIX_VISIBLE >= 202405
+#define FD_CLOFORK 4 /* close-on-fork flag */
+#endif
/* record locking flags (F_GETLK, F_SETLK, F_SETLKW) */
#define F_RDLCK 1 /* shared or read lock */
diff --git a/sys/sys/file.h b/sys/sys/file.h
index 284d523147b6..63313926c4f0 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -71,6 +71,7 @@ struct nameidata;
#define DTYPE_PROCDESC 12 /* process descriptor */
#define DTYPE_EVENTFD 13 /* eventfd */
#define DTYPE_TIMERFD 14 /* timerfd */
+#define DTYPE_INOTIFY 15 /* inotify descriptor */
#ifdef _KERNEL
diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h
index 55969b2ff4b3..0a388c90de26 100644
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -149,6 +149,7 @@ struct filedesc_to_leader {
*/
#define UF_EXCLOSE 0x01 /* auto-close on exec */
#define UF_RESOLVE_BENEATH 0x02 /* lookups must be beneath this dir */
+#define UF_FOCLOSE 0x04 /* auto-close on fork */
#ifdef _KERNEL
@@ -221,6 +222,7 @@ enum {
/* Flags for kern_dup(). */
#define FDDUP_FLAG_CLOEXEC 0x1 /* Atomically set UF_EXCLOSE. */
+#define FDDUP_FLAG_CLOFORK 0x2 /* Atomically set UF_FOCLOSE. */
/* For backward compatibility. */
#define falloc(td, resultfp, resultfd, flags) \
diff --git a/sys/sys/inotify.h b/sys/sys/inotify.h
new file mode 100644
index 000000000000..d1f23d5898bb
--- /dev/null
+++ b/sys/sys/inotify.h
@@ -0,0 +1,158 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Klara, Inc.
+ */
+
+#ifndef _INOTIFY_H_
+#define _INOTIFY_H_
+
+#include <sys/_types.h>
+
+/* Flags for inotify_init1(). */
+#define IN_NONBLOCK 0x00000004 /* O_NONBLOCK */
+#define IN_CLOEXEC 0x00100000 /* O_CLOEXEC */
+
+struct inotify_event {
+ int wd;
+ __uint32_t mask;
+ __uint32_t cookie;
+ __uint32_t len;
+ char name[0];
+};
+
+/* Events, set in the mask field. */
+#define IN_ACCESS 0x00000001
+#define IN_MODIFY 0x00000002
+#define IN_ATTRIB 0x00000004
+#define IN_CLOSE_WRITE 0x00000008
+#define IN_CLOSE_NOWRITE 0x00000010
+#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
+#define IN_OPEN 0x00000020
+#define IN_MOVED_FROM 0x00000040
+#define IN_MOVED_TO 0x00000080
+#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO)
+#define IN_CREATE 0x00000100
+#define IN_DELETE 0x00000200
+#define IN_DELETE_SELF 0x00000400
+#define IN_MOVE_SELF 0x00000800
+#define IN_ALL_EVENTS 0x00000fff
+
+/* Events report only for entries in a watched dir, not the dir itself. */
+#define _IN_DIR_EVENTS (IN_CLOSE_WRITE | IN_DELETE | IN_MODIFY | \
+ IN_MOVED_FROM | IN_MOVED_TO)
+
+#ifdef _KERNEL
+/*
+ * An unlink that's done as part of a rename only records IN_DELETE if the
+ * unlinked vnode itself is watched, and not when the containing directory is
+ * watched.
+ */
+#define _IN_MOVE_DELETE 0x40000000
+/*
+ * Inode link count changes only trigger IN_ATTRIB events if the inode itself is
+ * watched, and not when the containing directory is watched.
+ */
+#define _IN_ATTRIB_LINKCOUNT 0x80000000
+#endif
+
+/* Flags, set in the mask field. */
+#define IN_ONLYDIR 0x01000000
+#define IN_DONT_FOLLOW 0x02000000
+#define IN_EXCL_UNLINK 0x04000000
+#define IN_MASK_CREATE 0x10000000
+#define IN_MASK_ADD 0x20000000
+#define IN_ONESHOT 0x80000000
+#define _IN_ALL_FLAGS (IN_ONLYDIR | IN_DONT_FOLLOW | \
+ IN_EXCL_UNLINK | IN_MASK_CREATE | \
+ IN_MASK_ADD | IN_ONESHOT)
+
+/* Flags returned by the kernel. */
+#define IN_UNMOUNT 0x00002000
+#define IN_Q_OVERFLOW 0x00004000
+#define IN_IGNORED 0x00008000
+#define IN_ISDIR 0x40000000
+#define _IN_ALL_RETFLAGS (IN_Q_OVERFLOW | IN_UNMOUNT | IN_IGNORED | \
+ IN_ISDIR)
+
+#define _IN_ALIGN _Alignof(struct inotify_event)
+#define _IN_NAMESIZE(namelen) \
+ ((namelen) == 0 ? 0 : __align_up((namelen) + 1, _IN_ALIGN))
+
+#ifdef _KERNEL
+struct componentname;
+struct file;
+struct inotify_softc;
+struct thread;
+struct vnode;
+
+int inotify_create_file(struct thread *, struct file *, int, int *);
+void inotify_log(struct vnode *, const char *, size_t, int, __uint32_t);
+
+int kern_inotify_rm_watch(int, uint32_t, struct thread *);
+int kern_inotify_add_watch(int, int, const char *, uint32_t,
+ struct thread *);
+
+void vn_inotify(struct vnode *, struct vnode *, struct componentname *, int,
+ uint32_t);
+int vn_inotify_add_watch(struct vnode *, struct inotify_softc *,
+ __uint32_t, __uint32_t *, struct thread *);
+void vn_inotify_revoke(struct vnode *);
+
+/* Log an inotify event. */
+#define INOTIFY(vp, ev) do { \
+ if (__predict_false((vn_irflag_read(vp) & (VIRF_INOTIFY | \
+ VIRF_INOTIFY_PARENT)) != 0)) \
+ VOP_INOTIFY((vp), NULL, NULL, (ev), 0); \
+} while (0)
+
+/* Log an inotify event using a specific name for the vnode. */
+#define INOTIFY_NAME_LOCK(vp, dvp, cnp, ev, lock) do { \
+ if (__predict_false((vn_irflag_read(vp) & VIRF_INOTIFY) != 0 || \
+ (vn_irflag_read(dvp) & VIRF_INOTIFY) != 0)) { \
+ if (lock) \
+ vn_lock((vp), LK_SHARED | LK_RETRY); \
+ VOP_INOTIFY((vp), (dvp), (cnp), (ev), 0); \
+ if (lock) \
+ VOP_UNLOCK(vp); \
+ } \
+} while (0)
+#define INOTIFY_NAME(vp, dvp, cnp, ev) \
+ INOTIFY_NAME_LOCK((vp), (dvp), (cnp), (ev), false)
+
+extern __uint32_t inotify_rename_cookie;
+
+#define INOTIFY_MOVE(vp, fdvp, fcnp, tvp, tdvp, tcnp) do { \
+ if (__predict_false((vn_irflag_read(fdvp) & VIRF_INOTIFY) != 0 || \
+ (vn_irflag_read(tdvp) & VIRF_INOTIFY) != 0 || \
+ (vn_irflag_read(vp) & VIRF_INOTIFY) != 0)) { \
+ __uint32_t cookie; \
+ \
+ cookie = atomic_fetchadd_32(&inotify_rename_cookie, 1); \
+ VOP_INOTIFY((vp), (fdvp), (fcnp), IN_MOVED_FROM, cookie); \
+ VOP_INOTIFY((vp), (tdvp), (tcnp), IN_MOVED_TO, cookie); \
+ } \
+ if ((tvp) != NULL) \
+ INOTIFY_NAME_LOCK((tvp), (tdvp), (tcnp), \
+ _IN_MOVE_DELETE, true); \
+} while (0)
+
+#define INOTIFY_REVOKE(vp) do { \
+ if (__predict_false((vn_irflag_read(vp) & VIRF_INOTIFY) != 0)) \
+ vn_inotify_revoke((vp)); \
+} while (0)
+
+#else
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int inotify_init(void);
+int inotify_init1(int flags);
+int inotify_add_watch(int fd, const char *pathname, __uint32_t mask);
+int inotify_add_watch_at(int fd, int dfd, const char *pathname,
+ __uint32_t mask);
+int inotify_rm_watch(int fd, int wd);
+__END_DECLS
+#endif /* !_KERNEL */
+
+#endif /* !_INOTIFY_H_ */
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index a6f858e02395..f6480b173a5c 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -267,6 +267,7 @@ struct mount {
int mnt_lazyvnodelistsize; /* (l) # of lazy vnodes */
int mnt_upper_pending; /* (i) # of pending ops on mnt_uppers */
struct lock mnt_explock; /* vfs_export walkers lock */
+ struct lock mnt_renamelock; /* renames and O_RESOLVE_BENEATH */
TAILQ_HEAD(, mount_upper_node) mnt_uppers; /* (i) upper mounts over us */
TAILQ_HEAD(, mount_upper_node) mnt_notify; /* (i) upper mounts for notification */
STAILQ_ENTRY(mount) mnt_taskqueue_link; /* (d) our place in deferred unmount list */
diff --git a/sys/sys/namei.h b/sys/sys/namei.h
index 5c245235ace5..6008d83f729d 100644
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -108,7 +108,12 @@ struct nameidata {
* through the VOP interface.
*/
struct componentname ni_cnd;
+
+ /* Serving RBENEATH. */
struct nameicap_tracker_head ni_cap_tracker;
+ struct vnode *ni_rbeneath_dpp;
+ struct mount *ni_nctrack_mnt;
+
/*
* Private helper data for UFS, must be at the end. See
* NDINIT_PREFILL().
@@ -235,6 +240,10 @@ int cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status,
panic("namei data not inited"); \
if (((arg)->ni_debugflags & NAMEI_DBG_HADSTARTDIR) != 0) \
panic("NDREINIT on namei data with NAMEI_DBG_HADSTARTDIR"); \
+ if ((arg)->ni_nctrack_mnt != NULL) \
+ panic("NDREINIT on namei data with leaked ni_nctrack_mnt"); \
+ if (!TAILQ_EMPTY(&(arg)->ni_cap_tracker)) \
+ panic("NDREINIT on namei data with leaked ni_cap_tracker"); \
(arg)->ni_debugflags = NAMEI_DBG_INITED; \
}
#else
@@ -259,6 +268,9 @@ do { \
_ndp->ni_resflags = 0; \
filecaps_init(&_ndp->ni_filecaps); \
_ndp->ni_rightsneeded = _rightsp; \
+ _ndp->ni_rbeneath_dpp = NULL; \
+ _ndp->ni_nctrack_mnt = NULL; \
+ TAILQ_INIT(&_ndp->ni_cap_tracker); \
} while (0)
#define NDREINIT(ndp) do { \
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 57eb8ebcf12c..f941f021a423 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -74,7 +74,7 @@
* cannot include sys/param.h and should only be updated here.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1500050
+#define __FreeBSD_version 1500054
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/sys/random.h b/sys/sys/random.h
index 254ba9451d0a..5abf762cd200 100644
--- a/sys/sys/random.h
+++ b/sys/sys/random.h
@@ -85,7 +85,8 @@ enum random_entropy_source {
RANDOM_FS_ATIME,
RANDOM_UMA, /* Special!! UMA/SLAB Allocator */
RANDOM_CALLOUT,
- RANDOM_ENVIRONMENTAL_END = RANDOM_CALLOUT,
+ RANDOM_RANDOMDEV,
+ RANDOM_ENVIRONMENTAL_END = RANDOM_RANDOMDEV,
/* Fast hardware random-number sources from here on. */
RANDOM_PURE_START,
RANDOM_PURE_OCTEON = RANDOM_PURE_START,
diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h
index b15dace8cfa0..61411890c85b 100644
--- a/sys/sys/resourcevar.h
+++ b/sys/sys/resourcevar.h
@@ -122,6 +122,8 @@ struct uidinfo {
long ui_kqcnt; /* (b) number of kqueues */
long ui_umtxcnt; /* (b) number of shared umtxs */
long ui_pipecnt; /* (b) consumption of pipe buffers */
+ long ui_inotifycnt; /* (b) number of inotify descriptors */
+ long ui_inotifywatchcnt; /* (b) number of inotify watches */
uid_t ui_uid; /* (a) uid */
u_int ui_ref; /* (b) reference count */
#ifdef RACCT
@@ -144,6 +146,8 @@ int chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to,
int chgptscnt(struct uidinfo *uip, int diff, rlim_t maxval);
int chgumtxcnt(struct uidinfo *uip, int diff, rlim_t maxval);
int chgpipecnt(struct uidinfo *uip, int diff, rlim_t max);
+int chginotifycnt(struct uidinfo *uip, int diff, rlim_t maxval);
+int chginotifywatchcnt(struct uidinfo *uip, int diff, rlim_t maxval);
int kern_proc_setrlimit(struct thread *td, struct proc *p, u_int which,
struct rlimit *limp);
struct plimit
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index 5e7c554c34cf..cdd4fa3b4b89 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -111,10 +111,11 @@ typedef __uintptr_t uintptr_t;
*/
#define SOCK_CLOEXEC 0x10000000
#define SOCK_NONBLOCK 0x20000000
+#define SOCK_CLOFORK 0x40000000
#ifdef _KERNEL
/*
* Flags for accept1(), kern_accept4() and solisten_dequeue, in addition
- * to SOCK_CLOEXEC and SOCK_NONBLOCK.
+ * to SOCK_CLOEXEC, SOCK_CLOFORK and SOCK_NONBLOCK.
*/
#define ACCEPT4_INHERIT 0x1
#define ACCEPT4_COMPAT 0x2
@@ -478,6 +479,9 @@ struct msghdr {
#define MSG_MORETOCOME 0x00100000 /* additional data pending */
#define MSG_TLSAPPDATA 0x00200000 /* do not soreceive() alert rec. (TLS) */
#endif
+#if __BSD_VISIBLE
+#define MSG_CMSG_CLOFORK 0x00400000 /* make received fds close-on-fork */
+#endif
/*
* Header for ancillary data objects in msg_control buffer.
diff --git a/sys/sys/specialfd.h b/sys/sys/specialfd.h
index dc4d88ce689f..0b79c841d149 100644
--- a/sys/sys/specialfd.h
+++ b/sys/sys/specialfd.h
@@ -30,6 +30,7 @@
enum specialfd_type {
SPECIALFD_EVENTFD = 1,
+ SPECIALFD_INOTIFY = 2,
};
struct specialfd_eventfd {
@@ -37,4 +38,8 @@ struct specialfd_eventfd {
int flags;
};
+struct specialfd_inotify {
+ int flags;
+};
+
#endif /* !_SYS_SPECIALFD_H_ */
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index 68406a2dfc29..eec923d0b82e 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -529,4 +529,6 @@
#define SYS_fchroot 590
#define SYS_setcred 591
#define SYS_exterrctl 592
-#define SYS_MAXSYSCALL 593
+#define SYS_inotify_add_watch_at 593
+#define SYS_inotify_rm_watch 594
+#define SYS_MAXSYSCALL 595
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
index 9a90a63f35a3..547242a73277 100644
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -434,4 +434,6 @@ MIASM = \
getrlimitusage.o \
fchroot.o \
setcred.o \
- exterrctl.o
+ exterrctl.o \
+ inotify_add_watch_at.o \
+ inotify_rm_watch.o
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index fe6dd9e14fb4..fd183ffbc7a4 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -257,6 +257,7 @@ int kern_munlock(struct thread *td, uintptr_t addr, size_t size);
int kern_munmap(struct thread *td, uintptr_t addr, size_t size);
int kern_nanosleep(struct thread *td, struct timespec *rqt,
struct timespec *rmt);
+int kern_nosys(struct thread *td, int dummy);
int kern_ntp_adjtime(struct thread *td, struct timex *ntv, int *retvalp);
int kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap,
long *ploff);
diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h
index 6314b03142e7..4ddfc8516053 100644
--- a/sys/sys/sysent.h
+++ b/sys/sys/sysent.h
@@ -79,11 +79,10 @@ struct sysent { /* system call table */
*/
#define SYF_CAPENABLED 0x00000001
-#define SY_THR_FLAGMASK 0x7
-#define SY_THR_STATIC 0x1
-#define SY_THR_DRAINING 0x2
-#define SY_THR_ABSENT 0x4
-#define SY_THR_INCR 0x8
+#define SY_THR_STATIC 0x01
+#define SY_THR_DRAINING 0x02
+#define SY_THR_ABSENT 0x04
+#define SY_THR_INCR 0x08
#ifdef KLD_MODULE
#define SY_THR_STATIC_KLD 0
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
index 94da81c84d25..94b5a0a7a95e 100644
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1891,6 +1891,16 @@ struct exterrctl_args {
char flags_l_[PADL_(u_int)]; u_int flags; char flags_r_[PADR_(u_int)];
char ptr_l_[PADL_(void *)]; void * ptr; char ptr_r_[PADR_(void *)];
};
+struct inotify_add_watch_at_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char dfd_l_[PADL_(int)]; int dfd; char dfd_r_[PADR_(int)];
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+ char mask_l_[PADL_(uint32_t)]; uint32_t mask; char mask_r_[PADR_(uint32_t)];
+};
+struct inotify_rm_watch_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char wd_l_[PADL_(int)]; int wd; char wd_r_[PADR_(int)];
+};
int sys_exit(struct thread *, struct exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2293,6 +2303,8 @@ int sys_getrlimitusage(struct thread *, struct getrlimitusage_args *);
int sys_fchroot(struct thread *, struct fchroot_args *);
int sys_setcred(struct thread *, struct setcred_args *);
int sys_exterrctl(struct thread *, struct exterrctl_args *);
+int sys_inotify_add_watch_at(struct thread *, struct inotify_add_watch_at_args *);
+int sys_inotify_rm_watch(struct thread *, struct inotify_rm_watch_args *);
#ifdef COMPAT_43
@@ -3275,6 +3287,8 @@ int freebsd13_swapoff(struct thread *, struct freebsd13_swapoff_args *);
#define SYS_AUE_fchroot AUE_NULL
#define SYS_AUE_setcred AUE_SETCRED
#define SYS_AUE_exterrctl AUE_NULL
+#define SYS_AUE_inotify_add_watch_at AUE_INOTIFY
+#define SYS_AUE_inotify_rm_watch AUE_INOTIFY
#undef PAD_
#undef PADL_
diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h
index f5caea2e3919..c291c1dc2b95 100644
--- a/sys/sys/unistd.h
+++ b/sys/sys/unistd.h
@@ -156,6 +156,7 @@
#define _PC_DEALLOC_PRESENT 65
#define _PC_NAMEDATTR_ENABLED 66
#define _PC_HAS_NAMEDATTR 67
+#define _PC_HAS_HIDDENSYSTEM 68
#endif
/* From OpenSolaris, used by SEEK_DATA/SEEK_HOLE. */
@@ -210,6 +211,7 @@
* close_range() options.
*/
#define CLOSE_RANGE_CLOEXEC (1<<2)
+#define CLOSE_RANGE_CLOFORK (1<<3)
#endif /* __BSD_VISIBLE */
diff --git a/sys/sys/user.h b/sys/sys/user.h
index f94a91ca1238..103236b6ed1b 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -265,6 +265,7 @@ struct user {
#define KF_TYPE_DEV 12
#define KF_TYPE_EVENTFD 13
#define KF_TYPE_TIMERFD 14
+#define KF_TYPE_INOTIFY 15
#define KF_TYPE_UNKNOWN 255
#define KF_VTYPE_VNON 0
@@ -456,6 +457,10 @@ struct kinfo_file {
int32_t kf_kqueue_count;
int32_t kf_kqueue_state;
} kf_kqueue;
+ struct {
+ uint64_t kf_inotify_npending;
+ uint64_t kf_inotify_nbpending;
+ } kf_inotify;
} kf_un;
};
uint16_t kf_status; /* Status flags. */
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index bed20f607339..2c6947103c94 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -86,11 +86,13 @@ enum vgetstate {
* it from v_data. If non-null, this area is freed in getnewvnode().
*/
-struct namecache;
struct cache_fpl;
+struct inotify_watch;
+struct namecache;
struct vpollinfo {
struct mtx vpi_lock; /* lock to protect below */
+ TAILQ_HEAD(, inotify_watch) vpi_inotify; /* list of inotify watchers */
struct selinfo vpi_selinfo; /* identity of poller(s) */
short vpi_events; /* what they are looking for */
short vpi_revents; /* what has happened */
@@ -248,6 +250,9 @@ _Static_assert(sizeof(struct vnode) <= 448, "vnode size crosses 448 bytes");
#define VIRF_CROSSMP 0x0010 /* Cross-mp vnode, no locking */
#define VIRF_NAMEDDIR 0x0020 /* Named attribute directory */
#define VIRF_NAMEDATTR 0x0040 /* Named attribute */
+#define VIRF_INOTIFY 0x0080 /* This vnode is being watched */
+#define VIRF_INOTIFY_PARENT 0x0100 /* A parent of this vnode may be being
+ watched */
#define VI_UNUSED0 0x0001 /* unused */
#define VI_MOUNT 0x0002 /* Mount in progress */
@@ -667,6 +672,7 @@ char *cache_symlink_alloc(size_t size, int flags);
void cache_symlink_free(char *string, size_t size);
int cache_symlink_resolve(struct cache_fpl *fpl, const char *string,
size_t len);
+void cache_vop_inotify(struct vnode *vp, int event, uint32_t cookie);
void cache_vop_rename(struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp,
struct vnode *tvp, struct componentname *fcnp, struct componentname *tcnp);
void cache_vop_rmdir(struct vnode *dvp, struct vnode *vp);
@@ -869,8 +875,10 @@ int vop_stdfsync(struct vop_fsync_args *);
int vop_stdgetwritemount(struct vop_getwritemount_args *);
int vop_stdgetpages(struct vop_getpages_args *);
int vop_stdinactive(struct vop_inactive_args *);
-int vop_stdioctl(struct vop_ioctl_args *);
int vop_stdneed_inactive(struct vop_need_inactive_args *);
+int vop_stdinotify(struct vop_inotify_args *);
+int vop_stdinotify_add_watch(struct vop_inotify_add_watch_args *);
+int vop_stdioctl(struct vop_ioctl_args *);
int vop_stdkqfilter(struct vop_kqfilter_args *);
int vop_stdlock(struct vop_lock1_args *);
int vop_stdunlock(struct vop_unlock_args *);
@@ -910,9 +918,12 @@ int dead_read(struct vop_read_args *ap);
int dead_write(struct vop_write_args *ap);
/* These are called from within the actual VOPS. */
+void vop_allocate_post(void *a, int rc);
+void vop_copy_file_range_post(void *ap, int rc);
void vop_close_post(void *a, int rc);
void vop_create_pre(void *a);
void vop_create_post(void *a, int rc);
+void vop_deallocate_post(void *a, int rc);
void vop_whiteout_pre(void *a);
void vop_whiteout_post(void *a, int rc);
void vop_deleteextattr_pre(void *a);
@@ -1020,9 +1031,12 @@ void vop_rename_fail(struct vop_rename_args *ap);
#define VOP_WRITE_POST(ap, ret) \
noffset = (ap)->a_uio->uio_offset; \
- if (noffset > ooffset && !VN_KNLIST_EMPTY((ap)->a_vp)) { \
- VFS_KNOTE_LOCKED((ap)->a_vp, NOTE_WRITE \
- | (noffset > osize ? NOTE_EXTEND : 0)); \
+ if (noffset > ooffset) { \
+ if (!VN_KNLIST_EMPTY((ap)->a_vp)) { \
+ VFS_KNOTE_LOCKED((ap)->a_vp, NOTE_WRITE | \
+ (noffset > osize ? NOTE_EXTEND : 0)); \
+ } \
+ INOTIFY((ap)->a_vp, IN_MODIFY); \
}
#define VOP_LOCK(vp, flags) VOP_LOCK1(vp, flags, __FILE__, __LINE__)
diff --git a/sys/tools/vnode_if.awk b/sys/tools/vnode_if.awk
index d23c2af9bd9a..e829105197cc 100644
--- a/sys/tools/vnode_if.awk
+++ b/sys/tools/vnode_if.awk
@@ -193,6 +193,7 @@ if (cfile) {
printc(common_head \
"#include <sys/param.h>\n" \
"#include <sys/event.h>\n" \
+ "#include <sys/inotify.h>\n" \
"#include <sys/kernel.h>\n" \
"#include <sys/mount.h>\n" \
"#include <sys/sdt.h>\n" \
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 891e490a7031..75f5fe716c31 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -1012,7 +1012,6 @@ ffs_mountfs(struct vnode *odevvp, struct mount *mp, struct thread *td)
else
ump->um_check_blkno = NULL;
mtx_init(UFS_MTX(ump), "FFS", "FFS Lock", MTX_DEF);
- sx_init(&ump->um_checkpath_lock, "uchpth");
fs->fs_ronly = ronly;
fs->fs_active = NULL;
mp->mnt_data = ump;
@@ -1182,7 +1181,6 @@ out:
}
if (ump != NULL) {
mtx_destroy(UFS_MTX(ump));
- sx_destroy(&ump->um_checkpath_lock);
if (mp->mnt_gjprovider != NULL) {
free(mp->mnt_gjprovider, M_UFSMNT);
mp->mnt_gjprovider = NULL;
@@ -1306,7 +1304,6 @@ ffs_unmount(struct mount *mp, int mntflags)
vrele(ump->um_odevvp);
dev_rel(ump->um_dev);
mtx_destroy(UFS_MTX(ump));
- sx_destroy(&ump->um_checkpath_lock);
if (mp->mnt_gjprovider != NULL) {
free(mp->mnt_gjprovider, M_UFSMNT);
mp->mnt_gjprovider = NULL;
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index eaf37c58756b..3f9c95e934fc 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -1412,7 +1412,6 @@ ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target,
vp = tvp = ITOV(target);
mp = vp->v_mount;
*wait_ino = 0;
- sx_assert(&VFSTOUFS(mp)->um_checkpath_lock, SA_XLOCKED);
if (target->i_number == source_ino)
return (EEXIST);
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 9aea01e70951..53fac4b0665e 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1273,9 +1273,9 @@ ufs_rename(
struct mount *mp;
ino_t ino;
seqc_t fdvp_s, fvp_s, tdvp_s, tvp_s;
- bool checkpath_locked, want_seqc_end;
+ bool want_seqc_end;
- checkpath_locked = want_seqc_end = false;
+ want_seqc_end = false;
endoff = 0;
mp = tdvp->v_mount;
@@ -1427,10 +1427,6 @@ relock:
}
vfs_ref(mp);
MPASS(!want_seqc_end);
- if (checkpath_locked) {
- sx_xunlock(&VFSTOUFS(mp)->um_checkpath_lock);
- checkpath_locked = false;
- }
VOP_UNLOCK(fdvp);
VOP_UNLOCK(fvp);
vref(tdvp);
@@ -1484,8 +1480,6 @@ relock:
if (error)
goto unlockout;
- sx_xlock(&VFSTOUFS(mp)->um_checkpath_lock);
- checkpath_locked = true;
error = ufs_checkpath(ino, fdp->i_number, tdp, tcnp->cn_cred,
&ino);
/*
@@ -1493,8 +1487,6 @@ relock:
* everything else and VGET before restarting.
*/
if (ino) {
- sx_xunlock(&VFSTOUFS(mp)->um_checkpath_lock);
- checkpath_locked = false;
VOP_UNLOCK(fdvp);
VOP_UNLOCK(fvp);
VOP_UNLOCK(tdvp);
@@ -1574,9 +1566,6 @@ relock:
vn_seqc_write_end(fdvp);
want_seqc_end = false;
vfs_ref(mp);
- MPASS(checkpath_locked);
- sx_xunlock(&VFSTOUFS(mp)->um_checkpath_lock);
- checkpath_locked = false;
VOP_UNLOCK(fdvp);
VOP_UNLOCK(fvp);
vref(tdvp);
@@ -1763,9 +1752,6 @@ unlockout:
vn_seqc_write_end(fdvp);
}
- if (checkpath_locked)
- sx_xunlock(&VFSTOUFS(mp)->um_checkpath_lock);
-
vput(fdvp);
vput(fvp);
@@ -2734,6 +2720,9 @@ ufs_pathconf(
case _PC_SYMLINK_MAX:
*ap->a_retval = MAXPATHLEN;
break;
+ case _PC_HAS_HIDDENSYSTEM:
+ *ap->a_retval = 1;
+ break;
default:
error = vop_stdpathconf(ap);
diff --git a/sys/ufs/ufs/ufsmount.h b/sys/ufs/ufs/ufsmount.h
index 5c7fa11dae6a..d33b01e4425e 100644
--- a/sys/ufs/ufs/ufsmount.h
+++ b/sys/ufs/ufs/ufsmount.h
@@ -97,8 +97,6 @@ struct ufsmount {
uint64_t um_maxsymlinklen; /* (c) max size of short
symlink */
struct mtx um_lock; /* (c) Protects ufsmount & fs */
- struct sx um_checkpath_lock; /* (c) Protects ufs_checkpath()
- result */
struct mount_softdeps *um_softdep; /* (c) softdep mgmt structure */
struct vnode *um_quotas[MAXQUOTAS]; /* (q) pointer to quota files */
struct ucred *um_cred[MAXQUOTAS]; /* (q) quota file access cred */
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index 86b75a2d7989..d6bd06226d04 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -384,8 +384,8 @@ swap_release_by_cred(vm_ooffset_t decr, struct ucred *cred)
#endif
}
-static int swap_pager_full = 2; /* swap space exhaustion (task killing) */
-static int swap_pager_almost_full = 1; /* swap space exhaustion (w/hysteresis)*/
+static bool swap_pager_full = true; /* swap space exhaustion (task killing) */
+static bool swap_pager_almost_full = true; /* swap space exhaustion (w/hysteresis) */
static struct mtx swbuf_mtx; /* to sync nsw_wcount_async */
static int nsw_wcount_async; /* limit async write buffers */
static int nsw_wcount_async_max;/* assigned maximum */
@@ -642,14 +642,14 @@ swp_sizecheck(void)
{
if (swap_pager_avail < nswap_lowat) {
- if (swap_pager_almost_full == 0) {
+ if (!swap_pager_almost_full) {
printf("swap_pager: out of swap space\n");
- swap_pager_almost_full = 1;
+ swap_pager_almost_full = true;
}
} else {
- swap_pager_full = 0;
+ swap_pager_full = false;
if (swap_pager_avail > nswap_hiwat)
- swap_pager_almost_full = 0;
+ swap_pager_almost_full = false;
}
}
@@ -958,11 +958,10 @@ swp_pager_getswapspace(int *io_npages)
swp_sizecheck();
swdevhd = TAILQ_NEXT(sp, sw_list);
} else {
- if (swap_pager_full != 2) {
+ if (!swap_pager_full) {
printf("swp_pager_getswapspace(%d): failed\n",
*io_npages);
- swap_pager_full = 2;
- swap_pager_almost_full = 1;
+ swap_pager_full = swap_pager_almost_full = true;
}
swdevhd = NULL;
}
@@ -2863,10 +2862,8 @@ swapoff_one(struct swdevt *sp, struct ucred *cred, u_int flags)
sp->sw_id = NULL;
TAILQ_REMOVE(&swtailq, sp, sw_list);
nswapdev--;
- if (nswapdev == 0) {
- swap_pager_full = 2;
- swap_pager_almost_full = 1;
- }
+ if (nswapdev == 0)
+ swap_pager_full = swap_pager_almost_full = true;
if (swdevhd == sp)
swdevhd = NULL;
mtx_unlock(&sw_dev_mtx);
diff --git a/sys/vm/vm_domainset.c b/sys/vm/vm_domainset.c
index 7b8bf4c77663..b44bdb96b0d4 100644
--- a/sys/vm/vm_domainset.c
+++ b/sys/vm/vm_domainset.c
@@ -131,8 +131,7 @@ static void
vm_domainset_iter_next(struct vm_domainset_iter *di, int *domain)
{
- KASSERT(di->di_n > 0,
- ("vm_domainset_iter_first: Invalid n %d", di->di_n));
+ KASSERT(di->di_n > 0, ("%s: Invalid n %d", __func__, di->di_n));
switch (di->di_policy) {
case DOMAINSET_POLICY_FIRSTTOUCH:
/*
@@ -149,11 +148,10 @@ vm_domainset_iter_next(struct vm_domainset_iter *di, int *domain)
vm_domainset_iter_prefer(di, domain);
break;
default:
- panic("vm_domainset_iter_first: Unknown policy %d",
- di->di_policy);
+ panic("%s: Unknown policy %d", __func__, di->di_policy);
}
KASSERT(*domain < vm_ndomains,
- ("vm_domainset_iter_next: Invalid domain %d", *domain));
+ ("%s: Invalid domain %d", __func__, *domain));
}
static void
@@ -189,13 +187,11 @@ vm_domainset_iter_first(struct vm_domainset_iter *di, int *domain)
di->di_n = di->di_domain->ds_cnt;
break;
default:
- panic("vm_domainset_iter_first: Unknown policy %d",
- di->di_policy);
+ panic("%s: Unknown policy %d", __func__, di->di_policy);
}
- KASSERT(di->di_n > 0,
- ("vm_domainset_iter_first: Invalid n %d", di->di_n));
+ KASSERT(di->di_n > 0, ("%s: Invalid n %d", __func__, di->di_n));
KASSERT(*domain < vm_ndomains,
- ("vm_domainset_iter_first: Invalid domain %d", *domain));
+ ("%s: Invalid domain %d", __func__, *domain));
}
void
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index 21584abacfa3..3e57e8d4f1d0 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -1441,8 +1441,7 @@ vm_fault_busy_sleep(struct faultstate *fs)
}
vm_object_pip_wakeup(fs->object);
vm_fault_unlock_map(fs);
- if (fs->m != vm_page_lookup(fs->object, fs->pindex) ||
- !vm_page_busy_sleep(fs->m, "vmpfw", 0))
+ if (!vm_page_busy_sleep(fs->m, "vmpfw", 0))
VM_OBJECT_UNLOCK(fs->object);
VM_CNT_INC(v_intrans);
vm_object_deallocate(fs->first_object);
diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c
index 875c22d27628..e7d7b6726d2c 100644
--- a/sys/vm/vm_kern.c
+++ b/sys/vm/vm_kern.c
@@ -110,11 +110,18 @@ u_int exec_map_entry_size;
u_int exec_map_entries;
SYSCTL_ULONG(_vm, OID_AUTO, min_kernel_address, CTLFLAG_RD,
- SYSCTL_NULL_ULONG_PTR, VM_MIN_KERNEL_ADDRESS, "Min kernel address");
+#if defined(__amd64__)
+ &kva_layout.km_low, 0,
+#else
+ SYSCTL_NULL_ULONG_PTR, VM_MIN_KERNEL_ADDRESS,
+#endif
+ "Min kernel address");
SYSCTL_ULONG(_vm, OID_AUTO, max_kernel_address, CTLFLAG_RD,
#if defined(__arm__)
&vm_max_kernel_address, 0,
+#elif defined(__amd64__)
+ &kva_layout.km_high, 0,
#else
SYSCTL_NULL_ULONG_PTR, VM_MAX_KERNEL_ADDRESS,
#endif
diff --git a/sys/vm/vm_pagequeue.h b/sys/vm/vm_pagequeue.h
index cbbd27389662..9bd3b389fb60 100644
--- a/sys/vm/vm_pagequeue.h
+++ b/sys/vm/vm_pagequeue.h
@@ -260,9 +260,9 @@ struct vm_domain {
u_int vmd_inactive_shortage; /* Per-thread shortage. */
blockcount_t vmd_inactive_running; /* Number of inactive threads. */
blockcount_t vmd_inactive_starting; /* Number of threads started. */
- volatile u_int vmd_addl_shortage; /* Shortage accumulator. */
- volatile u_int vmd_inactive_freed; /* Successful inactive frees. */
- volatile u_int vmd_inactive_us; /* Microseconds for above. */
+ u_int vmd_addl_shortage; /* (a) Shortage accumulator. */
+ u_int vmd_inactive_freed; /* (a) Successful inactive frees. */
+ u_int vmd_inactive_us; /* (a) Microseconds for above. */
u_int vmd_inactive_pps; /* Exponential decay frees/second. */
int vmd_oom_seq;
int vmd_last_active_scan;
diff --git a/sys/x86/linux/linux_dummy_x86.c b/sys/x86/linux/linux_dummy_x86.c
index ae1d23e811e7..221f5dbf5ba3 100644
--- a/sys/x86/linux/linux_dummy_x86.c
+++ b/sys/x86/linux/linux_dummy_x86.c
@@ -46,7 +46,5 @@ LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
DUMMY(sysfs);
DUMMY(quotactl);
-/* Linux 2.6.13: */
-DUMMY(inotify_init);
/* Linux 2.6.22: */
DUMMY(signalfd);
diff --git a/tests/Makefile b/tests/Makefile
index e8dd7793f169..451d55498a26 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,3 +1,5 @@
+.include <src.opts.mk>
+
PACKAGE= tests
TESTSDIR= ${TESTSBASE}
@@ -11,6 +13,9 @@ SUBDIR+= examples
SUBDIR+= include
SUBDIR+= sys
SUBDIR+= atf_python
+.if ${MK_CDDL} != "no"
+SUBDIR+= oclo
+.endif
SUBDIR_PARALLEL=
diff --git a/tests/atf_python/sys/net/vnet.py b/tests/atf_python/sys/net/vnet.py
index 68c8ce4e0cba..7afb5c721bf3 100644
--- a/tests/atf_python/sys/net/vnet.py
+++ b/tests/atf_python/sys/net/vnet.py
@@ -61,6 +61,7 @@ class VnetInterface(object):
self.iftype = self.IFT_LOOP
else:
self.iftype = self.IFT_ETHER
+ self.ether = ToolsHelper.get_output("/sbin/ifconfig %s ether | awk '/ether/ { print $2; }'" % iface_name).rstrip()
@property
def ifindex(self):
@@ -99,9 +100,12 @@ class VnetInterface(object):
name = run_cmd("/sbin/ifconfig {} create".format(iface_name)).rstrip()
if not name:
raise Exception("Unable to create iface {}".format(iface_name))
- ret = [cls(alias_name, name)]
+ if1 = cls(alias_name, name)
+ ret = [if1]
if name.startswith("epair"):
- ret.append(cls(alias_name, name[:-1] + "b"))
+ if2 = cls(alias_name, name[:-1] + "b")
+ if1.epairb = if2
+ ret.append(if2);
return ret
def setup_addr(self, _addr: str):
diff --git a/tests/ci/Makefile b/tests/ci/Makefile
index b57de345f852..b8797e06ac75 100644
--- a/tests/ci/Makefile
+++ b/tests/ci/Makefile
@@ -33,11 +33,11 @@ EXTRA_MAKE_FLAGS?=
TARGET= ${MACHINE}
.endif
.if !defined(TARGET_ARCH) || empty(TARGET_ARCH)
-.if ${TARGET} == ${MACHINE}
+. if ${TARGET} == ${MACHINE}
TARGET_ARCH= ${MACHINE_ARCH}
-.else
+. else
TARGET_ARCH= ${TARGET}
-.endif
+. endif
.endif
IMAKE= ${MAKE} TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}
@@ -47,20 +47,20 @@ CROSS_TOOLCHAIN_PARAM= "CROSS_TOOLCHAIN=${CROSS_TOOLCHAIN}"
# Define OSRELEASE by using newvers.sh
.if !defined(OSRELEASE) || empty(OSRELEASE)
-.for _V in TYPE BRANCH REVISION
-. if !defined(${_V}) || empty(${_V})
+. for _V in TYPE BRANCH REVISION
+. if !defined(${_V}) || empty(${_V})
${_V}!= eval $$(awk '/^${_V}=/{print}' ${.CURDIR}/../../sys/conf/newvers.sh); echo $$${_V}
-. endif
-.endfor
-.for _V in ${TARGET_ARCH}
-.if !empty(TARGET:M${_V})
+. endif
+. endfor
+. for _V in ${TARGET_ARCH}
+. if !empty(TARGET:M${_V})
OSRELEASE= ${TYPE}-${REVISION}-${BRANCH}-${TARGET}
VOLUME_LABEL= ${REVISION:C/[.-]/_/g}_${BRANCH:C/[.-]/_/g}_${TARGET}
-.else
+. else
OSRELEASE= ${TYPE}-${REVISION}-${BRANCH}-${TARGET}-${TARGET_ARCH}
VOLUME_LABEL= ${REVISION:C/[.-]/_/g}_${BRANCH:C/[.-]/_/g}_${TARGET_ARCH}
-.endif
-.endfor
+. endif
+. endfor
.endif
.if exists(${.CURDIR}/tools/ci.conf) && !defined(CICONF)
@@ -104,13 +104,13 @@ TIMEOUT_VM=$$((${TIMEOUT_EXPECT} - 120))
. include "${.CURDIR}/Makefile.${TARGET_ARCH}"
.endif
.if ${TARGET_ARCH} != ${MACHINE_ARCH}
-.if ( ${TARGET_ARCH} != "i386" ) || ( ${MACHINE_ARCH} != "amd64" )
+. if ( ${TARGET_ARCH} != "i386" ) || ( ${MACHINE_ARCH} != "amd64" )
QEMUSTATIC=/usr/local/bin/qemu-${QEMU_ARCH}-static
QEMUTGT=portinstall-qemu
-.endif
+. endif
.endif
QEMUTGT?=
-QEMU_DEVICES?=-device virtio-blk,drive=hd0
+QEMU_DEVICES?=-device virtio-blk,drive=hd0 -device virtio-blk,drive=hd1
QEMU_EXTRA_PARAM?=
QEMU_MACHINE?=virt
QEMUBIN=/usr/local/bin/qemu-system-${QEMU_ARCH}
@@ -144,10 +144,10 @@ portinstall-pkg: .PHONY
.endif
portinstall-qemu: portinstall-pkg .PHONY
-.if !exists(/usr/local/bin/qemu-${TARGET_ARCH}-static)
+.if !exists(/usr/local/bin/qemu-${QEMU_ARCH}-static)
env ASSUME_ALWAYS_YES=yes pkg install emulators/qemu-user-static
.endif
-.if !exists(/usr/local/bin/qemu-system-${QEMU_ARCH})
+.if !exists(${QEMUBIN})
env ASSUME_ALWAYS_YES=yes pkg install emulators/qemu@nox11
.endif
@@ -210,7 +210,11 @@ ci-extract-meta: .PHONY
ci-runtest: ci-buildimage-${TARGET_ARCH:tl} portinstall .PHONY
.if ${MACHINE} == "amd64" && ( ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386" ) && ( !defined(USE_QEMU) || empty(USE_QEMU) )
/usr/sbin/bhyvectl --vm=${TEST_VM_NAME} --destroy || true
- /usr/sbin/bhyveload -c stdio -m ${VM_MEM_SIZE} -d ${CIDISK} ${TEST_VM_NAME}
+ expect -c "set timeout ${TIMEOUT_EXPECT}; \
+ spawn /usr/bin/timeout -k 5s 30s /usr/sbin/bhyveload \
+ -c stdio -m ${VM_MEM_SIZE} -d ${CIDISK} ${TEST_VM_NAME}; \
+ expect { eof }; \
+ exit [lindex [wait] 3]"
expect -c "set timeout ${TIMEOUT_EXPECT}; \
spawn /usr/bin/timeout -k 60 ${TIMEOUT_VM} /usr/sbin/bhyve \
-c ${PARALLEL_JOBS} -m ${VM_MEM_SIZE} -A -H -P \
diff --git a/tests/ci/tools/freebsdci b/tests/ci/tools/freebsdci
index f0030fe00aba..51bd19e2967d 100755
--- a/tests/ci/tools/freebsdci
+++ b/tests/ci/tools/freebsdci
@@ -25,19 +25,22 @@
. /etc/rc.subr
-: ${freebsdci_enable:="NO"}
-: ${freebsdci_type:="full"}
-
name="freebsdci"
desc="Run FreeBSD CI"
rcvar=freebsdci_enable
start_cmd="firstboot_ci_run"
stop_cmd=":"
os_arch=$(uname -p)
+parallelism=$(nproc)
tardev=/dev/vtbd1
metadir=/meta
istar=$(file -s ${tardev} | grep "POSIX tar archive" | wc -l)
+load_rc_config $name
+: ${freebsdci_enable:="NO"}
+: ${freebsdci_type:="full"}
+PATH="${PATH}:/usr/local/sbin:/usr/local/bin"
+
auto_shutdown()
{
# NOTE: Currently RISC-V kernels lack the ability to
@@ -74,7 +77,7 @@ full_tests()
tar xvf ${tardev} -C ${metadir}
cd /usr/tests
set +e
- kyua test
+ kyua -v parallelism=${parallelism} test
rc=$?
set -e
if [ ${rc} -ne 0 ] && [ ${rc} -ne 1 ]; then
@@ -104,5 +107,4 @@ firstboot_ci_run()
auto_shutdown
}
-load_rc_config $name
run_rc_command "$1"
diff --git a/tests/oclo/Makefile b/tests/oclo/Makefile
new file mode 100644
index 000000000000..350c9f857c85
--- /dev/null
+++ b/tests/oclo/Makefile
@@ -0,0 +1,11 @@
+.PATH: ${SRCTOP}/cddl/contrib/opensolaris/tests/os-tests/tests/oclo
+
+TESTSDIR= ${TESTSBASE}/cddl/oclo
+
+PLAIN_TESTS_C= oclo oclo_errors ocloexec_verify
+
+SRCS.oclo= oclo.c
+LIBADD.oclo+= openbsd
+LIBADD.ocloexec_verify+= util
+
+.include <bsd.test.mk>
diff --git a/tests/sys/file/closefrom_test.c b/tests/sys/file/closefrom_test.c
index e30c5eb3d591..7dccf858c772 100644
--- a/tests/sys/file/closefrom_test.c
+++ b/tests/sys/file/closefrom_test.c
@@ -144,7 +144,7 @@ main(void)
pid_t pid;
int fd, flags, i, start;
- printf("1..21\n");
+ printf("1..22\n");
/* We'd better start up with fd's 0, 1, and 2 open. */
start = devnull();
@@ -356,5 +356,38 @@ main(void)
fail_err("close_range");
ok("close_range(..., CLOSE_RANGE_CLOEXEC)");
+ /* test CLOSE_RANGE_CLOFORK */
+ for (i = 0; i < 8; i++)
+ (void)devnull();
+ fd = highest_fd();
+ start = fd - 8;
+ if (close_range(start + 1, start + 4, CLOSE_RANGE_CLOFORK) < 0)
+ fail_err("close_range(..., CLOSE_RANGE_CLOFORK)");
+ flags = fcntl(start, F_GETFD);
+ if (flags < 0)
+ fail_err("fcntl(.., F_GETFD)");
+ if ((flags & FD_CLOFORK) != 0)
+ fail("close_range", "CLOSE_RANGE_CLOFORK set close-on-exec "
+ "when it should not have on fd %d", start);
+ for (i = start + 1; i <= start + 4; i++) {
+ flags = fcntl(i, F_GETFD);
+ if (flags < 0)
+ fail_err("fcntl(.., F_GETFD)");
+ if ((flags & FD_CLOFORK) == 0)
+ fail("close_range", "CLOSE_RANGE_CLOFORK did not set "
+ "close-on-exec on fd %d", i);
+ }
+ for (; i < start + 8; i++) {
+ flags = fcntl(i, F_GETFD);
+ if (flags < 0)
+ fail_err("fcntl(.., F_GETFD)");
+ if ((flags & FD_CLOFORK) != 0)
+ fail("close_range", "CLOSE_RANGE_CLOFORK set close-on-exec "
+ "when it should not have on fd %d", i);
+ }
+ if (close_range(start, start + 8, 0) < 0)
+ fail_err("close_range");
+ ok("close_range(..., CLOSE_RANGE_CLOFORK)");
+
return (0);
}
diff --git a/tests/sys/file/dup_test.c b/tests/sys/file/dup_test.c
index b024e72d0d1a..455115eda8c8 100644
--- a/tests/sys/file/dup_test.c
+++ b/tests/sys/file/dup_test.c
@@ -46,6 +46,8 @@
* Test #31: check if dup3(0) fails if oldfd == newfd.
* Test #32: check if dup3(O_CLOEXEC) to a fd > current maximum number of
* open files limit work.
+ * Tests #33-43 : Same as #18-26, 30 & 32 with O_CLOFORK instead of O_CLOEXEC,
+ * except F_DUP2FD_CLOEXEC.
*/
#include <sys/types.h>
@@ -82,7 +84,7 @@ main(int __unused argc, char __unused *argv[])
orgfd = getafile();
- printf("1..32\n");
+ printf("1..43\n");
/* If dup(2) ever work? */
if ((fd1 = dup(orgfd)) < 0)
@@ -380,5 +382,99 @@ main(int __unused argc, char __unused *argv[])
printf("ok %d - dup3(O_CLOEXEC) didn't bypass NOFILE limit\n",
test);
+ /* Does fcntl(F_DUPFD_CLOFORK) work? */
+ if ((fd2 = fcntl(fd1, F_DUPFD_CLOFORK, 10)) < 0)
+ err(1, "fcntl(F_DUPFD_CLOFORK)");
+ if (fd2 < 10)
+ printf("not ok %d - fcntl(F_DUPFD_CLOFORK) returned wrong fd %d\n",
+ ++test, fd2);
+ else
+ printf("ok %d - fcntl(F_DUPFD_CLOFORK) works\n", ++test);
+
+ /* Was close-on-fork cleared? */
+ ++test;
+ if (fcntl(fd2, F_GETFD) != FD_CLOFORK)
+ printf(
+ "not ok %d - fcntl(F_DUPFD_CLOFORK) didn't set close-on-fork\n",
+ test);
+ else
+ printf("ok %d - fcntl(F_DUPFD_CLOFORK) set close-on-fork\n",
+ test);
+
+ /* Does dup3(O_CLOFORK) ever work? */
+ if ((fd2 = dup3(fd1, fd1 + 1, O_CLOFORK)) < 0)
+ err(1, "dup3(O_CLOFORK)");
+ printf("ok %d - dup3(O_CLOFORK) works\n", ++test);
+
+ /* Do we get the right fd? */
+ ++test;
+ if (fd2 != fd1 + 1)
+ printf(
+ "no ok %d - dup3(O_CLOFORK) didn't give us the right fd\n",
+ test);
+ else
+ printf("ok %d - dup3(O_CLOFORK) returned a correct fd\n",
+ test);
+
+ /* Was close-on-fork set? */
+ ++test;
+ if (fcntl(fd2, F_GETFD) != FD_CLOFORK)
+ printf(
+ "not ok %d - dup3(O_CLOFORK) didn't set close-on-fork\n",
+ test);
+ else
+ printf("ok %d - dup3(O_CLOFORK) set close-on-fork\n",
+ test);
+
+ /* Does dup3(0) ever work? */
+ if ((fd2 = dup3(fd1, fd1 + 1, 0)) < 0)
+ err(1, "dup3(0)");
+ printf("ok %d - dup3(0) works\n", ++test);
+
+ /* Do we get the right fd? */
+ ++test;
+ if (fd2 != fd1 + 1)
+ printf(
+ "no ok %d - dup3(0) didn't give us the right fd\n",
+ test);
+ else
+ printf("ok %d - dup3(0) returned a correct fd\n",
+ test);
+
+ /* Was close-on-fork cleared? */
+ ++test;
+ if (fcntl(fd2, F_GETFD) != 0)
+ printf(
+ "not ok %d - dup3(0) didn't clear close-on-fork\n",
+ test);
+ else
+ printf("ok %d - dup3(0) cleared close-on-fork\n",
+ test);
+
+ /* dup3() does not allow duplicating to the same fd */
+ ++test;
+ if (dup3(fd1, fd1, O_CLOFORK) != -1)
+ printf(
+ "not ok %d - dup3(fd1, fd1, O_CLOFORK) succeeded\n", test);
+ else
+ printf("ok %d - dup3(fd1, fd1, O_CLOFORK) failed\n", test);
+
+ ++test;
+ if (dup3(fd1, fd1, 0) != -1)
+ printf(
+ "not ok %d - dup3(fd1, fd1, 0) succeeded\n", test);
+ else
+ printf("ok %d - dup3(fd1, fd1, 0) failed\n", test);
+
+ ++test;
+ if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
+ err(1, "getrlimit");
+ if ((fd2 = dup3(fd1, rlp.rlim_cur + 1, O_CLOFORK)) >= 0)
+ printf("not ok %d - dup3(O_CLOFORK) bypassed NOFILE limit\n",
+ test);
+ else
+ printf("ok %d - dup3(O_CLOFORK) didn't bypass NOFILE limit\n",
+ test);
+
return (0);
}
diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile
index 8cc7beade3f3..336e73f29835 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -17,8 +17,11 @@ ATF_TESTS_C+= kern_copyin
ATF_TESTS_C+= kern_descrip_test
# One test modifies the maxfiles limit, which can cause spurious test failures.
TEST_METADATA.kern_descrip_test+= is_exclusive="true"
+ATF_TESTS_C+= exterr_test
ATF_TESTS_C+= fdgrowtable_test
+ATF_TESTS_C+= getdirentries_test
ATF_TESTS_C+= jail_lookup_root
+ATF_TESTS_C+= inotify_test
ATF_TESTS_C+= kill_zombie
.if ${MK_OPENSSL} != "no"
ATF_TESTS_C+= ktls_test
@@ -85,6 +88,7 @@ LIBADD.sys_getrandom+= c
LIBADD.sys_getrandom+= pthread
LIBADD.ptrace_test+= pthread
LIBADD.unix_seqpacket_test+= pthread
+LIBADD.inotify_test+= util
LIBADD.kcov+= pthread
CFLAGS.ktls_test+= -DOPENSSL_API_COMPAT=0x10100000L
LIBADD.ktls_test+= crypto util
diff --git a/tests/sys/kern/exterr_test.c b/tests/sys/kern/exterr_test.c
new file mode 100644
index 000000000000..17c84c1f8ed4
--- /dev/null
+++ b/tests/sys/kern/exterr_test.c
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (C) 2025 ConnectWise, LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/exterrvar.h>
+#include <sys/mman.h>
+
+#include <atf-c.h>
+#include <errno.h>
+#include <exterr.h>
+#include <stdio.h>
+
+ATF_TC(gettext_extended);
+ATF_TC_HEAD(gettext_extended, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Retrieve an extended error message");
+}
+ATF_TC_BODY(gettext_extended, tc)
+{
+ char exterr[UEXTERROR_MAXLEN];
+ int r;
+
+ /*
+ * Use an invalid call to mmap() because it supports extended error
+ * messages, requires no special resources, and does not need root.
+ */
+ ATF_CHECK_ERRNO(ENOTSUP,
+ mmap(NULL, 0, PROT_MAX(PROT_READ) | PROT_WRITE, 0, -1, 0));
+ r = uexterr_gettext(exterr, sizeof(exterr));
+ ATF_CHECK_EQ(0, r);
+ printf("Extended error: %s\n", exterr);
+ /* Note: error string may need to be updated due to kernel changes */
+ ATF_CHECK(strstr(exterr, "prot is not subset of max_prot") != 0);
+}
+
+ATF_TC(gettext_noextended);
+ATF_TC_HEAD(gettext_noextended, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Fail to retrieve an extended error message because none exists");
+}
+ATF_TC_BODY(gettext_noextended, tc)
+{
+ char exterr[UEXTERROR_MAXLEN];
+ int r;
+
+ ATF_CHECK_ERRNO(EINVAL, exterrctl(EXTERRCTL_UD, 0, NULL));
+ r = uexterr_gettext(exterr, sizeof(exterr));
+ ATF_CHECK_EQ(0, r);
+ ATF_CHECK_STREQ(exterr, "");
+}
+
+ATF_TC(gettext_noextended_after_extended);
+ATF_TC_HEAD(gettext_noextended_after_extended, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "uexterr_gettext should not return a stale extended error message");
+}
+ATF_TC_BODY(gettext_noextended_after_extended, tc)
+{
+ char exterr[UEXTERROR_MAXLEN];
+ int r;
+
+ /*
+ * First do something that will create an extended error message, but
+ * ignore it.
+ */
+ ATF_CHECK_ERRNO(ENOTSUP,
+ mmap(NULL, 0, PROT_MAX(PROT_READ) | PROT_WRITE, 0, -1, 0));
+
+ /* Then do something that won't create an extended error message */
+ ATF_CHECK_ERRNO(EINVAL, exterrctl(EXTERRCTL_UD, 0, NULL));
+
+ /* Hopefully we won't see the stale extended error message */
+ r = uexterr_gettext(exterr, sizeof(exterr));
+ ATF_CHECK_EQ(0, r);
+ ATF_CHECK_STREQ(exterr, "");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, gettext_extended);
+ ATF_TP_ADD_TC(tp, gettext_noextended);
+ ATF_TP_ADD_TC(tp, gettext_noextended_after_extended);
+
+ return (atf_no_error());
+}
diff --git a/tests/sys/kern/getdirentries_test.c b/tests/sys/kern/getdirentries_test.c
new file mode 100644
index 000000000000..e66872ffe5b6
--- /dev/null
+++ b/tests/sys/kern/getdirentries_test.c
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <atf-c.h>
+
+ATF_TC(getdirentries_ok);
+ATF_TC_HEAD(getdirentries_ok, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Successfully read a directory.");
+}
+ATF_TC_BODY(getdirentries_ok, tc)
+{
+ char dbuf[4096];
+ struct dirent *d;
+ off_t base;
+ ssize_t ret;
+ int dd, n;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE((ret = getdirentries(dd, dbuf, sizeof(dbuf), &base)) > 0);
+ ATF_REQUIRE_EQ(0, getdirentries(dd, dbuf, sizeof(dbuf), &base));
+ ATF_REQUIRE_EQ(base, lseek(dd, 0, SEEK_CUR));
+ ATF_CHECK_EQ(0, close(dd));
+ for (n = 0, d = (struct dirent *)dbuf;
+ d < (struct dirent *)(dbuf + ret);
+ d = (struct dirent *)((char *)d + d->d_reclen), n++)
+ /* nothing */ ;
+ ATF_CHECK_EQ((struct dirent *)(dbuf + ret), d);
+ ATF_CHECK_EQ(2, n);
+}
+
+ATF_TC(getdirentries_ebadf);
+ATF_TC_HEAD(getdirentries_ebadf, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "from an invalid descriptor.");
+}
+ATF_TC_BODY(getdirentries_ebadf, tc)
+{
+ char dbuf[4096];
+ off_t base;
+ int fd;
+
+ ATF_REQUIRE((fd = open("file", O_CREAT | O_WRONLY, 0644)) >= 0);
+ ATF_REQUIRE_EQ(-1, getdirentries(fd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(EBADF, errno);
+ ATF_REQUIRE_EQ(0, close(fd));
+ ATF_REQUIRE_EQ(-1, getdirentries(fd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(EBADF, errno);
+}
+
+ATF_TC(getdirentries_efault);
+ATF_TC_HEAD(getdirentries_efault, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "to an invalid buffer.");
+}
+ATF_TC_BODY(getdirentries_efault, tc)
+{
+ char dbuf[4096];
+ off_t base, *basep;
+ int dd;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, NULL, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(EFAULT, errno);
+ basep = NULL;
+ basep++;
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, sizeof(dbuf), basep));
+ ATF_CHECK_EQ(EFAULT, errno);
+ ATF_CHECK_EQ(0, close(dd));
+}
+
+ATF_TC(getdirentries_einval);
+ATF_TC_HEAD(getdirentries_einval, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "with various invalid parameters.");
+}
+ATF_TC_BODY(getdirentries_einval, tc)
+{
+ struct statfs fsb;
+ char dbuf[4096];
+ off_t base;
+ ssize_t ret;
+ int dd;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE_EQ(0, fstatfs(dd, &fsb));
+ /* nbytes too small */
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, 8, &base));
+ ATF_CHECK_EQ(EINVAL, errno);
+ /* nbytes too big */
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, SIZE_MAX, &base));
+ ATF_CHECK_EQ(EINVAL, errno);
+ /* invalid position */
+ ATF_REQUIRE((ret = getdirentries(dd, dbuf, sizeof(dbuf), &base)) > 0);
+ ATF_REQUIRE_EQ(0, getdirentries(dd, dbuf, sizeof(dbuf), &base));
+ ATF_REQUIRE(base > 0);
+ ATF_REQUIRE_EQ(base + 3, lseek(dd, 3, SEEK_CUR));
+ /* known to fail on ufs (FFS2) and zfs, and work on tmpfs */
+ if (strcmp(fsb.f_fstypename, "ufs") == 0 ||
+ strcmp(fsb.f_fstypename, "zfs") == 0) {
+ atf_tc_expect_fail("incorrectly returns 0 instead of EINVAL "
+ "on %s", fsb.f_fstypename);
+ }
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(EINVAL, errno);
+ ATF_CHECK_EQ(0, close(dd));
+}
+
+ATF_TC(getdirentries_enoent);
+ATF_TC_HEAD(getdirentries_enoent, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "after it is deleted.");
+}
+ATF_TC_BODY(getdirentries_enoent, tc)
+{
+ char dbuf[4096];
+ off_t base;
+ int dd;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE_EQ(0, rmdir("dir"));
+ ATF_REQUIRE_EQ(-1, getdirentries(dd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(ENOENT, errno);
+}
+
+ATF_TC(getdirentries_enotdir);
+ATF_TC_HEAD(getdirentries_enotdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Attempt to read a directory "
+ "from a descriptor not associated with a directory.");
+}
+ATF_TC_BODY(getdirentries_enotdir, tc)
+{
+ char dbuf[4096];
+ off_t base;
+ int fd;
+
+ ATF_REQUIRE((fd = open("file", O_CREAT | O_RDWR, 0644)) >= 0);
+ ATF_REQUIRE_EQ(-1, getdirentries(fd, dbuf, sizeof(dbuf), &base));
+ ATF_CHECK_EQ(ENOTDIR, errno);
+ ATF_CHECK_EQ(0, close(fd));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, getdirentries_ok);
+ ATF_TP_ADD_TC(tp, getdirentries_ebadf);
+ ATF_TP_ADD_TC(tp, getdirentries_efault);
+ ATF_TP_ADD_TC(tp, getdirentries_einval);
+ ATF_TP_ADD_TC(tp, getdirentries_enoent);
+ ATF_TP_ADD_TC(tp, getdirentries_enotdir);
+ return (atf_no_error());
+}
diff --git a/tests/sys/kern/inotify_test.c b/tests/sys/kern/inotify_test.c
new file mode 100644
index 000000000000..713db55afc22
--- /dev/null
+++ b/tests/sys/kern/inotify_test.c
@@ -0,0 +1,864 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Klara, Inc.
+ */
+
+#include <sys/capsicum.h>
+#include <sys/filio.h>
+#include <sys/inotify.h>
+#include <sys/ioccom.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/un.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <mntopts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static const char *
+ev2name(int event)
+{
+ switch (event) {
+ case IN_ACCESS:
+ return ("IN_ACCESS");
+ case IN_ATTRIB:
+ return ("IN_ATTRIB");
+ case IN_CLOSE_WRITE:
+ return ("IN_CLOSE_WRITE");
+ case IN_CLOSE_NOWRITE:
+ return ("IN_CLOSE_NOWRITE");
+ case IN_CREATE:
+ return ("IN_CREATE");
+ case IN_DELETE:
+ return ("IN_DELETE");
+ case IN_DELETE_SELF:
+ return ("IN_DELETE_SELF");
+ case IN_MODIFY:
+ return ("IN_MODIFY");
+ case IN_MOVE_SELF:
+ return ("IN_MOVE_SELF");
+ case IN_MOVED_FROM:
+ return ("IN_MOVED_FROM");
+ case IN_MOVED_TO:
+ return ("IN_MOVED_TO");
+ case IN_OPEN:
+ return ("IN_OPEN");
+ default:
+ return (NULL);
+ }
+}
+
+static void
+close_checked(int fd)
+{
+ ATF_REQUIRE(close(fd) == 0);
+}
+
+/*
+ * Make sure that no other events are pending, and close the inotify descriptor.
+ */
+static void
+close_inotify(int fd)
+{
+ int n;
+
+ ATF_REQUIRE(ioctl(fd, FIONREAD, &n) == 0);
+ ATF_REQUIRE(n == 0);
+ close_checked(fd);
+}
+
+static uint32_t
+consume_event_cookie(int ifd, int wd, unsigned int event, unsigned int flags,
+ const char *name)
+{
+ struct inotify_event *ev;
+ size_t evsz, namelen;
+ ssize_t n;
+ uint32_t cookie;
+
+ /* Only read one record. */
+ namelen = name == NULL ? 0 : strlen(name);
+ evsz = sizeof(*ev) + _IN_NAMESIZE(namelen);
+ ev = malloc(evsz);
+ ATF_REQUIRE(ev != NULL);
+
+ n = read(ifd, ev, evsz);
+ ATF_REQUIRE_MSG(n >= 0, "failed to read event %s", ev2name(event));
+ ATF_REQUIRE((size_t)n >= sizeof(*ev));
+ ATF_REQUIRE((size_t)n == sizeof(*ev) + ev->len);
+ ATF_REQUIRE((size_t)n == evsz);
+
+ ATF_REQUIRE_MSG((ev->mask & IN_ALL_EVENTS) == event,
+ "expected event %#x, got %#x", event, ev->mask);
+ ATF_REQUIRE_MSG((ev->mask & _IN_ALL_RETFLAGS) == flags,
+ "expected flags %#x, got %#x", flags, ev->mask);
+ ATF_REQUIRE_MSG(ev->wd == wd,
+ "expected wd %d, got %d", wd, ev->wd);
+ ATF_REQUIRE_MSG(name == NULL || strcmp(name, ev->name) == 0,
+ "expected name '%s', got '%s'", name, ev->name);
+ cookie = ev->cookie;
+ if ((ev->mask & (IN_MOVED_FROM | IN_MOVED_TO)) == 0)
+ ATF_REQUIRE(cookie == 0);
+ free(ev);
+ return (cookie);
+}
+
+/*
+ * Read an event from the inotify file descriptor and check that it
+ * matches the expected values.
+ */
+static void
+consume_event(int ifd, int wd, unsigned int event, unsigned int flags,
+ const char *name)
+{
+ (void)consume_event_cookie(ifd, wd, event, flags, name);
+}
+
+static int
+inotify(int flags)
+{
+ int ifd;
+
+ ifd = inotify_init1(flags);
+ ATF_REQUIRE(ifd != -1);
+ return (ifd);
+}
+
+static void
+mount_nullfs(char *dir, char *src)
+{
+ struct iovec *iov;
+ char errmsg[1024];
+ int error, iovlen;
+
+ iov = NULL;
+ iovlen = 0;
+
+ build_iovec(&iov, &iovlen, "fstype", "nullfs", (size_t)-1);
+ build_iovec(&iov, &iovlen, "fspath", dir, (size_t)-1);
+ build_iovec(&iov, &iovlen, "target", src, (size_t)-1);
+ build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
+
+ errmsg[0] = '\0';
+ error = nmount(iov, iovlen, 0);
+ ATF_REQUIRE_MSG(error == 0,
+ "mount nullfs %s %s: %s", src, dir,
+ errmsg[0] == '\0' ? strerror(errno) : errmsg);
+
+ free_iovec(&iov, &iovlen);
+}
+
+static void
+mount_tmpfs(const char *dir)
+{
+ struct iovec *iov;
+ char errmsg[1024];
+ int error, iovlen;
+
+ iov = NULL;
+ iovlen = 0;
+
+ build_iovec(&iov, &iovlen, "fstype", "tmpfs", (size_t)-1);
+ build_iovec(&iov, &iovlen, "fspath", __DECONST(char *, dir),
+ (size_t)-1);
+ build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
+
+ errmsg[0] = '\0';
+ error = nmount(iov, iovlen, 0);
+ ATF_REQUIRE_MSG(error == 0,
+ "mount tmpfs %s: %s", dir,
+ errmsg[0] == '\0' ? strerror(errno) : errmsg);
+
+ free_iovec(&iov, &iovlen);
+}
+
+static int
+watch_file(int ifd, int events, char *path)
+{
+ int fd, wd;
+
+ strncpy(path, "test.XXXXXX", PATH_MAX);
+ fd = mkstemp(path);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+
+ wd = inotify_add_watch(ifd, path, events);
+ ATF_REQUIRE(wd != -1);
+
+ return (wd);
+}
+
+static int
+watch_dir(int ifd, int events, char *path)
+{
+ char *p;
+ int wd;
+
+ strlcpy(path, "test.XXXXXX", PATH_MAX);
+ p = mkdtemp(path);
+ ATF_REQUIRE(p == path);
+
+ wd = inotify_add_watch(ifd, path, events);
+ ATF_REQUIRE(wd != -1);
+
+ return (wd);
+}
+
+/*
+ * Verify that Capsicum restrictions are applied as expected.
+ */
+ATF_TC_WITHOUT_HEAD(inotify_capsicum);
+ATF_TC_BODY(inotify_capsicum, tc)
+{
+ int error, dfd, ifd, wd;
+
+ ifd = inotify(IN_NONBLOCK);
+ ATF_REQUIRE(ifd != -1);
+
+ dfd = open(".", O_RDONLY | O_DIRECTORY);
+ ATF_REQUIRE(dfd != -1);
+
+ error = mkdirat(dfd, "testdir", 0755);
+ ATF_REQUIRE(error == 0);
+
+ error = cap_enter();
+ ATF_REQUIRE(error == 0);
+
+ /*
+ * Plain inotify_add_watch() is disallowed.
+ */
+ wd = inotify_add_watch(ifd, ".", IN_DELETE_SELF);
+ ATF_REQUIRE_ERRNO(ECAPMODE, wd == -1);
+ wd = inotify_add_watch_at(ifd, dfd, "testdir", IN_DELETE_SELF);
+ ATF_REQUIRE(wd >= 0);
+
+ /*
+ * Generate a record and consume it.
+ */
+ error = unlinkat(dfd, "testdir", AT_REMOVEDIR);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_DELETE_SELF, IN_ISDIR, NULL);
+ consume_event(ifd, wd, 0, IN_IGNORED, NULL);
+
+ close_checked(dfd);
+ close_inotify(ifd);
+}
+
+/*
+ * Make sure that duplicate, back-to-back events are coalesced.
+ */
+ATF_TC_WITHOUT_HEAD(inotify_coalesce);
+ATF_TC_BODY(inotify_coalesce, tc)
+{
+ char file[PATH_MAX], path[PATH_MAX];
+ int fd, fd1, ifd, n, wd;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ /* Create a directory and watch it. */
+ wd = watch_dir(ifd, IN_OPEN, path);
+ /* Create a file in the directory and open it. */
+ snprintf(file, sizeof(file), "%s/file", path);
+ fd = open(file, O_RDWR | O_CREAT, 0644);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ fd = open(file, O_RDWR);
+ ATF_REQUIRE(fd != -1);
+ fd1 = open(file, O_RDONLY);
+ ATF_REQUIRE(fd1 != -1);
+ close_checked(fd1);
+ close_checked(fd);
+
+ consume_event(ifd, wd, IN_OPEN, 0, "file");
+ ATF_REQUIRE(ioctl(ifd, FIONREAD, &n) == 0);
+ ATF_REQUIRE(n == 0);
+
+ close_inotify(ifd);
+}
+
+/*
+ * Check handling of IN_MASK_CREATE.
+ */
+ATF_TC_WITHOUT_HEAD(inotify_mask_create);
+ATF_TC_BODY(inotify_mask_create, tc)
+{
+ char path[PATH_MAX];
+ int ifd, wd, wd1;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ /* Create a directory and watch it. */
+ wd = watch_dir(ifd, IN_CREATE, path);
+ /* Updating the watch with IN_MASK_CREATE should result in an error. */
+ wd1 = inotify_add_watch(ifd, path, IN_MODIFY | IN_MASK_CREATE);
+ ATF_REQUIRE_ERRNO(EEXIST, wd1 == -1);
+ /* It's an error to specify IN_MASK_ADD with IN_MASK_CREATE. */
+ wd1 = inotify_add_watch(ifd, path, IN_MODIFY | IN_MASK_ADD |
+ IN_MASK_CREATE);
+ ATF_REQUIRE_ERRNO(EINVAL, wd1 == -1);
+ /* Updating the watch without IN_MASK_CREATE should work. */
+ wd1 = inotify_add_watch(ifd, path, IN_MODIFY);
+ ATF_REQUIRE(wd1 != -1);
+ ATF_REQUIRE_EQ(wd, wd1);
+
+ close_inotify(ifd);
+}
+
+/*
+ * Make sure that inotify cooperates with nullfs: if a lower vnode is the
+ * subject of an event, the upper vnode should be notified, and if the upper
+ * vnode is the subject of an event, the lower vnode should be notified.
+ */
+ATF_TC_WITH_CLEANUP(inotify_nullfs);
+ATF_TC_HEAD(inotify_nullfs, tc)
+{
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(inotify_nullfs, tc)
+{
+ char path[PATH_MAX], *p;
+ int dfd, error, fd, ifd, mask, wd;
+
+ mask = IN_CREATE | IN_OPEN;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ strlcpy(path, "./test.XXXXXX", sizeof(path));
+ p = mkdtemp(path);
+ ATF_REQUIRE(p == path);
+
+ error = mkdir("./mnt", 0755);
+ ATF_REQUIRE(error == 0);
+
+ /* Mount the testdir onto ./mnt. */
+ mount_nullfs("./mnt", path);
+
+ wd = inotify_add_watch(ifd, "./mnt", mask);
+ ATF_REQUIRE(wd != -1);
+
+ /* Create a file in the lower directory and open it. */
+ dfd = open(path, O_RDONLY | O_DIRECTORY);
+ ATF_REQUIRE(dfd != -1);
+ fd = openat(dfd, "file", O_RDWR | O_CREAT, 0644);
+ close_checked(fd);
+ close_checked(dfd);
+
+ /* We should see events via the nullfs mount. */
+ consume_event(ifd, wd, IN_OPEN, IN_ISDIR, NULL);
+ consume_event(ifd, wd, IN_CREATE, 0, "file");
+ consume_event(ifd, wd, IN_OPEN, 0, "file");
+
+ error = inotify_rm_watch(ifd, wd);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, 0, IN_IGNORED, NULL);
+
+ /* Watch the lower directory. */
+ wd = inotify_add_watch(ifd, path, mask);
+ ATF_REQUIRE(wd != -1);
+ /* ... and create a file in the upper directory and open it. */
+ dfd = open("./mnt", O_RDONLY | O_DIRECTORY);
+ ATF_REQUIRE(dfd != -1);
+ fd = openat(dfd, "file2", O_RDWR | O_CREAT, 0644);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ close_checked(dfd);
+
+ /* We should see events via the lower directory. */
+ consume_event(ifd, wd, IN_OPEN, IN_ISDIR, NULL);
+ consume_event(ifd, wd, IN_CREATE, 0, "file2");
+ consume_event(ifd, wd, IN_OPEN, 0, "file2");
+
+ close_inotify(ifd);
+}
+ATF_TC_CLEANUP(inotify_nullfs, tc)
+{
+ int error;
+
+ error = unmount("./mnt", 0);
+ if (error != 0) {
+ perror("unmount");
+ exit(1);
+ }
+}
+
+/*
+ * Make sure that exceeding max_events pending events results in an overflow
+ * event.
+ */
+ATF_TC_WITHOUT_HEAD(inotify_queue_overflow);
+ATF_TC_BODY(inotify_queue_overflow, tc)
+{
+ char path[PATH_MAX];
+ size_t size;
+ int error, dfd, ifd, max, wd;
+
+ size = sizeof(max);
+ error = sysctlbyname("vfs.inotify.max_queued_events", &max, &size, NULL,
+ 0);
+ ATF_REQUIRE(error == 0);
+
+ ifd = inotify(IN_NONBLOCK);
+
+ /* Create a directory and watch it for file creation events. */
+ wd = watch_dir(ifd, IN_CREATE, path);
+ dfd = open(path, O_DIRECTORY);
+ ATF_REQUIRE(dfd != -1);
+ /* Generate max+1 file creation events. */
+ for (int i = 0; i < max + 1; i++) {
+ char name[NAME_MAX];
+ int fd;
+
+ (void)snprintf(name, sizeof(name), "file%d", i);
+ fd = openat(dfd, name, O_CREAT | O_RDWR, 0644);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ }
+
+ /*
+ * Read our events. We should see files 0..max-1 and then an overflow
+ * event.
+ */
+ for (int i = 0; i < max; i++) {
+ char name[NAME_MAX];
+
+ (void)snprintf(name, sizeof(name), "file%d", i);
+ consume_event(ifd, wd, IN_CREATE, 0, name);
+ }
+
+ /* Look for an overflow event. */
+ consume_event(ifd, -1, 0, IN_Q_OVERFLOW, NULL);
+
+ close_checked(dfd);
+ close_inotify(ifd);
+}
+
+ATF_TC_WITHOUT_HEAD(inotify_event_access_file);
+ATF_TC_BODY(inotify_event_access_file, tc)
+{
+ char path[PATH_MAX], buf[16];
+ off_t nb;
+ ssize_t n;
+ int error, fd, fd1, ifd, s[2], wd;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ wd = watch_file(ifd, IN_ACCESS, path);
+
+ fd = open(path, O_RDWR);
+ n = write(fd, "test", 4);
+ ATF_REQUIRE(n == 4);
+
+ /* A simple read(2) should generate an access. */
+ ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0);
+ n = read(fd, buf, sizeof(buf));
+ ATF_REQUIRE(n == 4);
+ ATF_REQUIRE(memcmp(buf, "test", 4) == 0);
+ consume_event(ifd, wd, IN_ACCESS, 0, NULL);
+
+ /* copy_file_range(2) should as well. */
+ ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0);
+ fd1 = open("sink", O_RDWR | O_CREAT, 0644);
+ ATF_REQUIRE(fd1 != -1);
+ n = copy_file_range(fd, NULL, fd1, NULL, 4, 0);
+ ATF_REQUIRE(n == 4);
+ close_checked(fd1);
+ consume_event(ifd, wd, IN_ACCESS, 0, NULL);
+
+ /* As should sendfile(2). */
+ error = socketpair(AF_UNIX, SOCK_STREAM, 0, s);
+ ATF_REQUIRE(error == 0);
+ error = sendfile(fd, s[0], 0, 4, NULL, &nb, 0);
+ ATF_REQUIRE(error == 0);
+ ATF_REQUIRE(nb == 4);
+ consume_event(ifd, wd, IN_ACCESS, 0, NULL);
+ close_checked(s[0]);
+ close_checked(s[1]);
+
+ close_checked(fd);
+
+ close_inotify(ifd);
+}
+
+ATF_TC_WITHOUT_HEAD(inotify_event_access_dir);
+ATF_TC_BODY(inotify_event_access_dir, tc)
+{
+ char root[PATH_MAX], path[PATH_MAX];
+ struct dirent *ent;
+ DIR *dir;
+ int error, ifd, wd;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ wd = watch_dir(ifd, IN_ACCESS, root);
+ snprintf(path, sizeof(path), "%s/dir", root);
+ error = mkdir(path, 0755);
+ ATF_REQUIRE(error == 0);
+
+ /* Read an entry and generate an access. */
+ dir = opendir(path);
+ ATF_REQUIRE(dir != NULL);
+ ent = readdir(dir);
+ ATF_REQUIRE(ent != NULL);
+ ATF_REQUIRE(strcmp(ent->d_name, ".") == 0 ||
+ strcmp(ent->d_name, "..") == 0);
+ ATF_REQUIRE(closedir(dir) == 0);
+ consume_event(ifd, wd, IN_ACCESS, IN_ISDIR, "dir");
+
+ /*
+ * Reading the watched directory should generate an access event.
+ * This is contrary to Linux's inotify man page, which states that
+ * IN_ACCESS is only generated for accesses to objects in a watched
+ * directory.
+ */
+ dir = opendir(root);
+ ATF_REQUIRE(dir != NULL);
+ ent = readdir(dir);
+ ATF_REQUIRE(ent != NULL);
+ ATF_REQUIRE(strcmp(ent->d_name, ".") == 0 ||
+ strcmp(ent->d_name, "..") == 0);
+ ATF_REQUIRE(closedir(dir) == 0);
+ consume_event(ifd, wd, IN_ACCESS, IN_ISDIR, NULL);
+
+ close_inotify(ifd);
+}
+
+ATF_TC_WITHOUT_HEAD(inotify_event_attrib);
+ATF_TC_BODY(inotify_event_attrib, tc)
+{
+ char path[PATH_MAX];
+ int error, ifd, fd, wd;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ wd = watch_file(ifd, IN_ATTRIB, path);
+
+ fd = open(path, O_RDWR);
+ ATF_REQUIRE(fd != -1);
+ error = fchmod(fd, 0600);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_ATTRIB, 0, NULL);
+
+ error = fchown(fd, getuid(), getgid());
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_ATTRIB, 0, NULL);
+
+ close_checked(fd);
+ close_inotify(ifd);
+}
+
+ATF_TC_WITHOUT_HEAD(inotify_event_close_nowrite);
+ATF_TC_BODY(inotify_event_close_nowrite, tc)
+{
+ char file[PATH_MAX], file1[PATH_MAX], dir[PATH_MAX];
+ int ifd, fd, wd1, wd2;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ wd1 = watch_dir(ifd, IN_CLOSE_NOWRITE, dir);
+ wd2 = watch_file(ifd, IN_CLOSE_NOWRITE | IN_CLOSE_WRITE, file);
+
+ fd = open(dir, O_DIRECTORY);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ consume_event(ifd, wd1, IN_CLOSE_NOWRITE, IN_ISDIR, NULL);
+
+ fd = open(file, O_RDONLY);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ consume_event(ifd, wd2, IN_CLOSE_NOWRITE, 0, NULL);
+
+ snprintf(file1, sizeof(file1), "%s/file", dir);
+ fd = open(file1, O_RDONLY | O_CREAT, 0644);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ consume_event(ifd, wd1, IN_CLOSE_NOWRITE, 0, "file");
+
+ close_inotify(ifd);
+}
+
+ATF_TC_WITHOUT_HEAD(inotify_event_close_write);
+ATF_TC_BODY(inotify_event_close_write, tc)
+{
+ char path[PATH_MAX];
+ int ifd, fd, wd;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ wd = watch_file(ifd, IN_CLOSE_NOWRITE | IN_CLOSE_WRITE, path);
+
+ fd = open(path, O_RDWR);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ consume_event(ifd, wd, IN_CLOSE_WRITE, 0, NULL);
+
+ close_inotify(ifd);
+}
+
+/* Verify that various operations in a directory generate IN_CREATE events. */
+ATF_TC_WITHOUT_HEAD(inotify_event_create);
+ATF_TC_BODY(inotify_event_create, tc)
+{
+ struct sockaddr_un sun;
+ char path[PATH_MAX], path1[PATH_MAX], root[PATH_MAX];
+ ssize_t n;
+ int error, ifd, ifd1, fd, s, wd, wd1;
+ char b;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ wd = watch_dir(ifd, IN_CREATE, root);
+
+ /* Regular file. */
+ snprintf(path, sizeof(path), "%s/file", root);
+ fd = open(path, O_RDWR | O_CREAT, 0644);
+ ATF_REQUIRE(fd != -1);
+ /*
+ * Make sure we get an event triggered by the fd used to create the
+ * file.
+ */
+ ifd1 = inotify(IN_NONBLOCK);
+ wd1 = inotify_add_watch(ifd1, root, IN_MODIFY);
+ b = 42;
+ n = write(fd, &b, sizeof(b));
+ ATF_REQUIRE(n == sizeof(b));
+ close_checked(fd);
+ consume_event(ifd, wd, IN_CREATE, 0, "file");
+ consume_event(ifd1, wd1, IN_MODIFY, 0, "file");
+ close_inotify(ifd1);
+
+ /* Hard link. */
+ snprintf(path1, sizeof(path1), "%s/link", root);
+ error = link(path, path1);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_CREATE, 0, "link");
+
+ /* Directory. */
+ snprintf(path, sizeof(path), "%s/dir", root);
+ error = mkdir(path, 0755);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_CREATE, IN_ISDIR, "dir");
+
+ /* Symbolic link. */
+ snprintf(path1, sizeof(path1), "%s/symlink", root);
+ error = symlink(path, path1);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_CREATE, 0, "symlink");
+
+ /* FIFO. */
+ snprintf(path, sizeof(path), "%s/fifo", root);
+ error = mkfifo(path, 0644);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_CREATE, 0, "fifo");
+
+ /* Binding a socket. */
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ sun.sun_len = sizeof(sun);
+ snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/socket", root);
+ error = bind(s, (struct sockaddr *)&sun, sizeof(sun));
+ ATF_REQUIRE(error == 0);
+ close_checked(s);
+ consume_event(ifd, wd, IN_CREATE, 0, "socket");
+
+ close_inotify(ifd);
+}
+
+ATF_TC_WITHOUT_HEAD(inotify_event_delete);
+ATF_TC_BODY(inotify_event_delete, tc)
+{
+ char root[PATH_MAX], path[PATH_MAX], file[PATH_MAX];
+ int error, fd, ifd, wd, wd2;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ wd = watch_dir(ifd, IN_DELETE | IN_DELETE_SELF, root);
+
+ snprintf(path, sizeof(path), "%s/file", root);
+ fd = open(path, O_RDWR | O_CREAT, 0644);
+ ATF_REQUIRE(fd != -1);
+ error = unlink(path);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_DELETE, 0, "file");
+ close_checked(fd);
+
+ /*
+ * Make sure that renaming over a file generates a delete event when and
+ * only when that file is watched.
+ */
+ fd = open(path, O_RDWR | O_CREAT, 0644);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ wd2 = inotify_add_watch(ifd, path, IN_DELETE | IN_DELETE_SELF);
+ ATF_REQUIRE(wd2 != -1);
+ snprintf(file, sizeof(file), "%s/file2", root);
+ fd = open(file, O_RDWR | O_CREAT, 0644);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ error = rename(file, path);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd2, IN_DELETE_SELF, 0, NULL);
+ consume_event(ifd, wd2, 0, IN_IGNORED, NULL);
+
+ error = unlink(path);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_DELETE, 0, "file");
+ error = rmdir(root);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd, IN_DELETE_SELF, IN_ISDIR, NULL);
+ consume_event(ifd, wd, 0, IN_IGNORED, NULL);
+
+ close_inotify(ifd);
+}
+
+ATF_TC_WITHOUT_HEAD(inotify_event_move);
+ATF_TC_BODY(inotify_event_move, tc)
+{
+ char dir1[PATH_MAX], dir2[PATH_MAX], path1[PATH_MAX], path2[PATH_MAX];
+ char path3[PATH_MAX];
+ int error, ifd, fd, wd1, wd2, wd3;
+ uint32_t cookie1, cookie2;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ wd1 = watch_dir(ifd, IN_MOVE | IN_MOVE_SELF, dir1);
+ wd2 = watch_dir(ifd, IN_MOVE | IN_MOVE_SELF, dir2);
+
+ snprintf(path1, sizeof(path1), "%s/file", dir1);
+ fd = open(path1, O_RDWR | O_CREAT, 0644);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ snprintf(path2, sizeof(path2), "%s/file2", dir2);
+ error = rename(path1, path2);
+ ATF_REQUIRE(error == 0);
+ cookie1 = consume_event_cookie(ifd, wd1, IN_MOVED_FROM, 0, "file");
+ cookie2 = consume_event_cookie(ifd, wd2, IN_MOVED_TO, 0, "file2");
+ ATF_REQUIRE_MSG(cookie1 == cookie2,
+ "expected cookie %u, got %u", cookie1, cookie2);
+
+ snprintf(path2, sizeof(path2), "%s/dir", dir2);
+ error = rename(dir1, path2);
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd1, IN_MOVE_SELF, IN_ISDIR, NULL);
+ consume_event(ifd, wd2, IN_MOVED_TO, IN_ISDIR, "dir");
+
+ wd3 = watch_file(ifd, IN_MOVE_SELF, path3);
+ error = rename(path3, "foo");
+ ATF_REQUIRE(error == 0);
+ consume_event(ifd, wd3, IN_MOVE_SELF, 0, NULL);
+
+ close_inotify(ifd);
+}
+
+ATF_TC_WITHOUT_HEAD(inotify_event_open);
+ATF_TC_BODY(inotify_event_open, tc)
+{
+ char root[PATH_MAX], path[PATH_MAX];
+ int error, ifd, fd, wd;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ wd = watch_dir(ifd, IN_OPEN, root);
+
+ snprintf(path, sizeof(path), "%s/file", root);
+ fd = open(path, O_RDWR | O_CREAT, 0644);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ consume_event(ifd, wd, IN_OPEN, 0, "file");
+
+ fd = open(path, O_PATH);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ consume_event(ifd, wd, IN_OPEN, 0, "file");
+
+ fd = open(root, O_DIRECTORY);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ consume_event(ifd, wd, IN_OPEN, IN_ISDIR, NULL);
+
+ snprintf(path, sizeof(path), "%s/fifo", root);
+ error = mkfifo(path, 0644);
+ ATF_REQUIRE(error == 0);
+ fd = open(path, O_RDWR);
+ ATF_REQUIRE(fd != -1);
+ close_checked(fd);
+ consume_event(ifd, wd, IN_OPEN, 0, "fifo");
+
+ close_inotify(ifd);
+}
+
+ATF_TC_WITH_CLEANUP(inotify_event_unmount);
+ATF_TC_HEAD(inotify_event_unmount, tc)
+{
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(inotify_event_unmount, tc)
+{
+ int error, fd, ifd, wd;
+
+ ifd = inotify(IN_NONBLOCK);
+
+ error = mkdir("./root", 0755);
+ ATF_REQUIRE(error == 0);
+
+ mount_tmpfs("./root");
+
+ error = mkdir("./root/dir", 0755);
+ ATF_REQUIRE(error == 0);
+ wd = inotify_add_watch(ifd, "./root/dir", IN_OPEN);
+ ATF_REQUIRE(wd >= 0);
+
+ fd = open("./root/dir", O_RDONLY | O_DIRECTORY);
+ ATF_REQUIRE(fd != -1);
+ consume_event(ifd, wd, IN_OPEN, IN_ISDIR, NULL);
+ close_checked(fd);
+
+ /* A regular unmount should fail, as inotify holds a vnode reference. */
+ error = unmount("./root", 0);
+ ATF_REQUIRE_ERRNO(EBUSY, error == -1);
+ error = unmount("./root", MNT_FORCE);
+ ATF_REQUIRE_MSG(error == 0,
+ "unmounting ./root failed: %s", strerror(errno));
+
+ consume_event(ifd, wd, 0, IN_UNMOUNT, NULL);
+ consume_event(ifd, wd, 0, IN_IGNORED, NULL);
+
+ close_inotify(ifd);
+}
+ATF_TC_CLEANUP(inotify_event_unmount, tc)
+{
+ (void)unmount("./root", MNT_FORCE);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ /* Tests for the inotify syscalls. */
+ ATF_TP_ADD_TC(tp, inotify_capsicum);
+ ATF_TP_ADD_TC(tp, inotify_coalesce);
+ ATF_TP_ADD_TC(tp, inotify_mask_create);
+ ATF_TP_ADD_TC(tp, inotify_nullfs);
+ ATF_TP_ADD_TC(tp, inotify_queue_overflow);
+ /* Tests for the various inotify event types. */
+ ATF_TP_ADD_TC(tp, inotify_event_access_file);
+ ATF_TP_ADD_TC(tp, inotify_event_access_dir);
+ ATF_TP_ADD_TC(tp, inotify_event_attrib);
+ ATF_TP_ADD_TC(tp, inotify_event_close_nowrite);
+ ATF_TP_ADD_TC(tp, inotify_event_close_write);
+ ATF_TP_ADD_TC(tp, inotify_event_create);
+ ATF_TP_ADD_TC(tp, inotify_event_delete);
+ ATF_TP_ADD_TC(tp, inotify_event_move);
+ ATF_TP_ADD_TC(tp, inotify_event_open);
+ ATF_TP_ADD_TC(tp, inotify_event_unmount);
+ return (atf_no_error());
+}
diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c
index 95271c04a16b..7dc4541ad402 100644
--- a/tests/sys/kern/unix_passfd_test.c
+++ b/tests/sys/kern/unix_passfd_test.c
@@ -380,6 +380,30 @@ ATF_TC_BODY(simple_send_fd_msg_cmsg_cloexec, tc)
}
/*
+ * Like simple_send_fd but also sets MSG_CMSG_CLOFORK and checks that the
+ * received file descriptor has the FD_CLOFORK flag set.
+ */
+ATF_TC_WITHOUT_HEAD(simple_send_fd_msg_cmsg_clofork);
+ATF_TC_BODY(simple_send_fd_msg_cmsg_clofork, tc)
+{
+ struct stat getfd_stat, putfd_stat;
+ int fd[2], getfd, putfd;
+
+ domainsocketpair(fd);
+ tempfile(&putfd);
+ dofstat(putfd, &putfd_stat);
+ sendfd(fd[0], putfd);
+ recvfd(fd[1], &getfd, MSG_CMSG_CLOFORK);
+ dofstat(getfd, &getfd_stat);
+ samefile(&putfd_stat, &getfd_stat);
+ ATF_REQUIRE_EQ_MSG(fcntl(getfd, F_GETFD) & FD_CLOFORK, FD_CLOFORK,
+ "FD_CLOFORK not set on the received file descriptor");
+ close(putfd);
+ close(getfd);
+ closesocketpair(fd);
+}
+
+/*
* Same as simple_send_fd, only close the file reference after sending, so that
* the only reference is the descriptor in the UNIX domain socket buffer.
*/
@@ -1170,6 +1194,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, simple_send_fd);
ATF_TP_ADD_TC(tp, simple_send_fd_msg_cmsg_cloexec);
+ ATF_TP_ADD_TC(tp, simple_send_fd_msg_cmsg_clofork);
ATF_TP_ADD_TC(tp, send_and_close);
ATF_TP_ADD_TC(tp, send_and_cancel);
ATF_TP_ADD_TC(tp, send_and_shutdown);
diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh
index 2c6b039048e3..cc0b212aebd2 100755
--- a/tests/sys/net/if_bridge_test.sh
+++ b/tests/sys/net/if_bridge_test.sh
@@ -829,6 +829,398 @@ member_ifaddrs_vlan_cleanup()
vnet_cleanup
}
+atf_test_case "vlan_pvid" "cleanup"
+vlan_pvid_head()
+{
+ atf_set descr 'bridge with two ports with pvid set'
+ atf_set require.user root
+}
+
+vlan_pvid_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ epone=$(vnet_mkepair)
+ eptwo=$(vnet_mkepair)
+
+ vnet_mkjail one ${epone}b
+ vnet_mkjail two ${eptwo}b
+
+ jexec one ifconfig ${epone}b 192.0.2.1/24 up
+ jexec two ifconfig ${eptwo}b 192.0.2.2/24 up
+
+ bridge=$(vnet_mkbridge)
+
+ ifconfig ${bridge} up
+ ifconfig ${epone}a up
+ ifconfig ${eptwo}a up
+ ifconfig ${bridge} addm ${epone}a untagged ${epone}a 20
+ ifconfig ${bridge} addm ${eptwo}a untagged ${eptwo}a 20
+
+ # With VLAN filtering enabled, traffic should be passed.
+ atf_check -s exit:0 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:0 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+
+ # Removed the untagged VLAN on one port; traffic should not be passed.
+ ifconfig ${bridge} -untagged ${epone}a
+ atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+}
+
+vlan_pvid_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "vlan_pvid_filtered" "cleanup"
+vlan_pvid_filtered_head()
+{
+ atf_set descr 'bridge with two ports with different pvids'
+ atf_set require.user root
+}
+
+vlan_pvid_filtered_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ epone=$(vnet_mkepair)
+ eptwo=$(vnet_mkepair)
+
+ vnet_mkjail one ${epone}b
+ vnet_mkjail two ${eptwo}b
+
+ jexec one ifconfig ${epone}b 192.0.2.1/24 up
+ jexec two ifconfig ${eptwo}b 192.0.2.2/24 up
+
+ bridge=$(vnet_mkbridge)
+
+ ifconfig ${bridge} up
+ ifconfig ${epone}a up
+ ifconfig ${eptwo}a up
+ ifconfig ${bridge} addm ${epone}a untagged ${epone}a 20
+ ifconfig ${bridge} addm ${eptwo}a untagged ${eptwo}a 30
+
+ atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+}
+
+vlan_pvid_filtered_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "vlan_pvid_tagged" "cleanup"
+vlan_pvid_tagged_head()
+{
+ atf_set descr 'bridge pvid with tagged frames for pvid'
+ atf_set require.user root
+}
+
+vlan_pvid_tagged_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ epone=$(vnet_mkepair)
+ eptwo=$(vnet_mkepair)
+
+ vnet_mkjail one ${epone}b
+ vnet_mkjail two ${eptwo}b
+
+ # Create two tagged interfaces on the appropriate VLANs
+ jexec one ifconfig ${epone}b up
+ jexec one ifconfig ${epone}b.20 create 192.0.2.1/24 up
+ jexec two ifconfig ${eptwo}b up
+ jexec two ifconfig ${eptwo}b.20 create 192.0.2.2/24 up
+
+ bridge=$(vnet_mkbridge)
+
+ ifconfig ${bridge} up
+ ifconfig ${epone}a up
+ ifconfig ${eptwo}a up
+ ifconfig ${bridge} addm ${epone}a untagged ${epone}a 20
+ ifconfig ${bridge} addm ${eptwo}a untagged ${eptwo}a 20
+
+ # Tagged frames should not be passed.
+ atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+}
+
+vlan_pvid_tagged_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "vlan_pvid_1q" "cleanup"
+vlan_pvid_1q_head()
+{
+ atf_set descr '802.1q tag addition and removal'
+ atf_set require.user root
+}
+
+vlan_pvid_1q_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ epone=$(vnet_mkepair)
+ eptwo=$(vnet_mkepair)
+
+ vnet_mkjail one ${epone}b
+ vnet_mkjail two ${eptwo}b
+
+ # Set up one jail with an access port, and the other with a trunk port.
+ # This forces the bridge to add and remove .1q tags to bridge the
+ # traffic.
+
+ jexec one ifconfig ${epone}b 192.0.2.1/24 up
+ jexec two ifconfig ${eptwo}b up
+ jexec two ifconfig ${eptwo}b.20 create 192.0.2.2/24 up
+
+ bridge=$(vnet_mkbridge)
+
+ ifconfig ${bridge} addm ${epone}a untagged ${epone}a 20
+ ifconfig ${bridge} addm ${eptwo}a
+
+ ifconfig ${bridge} up
+ ifconfig ${epone}a up
+ ifconfig ${eptwo}a up
+
+ atf_check -s exit:0 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:0 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+}
+
+vlan_pvid_1q_cleanup()
+{
+ vnet_cleanup
+}
+
+#
+# Test vlan filtering.
+#
+atf_test_case "vlan_filtering" "cleanup"
+vlan_filtering_head()
+{
+ atf_set descr 'tagged traffic with filtering'
+ atf_set require.user root
+}
+
+vlan_filtering_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ epone=$(vnet_mkepair)
+ eptwo=$(vnet_mkepair)
+
+ vnet_mkjail one ${epone}b
+ vnet_mkjail two ${eptwo}b
+
+ jexec one ifconfig ${epone}b up
+ jexec one ifconfig ${epone}b.20 create 192.0.2.1/24 up
+ jexec two ifconfig ${eptwo}b up
+ jexec two ifconfig ${eptwo}b.20 create 192.0.2.2/24 up
+
+ bridge=$(vnet_mkbridge)
+
+ ifconfig ${bridge} up
+ ifconfig ${epone}a up
+ ifconfig ${eptwo}a up
+ ifconfig ${bridge} addm ${epone}a vlanfilter ${epone}a
+ ifconfig ${bridge} addm ${eptwo}a vlanfilter ${eptwo}a
+
+ # Right now there are no VLANs on the access list, so everything
+ # should be blocked.
+ atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+
+ # Set the untagged vlan on both ports to 20 and make sure traffic is
+ # still blocked. We intentionally do not pass tagged traffic for the
+ # untagged vlan.
+ atf_check -s exit:0 ifconfig ${bridge} untagged ${epone}a 20
+ atf_check -s exit:0 ifconfig ${bridge} untagged ${eptwo}a 20
+
+ atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+
+ atf_check -s exit:0 ifconfig ${bridge} -untagged ${epone}a
+ atf_check -s exit:0 ifconfig ${bridge} -untagged ${eptwo}a
+
+ # Add VLANs 10-30 to the access list; now access should be allowed.
+ ifconfig ${bridge} +tagged ${epone}a 10-30
+ ifconfig ${bridge} +tagged ${eptwo}a 10-30
+ atf_check -s exit:0 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:0 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+
+ # Remove vlan 20 from the access list, now access should be blocked
+ # again.
+ ifconfig ${bridge} -tagged ${epone}a 20
+ ifconfig ${bridge} -tagged ${eptwo}a 20
+ atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+}
+
+vlan_filtering_cleanup()
+{
+ vnet_cleanup
+}
+
+#
+# Test the ifconfig 'tagged' option.
+#
+atf_test_case "vlan_ifconfig_tagged" "cleanup"
+vlan_ifconfig_tagged_head()
+{
+ atf_set descr 'test the ifconfig tagged option'
+ atf_set require.user root
+}
+
+vlan_ifconfig_tagged_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ ep=$(vnet_mkepair)
+ bridge=$(vnet_mkbridge)
+
+ ifconfig ${bridge} addm ${ep}a vlanfilter ${ep}a up
+ ifconfig ${ep}a up
+
+ # To start with, no vlans should be configured.
+ atf_check -s exit:0 -o not-match:"tagged" ifconfig ${bridge}
+
+ # Add vlans 100-149.
+ atf_check -s exit:0 ifconfig ${bridge} tagged ${ep}a 100-149
+ atf_check -s exit:0 -o match:"tagged 100-149" ifconfig ${bridge}
+
+ # Replace the vlan list with 139-199.
+ atf_check -s exit:0 ifconfig ${bridge} tagged ${ep}a 139-199
+ atf_check -s exit:0 -o match:"tagged 139-199" ifconfig ${bridge}
+
+ # Add vlans 100-170.
+ atf_check -s exit:0 ifconfig ${bridge} +tagged ${ep}a 100-170
+ atf_check -s exit:0 -o match:"tagged 100-199" ifconfig ${bridge}
+
+ # Remove vlans 104, 105, and 150-159
+ atf_check -s exit:0 ifconfig ${bridge} -tagged ${ep}a 104,105,150-159
+ atf_check -s exit:0 -o match:"tagged 100-103,106-149,160-199" \
+ ifconfig ${bridge}
+
+ # Remove the entire vlan list.
+ atf_check -s exit:0 ifconfig ${bridge} tagged ${ep}a none
+ atf_check -s exit:0 -o not-match:"tagged" ifconfig ${bridge}
+
+ # Test some invalid vlans sets.
+ for bad_vlan in -1 0 4096 4097 foo 0-10 4000-5000 foo-40 40-foo; do
+ atf_check -s exit:1 -e ignore \
+ ifconfig ${bridge} tagged "$bad_vlan"
+ done
+}
+
+vlan_ifconfig_tagged_cleanup()
+{
+ vnet_cleanup
+}
+
+#
+# Test a vlan(4) "SVI" interface on top of a bridge.
+#
+atf_test_case "vlan_svi" "cleanup"
+vlan_svi_head()
+{
+ atf_set descr 'vlan bridge with an SVI'
+ atf_set require.user root
+}
+
+vlan_svi_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ epone=$(vnet_mkepair)
+
+ vnet_mkjail one ${epone}b
+
+ jexec one ifconfig ${epone}b up
+ jexec one ifconfig ${epone}b.20 create 192.0.2.1/24 up
+
+ bridge=$(vnet_mkbridge)
+
+ ifconfig ${bridge} up
+ ifconfig ${epone}a up
+ ifconfig ${bridge} addm ${epone}a tagged ${epone}a 20
+
+ svi=$(vnet_mkvlan)
+ ifconfig ${svi} vlan 20 vlandev ${bridge}
+ ifconfig ${svi} inet 192.0.2.2/24 up
+
+ atf_check -s exit:0 -o ignore ping -c 3 -t 1 192.0.2.1
+}
+
+vlan_svi_cleanup()
+{
+ vnet_cleanup
+}
+
+#
+# Test QinQ (802.1ad).
+#
+atf_test_case "vlan_qinq" "cleanup"
+vlan_qinq_head()
+{
+ atf_set descr 'vlan filtering with QinQ traffic'
+ atf_set require.user root
+}
+
+vlan_qinq_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ epone=$(vnet_mkepair)
+ eptwo=$(vnet_mkepair)
+
+ vnet_mkjail one ${epone}b
+ vnet_mkjail two ${eptwo}b
+
+ # Create a QinQ trunk between the two jails. The outer (provider) tag
+ # is 5, and the inner tag is 10.
+
+ jexec one ifconfig ${epone}b up
+ jexec one ifconfig ${epone}b.5 create vlanproto 802.1ad up
+ jexec one ifconfig ${epone}b.5.10 create inet 192.0.2.1/24 up
+
+ jexec two ifconfig ${eptwo}b up
+ jexec two ifconfig ${eptwo}b.5 create vlanproto 802.1ad up
+ jexec two ifconfig ${eptwo}b.5.10 create inet 192.0.2.2/24 up
+
+ bridge=$(vnet_mkbridge)
+
+ ifconfig ${bridge} up
+ ifconfig ${epone}a up
+ ifconfig ${eptwo}a up
+ ifconfig ${bridge} addm ${epone}a vlanfilter ${epone}a
+ ifconfig ${bridge} addm ${eptwo}a vlanfilter ${eptwo}a
+
+ # Right now there are no VLANs on the access list, so everything
+ # should be blocked.
+ atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+
+ # Add the provider tag to the access list; now traffic should be passed.
+ ifconfig ${bridge} +tagged ${epone}a 5
+ ifconfig ${bridge} +tagged ${eptwo}a 5
+ atf_check -s exit:0 -o ignore jexec one ping -c 3 -t 1 192.0.2.2
+ atf_check -s exit:0 -o ignore jexec two ping -c 3 -t 1 192.0.2.1
+}
+
+vlan_qinq_cleanup()
+{
+ vnet_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "bridge_transmit_ipv4_unicast"
@@ -847,4 +1239,12 @@ atf_init_test_cases()
atf_add_test_case "member_ifaddrs_enabled"
atf_add_test_case "member_ifaddrs_disabled"
atf_add_test_case "member_ifaddrs_vlan"
+ atf_add_test_case "vlan_pvid"
+ atf_add_test_case "vlan_pvid_1q"
+ atf_add_test_case "vlan_pvid_filtered"
+ atf_add_test_case "vlan_pvid_tagged"
+ atf_add_test_case "vlan_filtering"
+ atf_add_test_case "vlan_ifconfig_tagged"
+ atf_add_test_case "vlan_svi"
+ atf_add_test_case "vlan_qinq"
}
diff --git a/tests/sys/netinet6/addr6.sh b/tests/sys/netinet6/addr6.sh
index 38e4bb152240..6fd66d5aa0c7 100755
--- a/tests/sys/netinet6/addr6.sh
+++ b/tests/sys/netinet6/addr6.sh
@@ -39,7 +39,32 @@ addr6_invalid_addr_cleanup()
vnet_cleanup
}
+atf_test_case "anycast_raw_addr" "cleanup"
+anycast_raw_addr_head()
+{
+ atf_set descr "a raw socket can bind to an anycast address"
+ atf_set require.user root
+}
+
+anycast_raw_addr_body()
+{
+ # lo0 needs to be up in the test jail for this test to work
+ ifconfig lo0 up
+
+ netif=$(ifconfig lo create)
+ echo $netif >netif
+ atf_check -s exit:0 ifconfig $netif inet6 2001:db8::1/128 up
+ atf_check -s exit:0 ifconfig $netif inet6 2001:db8::2/128 anycast
+ atf_check -s exit:0 -o ignore ping -c1 -S 2001:db8::2 2001:db8::1
+}
+
+anycast_raw_addr_cleanup()
+{
+ ifconfig $(cat netif) destroy
+}
+
atf_init_test_cases()
{
atf_add_test_case "addr6_invalid_addr"
+ atf_add_test_case "anycast_raw_addr"
}
diff --git a/tests/sys/netpfil/pf/anchor.sh b/tests/sys/netpfil/pf/anchor.sh
index b4b52d7a24d6..64ca84b34c3d 100644
--- a/tests/sys/netpfil/pf/anchor.sh
+++ b/tests/sys/netpfil/pf/anchor.sh
@@ -350,9 +350,9 @@ nat_body()
jexec alcatraz pfctl -sn -a "foo/bar"
jexec alcatraz pfctl -sn -a "foo/baz"
- atf_check -s exit:0 -o match:"nat log on epair0a inet from 192.0.2.0/24 to any port = domain -> 192.0.2.1" \
+ atf_check -s exit:0 -o match:"nat log on ${epair}a inet from 192.0.2.0/24 to any port = domain -> 192.0.2.1" \
jexec alcatraz pfctl -sn -a "*"
- atf_check -s exit:0 -o match:"rdr on epair0a inet proto tcp from any to any port = echo -> 127.0.0.1 port 7" \
+ atf_check -s exit:0 -o match:"rdr on ${epair}a inet proto tcp from any to any port = echo -> 127.0.0.1 port 7" \
jexec alcatraz pfctl -sn -a "*"
}
@@ -437,6 +437,62 @@ quick_cleanup()
pft_cleanup
}
+atf_test_case "recursive_flush" "cleanup"
+recursive_flush_head()
+{
+ atf_set descr 'Test recursive flushing of rules'
+ atf_set require.user root
+}
+
+recursive_flush_body()
+{
+ pft_init
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail alcatraz ${epair}a
+
+ ifconfig ${epair}b 192.0.2.2/24 up
+ jexec alcatraz ifconfig ${epair}a 192.0.2.1/24 up
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
+
+ jexec alcatraz pfctl -e
+ pft_set_rules alcatraz \
+ "block" \
+ "anchor \"foo\" {\n\
+ pass\n\
+ }"
+
+ # We can ping thanks to the pass rule in foo
+ atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
+
+ # Only reset the main rules. I.e. not a recursive flush
+ pft_set_rules alcatraz \
+ "block" \
+ "anchor \"foo\""
+
+ # "foo" still has the pass rule, so this works
+ jexec alcatraz pfctl -a "*" -sr
+ atf_check -s exit:0 -o ignore ping -c 1 192.0.2.1
+
+ # Now do a recursive flush
+ atf_check -s exit:0 -e ignore -o ignore \
+ jexec alcatraz pfctl -a "*" -Fr
+ pft_set_rules alcatraz \
+ "block" \
+ "anchor \"foo\""
+
+ # So this fails
+ jexec alcatraz pfctl -a "*" -sr
+ atf_check -s exit:2 -o ignore ping -c 1 192.0.2.1
+}
+
+recursive_flush_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "pr183198"
@@ -450,4 +506,5 @@ atf_init_test_cases()
atf_add_test_case "nat"
atf_add_test_case "include"
atf_add_test_case "quick"
+ atf_add_test_case "recursive_flush"
}
diff --git a/tests/sys/netpfil/pf/debug.sh b/tests/sys/netpfil/pf/debug.sh
index 18a7febfbb5b..404d37ab8932 100644
--- a/tests/sys/netpfil/pf/debug.sh
+++ b/tests/sys/netpfil/pf/debug.sh
@@ -50,7 +50,57 @@ basic_cleanup()
pft_cleanup
}
+atf_test_case "reset" "cleanup"
+reset_head()
+{
+ atf_set descr 'Test resetting debug level'
+ atf_set require.user root
+}
+
+reset_body()
+{
+ pft_init
+
+ vnet_mkjail debug
+
+ # Default is Urgent
+ atf_check -s exit:0 -o match:'Debug: Urgent' \
+ jexec debug pfctl -sa
+ state_limit=$(jexec debug pfctl -sa | grep 'states.*hard limit' | awk '{ print $4; }')
+
+ # Change defaults
+ pft_set_rules debug \
+ "set limit states 42"
+ atf_check -s exit:0 -e ignore \
+ jexec debug pfctl -x loud
+
+ atf_check -s exit:0 -o match:'Debug: Loud' \
+ jexec debug pfctl -sa
+ new_state_limit=$(jexec debug pfctl -sa | grep 'states.*hard limit' | awk '{ print $4; }')
+ if [ $state_limit -eq $new_state_limit ]; then
+ jexec debug pfctl -sa
+ atf_fail "Failed to change state limit"
+ fi
+
+ # Reset
+ atf_check -s exit:0 -o ignore -e ignore \
+ jexec debug pfctl -FR
+ atf_check -s exit:0 -o match:'Debug: Urgent' \
+ jexec debug pfctl -sa
+ new_state_limit=$(jexec debug pfctl -sa | grep 'states.*hard limit' | awk '{ print $4; }')
+ if [ $state_limit -ne $new_state_limit ]; then
+ jexec debug pfctl -sa
+ atf_fail "Failed to reset state limit"
+ fi
+}
+
+reset_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "basic"
+ atf_add_test_case "reset"
}
diff --git a/tests/sys/netpfil/pf/header.py b/tests/sys/netpfil/pf/header.py
index 6832cfe6d42b..a5e36bc85d14 100644
--- a/tests/sys/netpfil/pf/header.py
+++ b/tests/sys/netpfil/pf/header.py
@@ -53,10 +53,9 @@ class TestHeader(VnetTestTemplate):
def test_too_many(self):
"Verify that we drop packets with silly numbers of headers."
- sendif = self.vnet.iface_alias_map["if1"].name
+ sendif = self.vnet.iface_alias_map["if1"]
recvif = self.vnet.iface_alias_map["if2"].name
- gw_mac = ToolsHelper.get_output("/sbin/ifconfig %s ether | awk '/ether/ { print $2; }'" % sendif)
- gw_mac = re.sub("0a$", "0b", gw_mac)
+ gw_mac = sendif.epairb.ether
ToolsHelper.print_output("/sbin/route add default 192.0.2.1")
@@ -67,7 +66,7 @@ class TestHeader(VnetTestTemplate):
pkt = sp.Ether(dst=gw_mac) \
/ sp.IP(dst="198.51.100.3") \
/ sp.ICMP(type='echo-request')
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
@@ -89,7 +88,7 @@ class TestHeader(VnetTestTemplate):
pkt = pkt / sp.AH(nh=51, payloadlen=1)
pkt = pkt / sp.AH(nh=1, payloadlen=1) / sp.ICMP(type='echo-request')
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
found = False
@@ -109,7 +108,7 @@ class TestHeader(VnetTestTemplate):
pkt = pkt / sp.AH(nh=51, payloadlen=1)
pkt = pkt / sp.AH(nh=1, payloadlen=1) / sp.ICMP(type='echo-request')
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
@@ -148,10 +147,10 @@ class TestHeader6(VnetTestTemplate):
"Verify that we drop packets with silly numbers of headers."
ToolsHelper.print_output("/sbin/ifconfig")
- sendif = self.vnet.iface_alias_map["if1"].name
+ sendif = self.vnet.iface_alias_map["if1"]
recvif = self.vnet.iface_alias_map["if2"].name
- our_mac = ToolsHelper.get_output("/sbin/ifconfig %s ether | awk '/ether/ { print $2; }'" % sendif)
- gw_mac = re.sub("0a$", "0b", our_mac)
+ our_mac = sendif.ether
+ gw_mac = sendif.epairb.ether
ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1")
@@ -162,7 +161,7 @@ class TestHeader6(VnetTestTemplate):
pkt = sp.Ether(src=our_mac, dst=gw_mac) \
/ sp.IPv6(src="2001:db8::2", dst="2001:db8:1::3") \
/ sp.ICMPv6EchoRequest()
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
@@ -182,7 +181,7 @@ class TestHeader6(VnetTestTemplate):
for i in range(0, 18):
pkt = pkt / sp.AH(nh=51, payloadlen=1)
pkt = pkt / sp.AH(nh=58, payloadlen=1) / sp.ICMPv6EchoRequest()
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
@@ -202,7 +201,7 @@ class TestHeader6(VnetTestTemplate):
for i in range(0, 19):
pkt = pkt / sp.AH(nh=51, payloadlen=1)
pkt = pkt / sp.AH(nh=58, payloadlen=1) / sp.ICMPv6EchoRequest()
- s = DelayedSend(pkt, sendif)
+ s = DelayedSend(pkt, sendif.name)
reply = sp.sniff(iface=recvif, timeout=3)
print(reply)
diff --git a/tests/sys/netpfil/pf/icmp.py b/tests/sys/netpfil/pf/icmp.py
index 83096886691e..59f2e8190b30 100644
--- a/tests/sys/netpfil/pf/icmp.py
+++ b/tests/sys/netpfil/pf/icmp.py
@@ -91,10 +91,10 @@ class TestICMP(VnetTestTemplate):
def test_inner_match(self):
vnet = self.vnet_map["vnet1"]
dst_vnet = self.vnet_map["vnet3"]
- sendif = vnet.iface_alias_map["if1"].name
+ sendif = vnet.iface_alias_map["if1"]
- our_mac = ToolsHelper.get_output("/sbin/ifconfig %s ether | awk '/ether/ { print $2; }'" % sendif)
- dst_mac = re.sub("0a$", "0b", our_mac)
+ our_mac = sendif.ether
+ dst_mac = sendif.epairb.ether
# Import in the correct vnet, so at to not confuse Scapy
import scapy.all as sp
@@ -111,7 +111,7 @@ class TestICMP(VnetTestTemplate):
/ sp.IP(src="192.0.2.2", dst="198.51.100.2") \
/ sp.ICMP(type='echo-request') \
/ "PAYLOAD"
- sp.sendp(pkt, sendif, verbose=False)
+ sp.sendp(pkt, sendif.name, verbose=False)
# Now try to pass an ICMP error message piggy-backing on that state, but
# use a different source address
@@ -120,7 +120,7 @@ class TestICMP(VnetTestTemplate):
/ sp.ICMP(type='dest-unreach') \
/ sp.IP(src="198.51.100.2", dst="192.0.2.2") \
/ sp.ICMP(type='echo-reply')
- sp.sendp(pkt, sendif, verbose=False)
+ sp.sendp(pkt, sendif.name, verbose=False)
try:
rcvd = self.wait_object(dst_vnet.pipe, timeout=1)
diff --git a/tests/sys/netpfil/pf/ioctl/validation.c b/tests/sys/netpfil/pf/ioctl/validation.c
index 1ce8999dcb91..18fafe11c6ab 100644
--- a/tests/sys/netpfil/pf/ioctl/validation.c
+++ b/tests/sys/netpfil/pf/ioctl/validation.c
@@ -32,6 +32,7 @@
#include <net/if.h>
#include <net/pfvar.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@@ -893,6 +894,39 @@ ATF_TC_CLEANUP(rpool_mtx2, tc)
COMMON_CLEANUP();
}
+ATF_TC_WITH_CLEANUP(natlook);
+ATF_TC_HEAD(natlook, tc)
+{
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+
+ATF_TC_BODY(natlook, tc)
+{
+ struct pfioc_natlook nl = { 0 };
+
+ COMMON_HEAD();
+
+ nl.af = AF_INET;
+ nl.proto = IPPROTO_ICMP;
+ nl.saddr.v4.s_addr = 0x01020304;
+ nl.daddr.v4.s_addr = 0x05060708;
+
+ /* Invalid direction */
+ nl.direction = 42;
+
+ ATF_CHECK_ERRNO(EINVAL, ioctl(dev, DIOCNATLOOK, &nl) == -1);
+
+ /* Invalid af */
+ nl.direction = PF_IN;
+ nl.af = 99;
+
+ ATF_CHECK_ERRNO(EAFNOSUPPORT, ioctl(dev, DIOCNATLOOK, &nl) == -1);
+}
+
+ATF_TC_CLEANUP(natlook, tc)
+{
+ COMMON_CLEANUP();
+}
ATF_TP_ADD_TCS(tp)
{
@@ -918,6 +952,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, tag);
ATF_TP_ADD_TC(tp, rpool_mtx);
ATF_TP_ADD_TC(tp, rpool_mtx2);
+ ATF_TP_ADD_TC(tp, natlook);
return (atf_no_error());
}
diff --git a/tests/sys/netpfil/pf/mbuf.sh b/tests/sys/netpfil/pf/mbuf.sh
index d845f793a969..e3f138bb73b9 100644
--- a/tests/sys/netpfil/pf/mbuf.sh
+++ b/tests/sys/netpfil/pf/mbuf.sh
@@ -105,6 +105,12 @@ inet6_in_mbuf_len_body()
epair=$(vnet_mkepair)
ifconfig ${epair}a inet6 2001:db8::1/64 up no_dad
+ # Ensure we don't unintentionally send MLD packets to alcatraz
+ pfctl -e
+ echo "block
+ pass out inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv, echoreq, echorep }
+ " | pfctl -g -f -
+
# Set up a simple jail with one interface
vnet_mkjail alcatraz ${epair}b
jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 up no_dad
diff --git a/tests/sys/netpfil/pf/nat.sh b/tests/sys/netpfil/pf/nat.sh
index f1fdf6405d97..16c981f97399 100644
--- a/tests/sys/netpfil/pf/nat.sh
+++ b/tests/sys/netpfil/pf/nat.sh
@@ -777,6 +777,38 @@ binat_match_cleanup()
kill $(cat ${PWD}/inetd_tester.pid)
}
+atf_test_case "empty_pool" "cleanup"
+empty_pool_head()
+{
+ atf_set descr 'NAT with empty pool'
+ atf_set require.user root
+}
+
+empty_pool_body()
+{
+ pft_init
+ setup_router_server_ipv6
+
+
+ pft_set_rules router \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
+ "pass in on ${epair_tester}b" \
+ "pass out on ${epair_server}a inet6 from any to ${net_server_host_server} nat-to <nonexistent>" \
+
+ # pf_map_addr_sn() won't be able to pick a target address, because
+ # the table used in redireciton pool is empty. Packet will not be
+ # forwarded, error counter will be increased.
+ ping_server_check_reply exit:1
+ # Ignore warnings about not-loaded ALTQ
+ atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null"
+}
+
+empty_pool_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "exhaust"
@@ -794,4 +826,5 @@ atf_init_test_cases()
atf_add_test_case "nat_match"
atf_add_test_case "binat_compat"
atf_add_test_case "binat_match"
+ atf_add_test_case "empty_pool"
}
diff --git a/tests/sys/netpfil/pf/nat64.py b/tests/sys/netpfil/pf/nat64.py
index adae2489ce5e..5cc4713a16cc 100644
--- a/tests/sys/netpfil/pf/nat64.py
+++ b/tests/sys/netpfil/pf/nat64.py
@@ -272,3 +272,18 @@ class TestNAT64(VnetTestTemplate):
reply = self.common_test_source_addr(packet)
icmp = reply.getlayer(sp.ICMPv6EchoRequest)
assert icmp
+
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_bad_len(self):
+ """
+ PR 288224: we can panic if the IPv6 plen is longer than the packet length.
+ """
+ ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1")
+ import scapy.all as sp
+
+ packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=2, plen=512) \
+ / sp.ICMPv6EchoRequest() / sp.Raw("foo")
+ reply = sp.sr1(packet, timeout=3)
+ # We don't expect a reply to a corrupted packet
+ assert not reply
diff --git a/tests/sys/netpfil/pf/pfsync.sh b/tests/sys/netpfil/pf/pfsync.sh
index 7f545b43a066..3be4a3024393 100644
--- a/tests/sys/netpfil/pf/pfsync.sh
+++ b/tests/sys/netpfil/pf/pfsync.sh
@@ -835,6 +835,90 @@ basic_ipv6_cleanup()
pfsynct_cleanup
}
+atf_test_case "rtable" "cleanup"
+rtable_head()
+{
+ atf_set descr 'Test handling of invalid rtableid'
+ atf_set require.user root
+}
+
+rtable_body()
+{
+ pfsynct_init
+
+ epair_sync=$(vnet_mkepair)
+ epair_one=$(vnet_mkepair)
+ epair_two=$(vnet_mkepair)
+
+ vnet_mkjail one ${epair_one}a ${epair_sync}a
+ vnet_mkjail two ${epair_two}a ${epair_sync}b
+
+ # pfsync interface
+ jexec one ifconfig ${epair_sync}a 192.0.2.1/24 up
+ jexec one ifconfig ${epair_one}a 198.51.100.1/24 up
+ jexec one ifconfig pfsync0 \
+ syncdev ${epair_sync}a \
+ maxupd 1 \
+ up
+ jexec two ifconfig ${epair_two}a 198.51.100.1/24 up
+ jexec two ifconfig ${epair_sync}b 192.0.2.2/24 up
+ jexec two ifconfig pfsync0 \
+ syncdev ${epair_sync}b \
+ maxupd 1 \
+ up
+
+ # Make life easy, give ${epair_two}a the same mac addrss as ${epair_one}a
+ mac=$(jexec one ifconfig ${epair_one}a | awk '/ether/ { print($2); }')
+ jexec two ifconfig ${epair_two}a ether ${mac}
+
+ # Enable pf!
+ jexec one /sbin/sysctl net.fibs=8
+ jexec one pfctl -e
+ pft_set_rules one \
+ "set skip on ${epair_sync}a" \
+ "pass rtable 3 keep state"
+ # No extra fibs in two
+ jexec two pfctl -e
+ pft_set_rules two \
+ "set skip on ${epair_sync}b" \
+ "pass keep state"
+
+ ifconfig ${epair_one}b 198.51.100.254/24 up
+ ifconfig ${epair_two}b 198.51.100.253/24 up
+
+ # Create a new state
+ env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --sendif ${epair_one}b \
+ --fromaddr 198.51.100.254 \
+ --to 198.51.100.1 \
+ --recvif ${epair_one}b
+
+ # Now
+ jexec one pfctl -ss -vv
+ sleep 2
+
+ # Now try to use that state on jail two
+ env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --sendif ${epair_two}b \
+ --fromaddr 198.51.100.254 \
+ --to 198.51.100.1 \
+ --recvif ${epair_two}b
+
+ echo one
+ jexec one pfctl -ss -vv
+ jexec one pfctl -sr -vv
+ echo two
+ jexec two pfctl -ss -vv
+ jexec two pfctl -sr -vv
+}
+
+rtable_cleanup()
+{
+ pfsynct_cleanup
+}
+
route_to_common_head()
{
pfsync_version=$1
@@ -1134,6 +1218,7 @@ atf_init_test_cases()
atf_add_test_case "timeout"
atf_add_test_case "basic_ipv6_unicast"
atf_add_test_case "basic_ipv6"
+ atf_add_test_case "rtable"
atf_add_test_case "route_to_1301"
atf_add_test_case "route_to_1301_bad_ruleset"
atf_add_test_case "route_to_1301_bad_rpool"
diff --git a/tests/sys/netpfil/pf/rdr.sh b/tests/sys/netpfil/pf/rdr.sh
index 4c08b4973891..f7c920bbfa8f 100644
--- a/tests/sys/netpfil/pf/rdr.sh
+++ b/tests/sys/netpfil/pf/rdr.sh
@@ -142,7 +142,7 @@ tcp_v6_pass_body()
{
tcp_v6_setup # Sets ${epair_…} variables
tcp_v6_common \
- "rdr on ${epair_one}a proto tcp from any to any port 80 -> 2001:db8:b::2 port 8000"
+ "pass in on ${epair_one}a proto tcp from any to any port 80 rdr-to 2001:db8:b::2 port 8000"
}
tcp_v6_pass_cleanup()
diff --git a/tests/sys/netpfil/pf/route_to.sh b/tests/sys/netpfil/pf/route_to.sh
index 5c0d355b8ea1..fd1653cce311 100644
--- a/tests/sys/netpfil/pf/route_to.sh
+++ b/tests/sys/netpfil/pf/route_to.sh
@@ -859,6 +859,121 @@ ttl_cleanup()
pft_cleanup
}
+
+atf_test_case "empty_pool" "cleanup"
+empty_pool_head()
+{
+ atf_set descr 'Route-to with empty pool'
+ atf_set require.user root
+}
+
+empty_pool_body()
+{
+ pft_init
+ setup_router_server_ipv6
+
+
+ pft_set_rules router \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
+ "pass in on ${epair_tester}b route-to (${epair_server}a <nonexistent>) inet6 from any to ${net_server_host_server}" \
+ "pass out on ${epair_server}a"
+
+ # pf_map_addr_sn() won't be able to pick a target address, because
+ # the table used in redireciton pool is empty. Packet will not be
+ # forwarded, error counter will be increased.
+ ping_server_check_reply exit:1
+ # Ignore warnings about not-loaded ALTQ
+ atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null"
+}
+
+empty_pool_cleanup()
+{
+ pft_cleanup
+}
+
+
+atf_test_case "table_loop" "cleanup"
+
+table_loop_head()
+{
+ atf_set descr 'Check that iterating over tables poperly loops'
+ atf_set require.user root
+}
+
+table_loop_body()
+{
+ setup_router_server_nat64
+
+ # Clients will connect from another network behind the router.
+ # This allows for using multiple source addresses.
+ jexec router route add -6 ${net_clients_6}::/${net_clients_6_mask} ${net_tester_6_host_tester}
+ jexec router route add ${net_clients_4}.0/${net_clients_4_mask} ${net_tester_4_host_tester}
+
+ # The servers are reachable over additional IP addresses for
+ # testing of tables and subnets. The addresses are noncontinougnus
+ # for pf_map_addr() counter tests.
+ for i in 0 1 4 5; do
+ a1=$((24 + i))
+ jexec server1 ifconfig ${epair_server1}b inet ${net_server1_4}.${a1}/32 alias
+ jexec server1 ifconfig ${epair_server1}b inet6 ${net_server1_6}::42:${i}/128 alias
+ a2=$((40 + i))
+ jexec server2 ifconfig ${epair_server2}b inet ${net_server2_4}.${a2}/32 alias
+ jexec server2 ifconfig ${epair_server2}b inet6 ${net_server2_6}::42:${i}/128 alias
+ done
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set debug loud" \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "table <rt_targets_1> { ${net_server1_6}::42:4/127 ${net_server1_6}::42:0/127 }" \
+ "table <rt_targets_2> { ${net_server2_6}::42:4/127 }" \
+ "pass in on ${epair_tester}b \
+ route-to { \
+ (${epair_server1}a <rt_targets_1>) \
+ (${epair_server2}a <rt_targets_2_empty>) \
+ (${epair_server2}a <rt_targets_2>) \
+ } \
+ inet6 proto tcp \
+ keep state"
+
+ # Both hosts of the pool are tables. Each table gets iterated over once,
+ # then the pool iterates to the next host, which is also iterated,
+ # then the pool loops back to the 1st host. If an empty table is found,
+ # it is skipped. Unless that's the only table, that is tested by
+ # the "empty_pool" test.
+ for port in $(seq 1 7); do
+ port=$((4200 + port))
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=${port}
+ done
+
+ states=$(mktemp) || exit 1
+ jexec router pfctl -qvvss | normalize_pfctl_s > $states
+ cat $states
+
+ for state_regexp in \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4201\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4202\] .* route-to: ${net_server1_6}::42:1@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4203\] .* route-to: ${net_server1_6}::42:4@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4204\] .* route-to: ${net_server1_6}::42:5@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4205\] .* route-to: ${net_server2_6}::42:4@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4206\] .* route-to: ${net_server2_6}::42:5@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4207\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \
+ ; do
+ grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
+ done
+}
+
+table_loop_cleanup()
+{
+ pft_cleanup
+}
+
+
atf_init_test_cases()
{
atf_add_test_case "v4"
@@ -877,4 +992,6 @@ atf_init_test_cases()
atf_add_test_case "dummynet_double"
atf_add_test_case "sticky"
atf_add_test_case "ttl"
+ atf_add_test_case "empty_pool"
+ atf_add_test_case "table_loop"
}
diff --git a/tests/sys/netpfil/pf/utils.subr b/tests/sys/netpfil/pf/utils.subr
index 6af10e80390d..3f8d437920f9 100644
--- a/tests/sys/netpfil/pf/utils.subr
+++ b/tests/sys/netpfil/pf/utils.subr
@@ -274,6 +274,107 @@ setup_router_server_ipv6()
jexec server inetd -p ${PWD}/inetd.pid $inetd_conf
}
+# Create a router and 2 server jails for nat64 and rfc5549 test cases.
+# The router is connected to servers, both are dual-stack, and to the
+# tester jail. All links are dual stack.
+setup_router_server_nat64()
+{
+ pft_init
+
+ epair_tester=$(vnet_mkepair)
+ epair_server1=$(vnet_mkepair)
+ epair_server2=$(vnet_mkepair)
+
+ # Funny how IPv4 address space is to small to even assign nice /24
+ # prefixes on all needed networks. On IPv6 we have a separate /64 for
+ # each link, loopback server, and client/SNAT pool. On IPv4 we must
+ # use small /28 prefixes, so even though we define all networks
+ # as variables we can't easily use them in tests if additional addresses
+ # are needed.
+
+ # IP addresses which can be used by the tester jail.
+ # Can be used as SNAT or as source with pft_ping.py. It is up to
+ # the test code to make them accessible from router.
+ net_clients_4=203.0.113
+ net_clients_4_mask=24
+ net_clients_6=2001:db8:44
+ net_clients_6_mask=64
+
+ # IP addresses on loopback interfaces of both servers. They can be
+ # accessed using the route-to targtet.
+ host_server_4=192.0.2.100
+ host_server_6=2001:db8:4203::100
+
+ net_tester_4=198.51.100
+ net_tester_4_mask=28
+ net_tester_4_host_router=198.51.100.1
+ net_tester_4_host_tester=198.51.100.2
+
+ net_tester_6=2001:db8:4200
+ net_tester_6_mask=64
+ net_tester_6_host_router=2001:db8:4200::1
+ net_tester_6_host_tester=2001:db8:4200::2
+
+ net_server1_4=198.51.100
+ net_server1_4_mask=28
+ net_server1_4_host_router=198.51.100.17
+ net_server1_4_host_server=198.51.100.18
+
+ net_server1_6=2001:db8:4201
+ net_server1_6_mask=64
+ net_server1_6_host_router=2001:db8:4201::1
+ net_server1_6_host_server=2001:db8:4201::2
+
+ net_server2_4=198.51.100
+ net_server2_4_mask=28
+ net_server2_4_host_router=198.51.100.33
+ net_server2_4_host_server=198.51.100.34
+
+ net_server2_6=2001:db8:4202
+ net_server2_6_mask=64
+ net_server2_6_host_router=2001:db8:4202::1
+ net_server2_6_host_server=2001:db8:4202::2
+
+ vnet_mkjail router ${epair_tester}b ${epair_server1}a ${epair_server2}a
+ jexec router ifconfig ${epair_tester}b inet ${net_tester_4_host_router}/${net_tester_4_mask} up
+ jexec router ifconfig ${epair_tester}b inet6 ${net_tester_6_host_router}/${net_tester_6_mask} up no_dad
+ jexec router ifconfig ${epair_server1}a inet ${net_server1_4_host_router}/${net_server1_4_mask} up
+ jexec router ifconfig ${epair_server1}a inet6 ${net_server1_6_host_router}/${net_server1_6_mask} up no_dad
+ jexec router ifconfig ${epair_server2}a inet ${net_server2_4_host_router}/${net_server2_4_mask} up
+ jexec router ifconfig ${epair_server2}a inet6 ${net_server2_6_host_router}/${net_server2_6_mask} up no_dad
+ jexec router sysctl net.inet.ip.forwarding=1
+ jexec router sysctl net.inet6.ip6.forwarding=1
+ jexec router pfctl -e
+
+ ifconfig ${epair_tester}a inet ${net_tester_4_host_tester}/${net_tester_4_mask} up
+ ifconfig ${epair_tester}a inet6 ${net_tester_6_host_tester}/${net_tester_6_mask} up no_dad
+ route add 0.0.0.0/0 ${net_tester_4_host_router}
+ route add -6 ::/0 ${net_tester_6_host_router}
+
+ inetd_conf=$(mktemp)
+ echo "discard stream tcp46 nowait root internal" >> $inetd_conf
+
+ vnet_mkjail server1 ${epair_server1}b
+ jexec server1 /etc/rc.d/netif start lo0
+ jexec server1 ifconfig ${epair_server1}b inet ${net_server1_4_host_server}/${net_server1_4_mask} up
+ jexec server1 ifconfig ${epair_server1}b inet6 ${net_server1_6_host_server}/${net_server1_6_mask} up no_dad
+ jexec server1 ifconfig lo0 ${host_server_4}/32 alias
+ jexec server1 ifconfig lo0 inet6 ${host_server_6}/128 alias
+ jexec server1 inetd -p ${PWD}/inetd_1.pid $inetd_conf
+ jexec server1 route add 0.0.0.0/0 ${net_server1_4_host_router}
+
+ jexec server1 route add -6 ::/0 ${net_server1_6_host_router}
+ vnet_mkjail server2 ${epair_server2}b
+ jexec server2 /etc/rc.d/netif start lo0
+ jexec server2 ifconfig ${epair_server2}b inet ${net_server2_4_host_server}/${net_server2_4_mask} up
+ jexec server2 ifconfig ${epair_server2}b inet6 ${net_server2_6_host_server}/${net_server2_6_mask} up no_dad
+ jexec server2 ifconfig lo0 ${host_server_4}/32 alias
+ jexec server2 ifconfig lo0 inet6 ${host_server_6}/128 alias
+ jexec server2 inetd -p ${PWD}/inetd_2.pid $inetd_conf
+ jexec server2 route add 0.0.0.0/0 ${net_server2_4_host_router}
+ jexec server2 route add -6 ::/0 ${net_server2_6_host_router}
+}
+
# Ping the dummy static NDP target.
# Check for pings being forwarded through the router towards the target.
ping_dummy_check_request()
diff --git a/tools/build/cross-build/include/common/exterr.h b/tools/build/cross-build/include/common/exterr.h
new file mode 100644
index 000000000000..62482841c7b2
--- /dev/null
+++ b/tools/build/cross-build/include/common/exterr.h
@@ -0,0 +1,14 @@
+#ifndef _EXTERR_H_
+#define _EXTERR_H_
+
+#include <sys/types.h>
+
+static inline int
+uexterr_gettext(char *buf, size_t bufsz)
+{
+ if (bufsz > 0)
+ buf[0] = '\0';
+ return (0);
+}
+
+#endif
diff --git a/tools/build/cross-build/include/common/sys/exterrvar.h b/tools/build/cross-build/include/common/sys/exterrvar.h
new file mode 100644
index 000000000000..0ba821aadef2
--- /dev/null
+++ b/tools/build/cross-build/include/common/sys/exterrvar.h
@@ -0,0 +1,6 @@
+#ifndef _SYS_EXTERRVAR_H_
+#define _SYS_EXTERRVAR_H_
+
+#define UEXTERROR_MAXLEN 256
+
+#endif
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index eb2713bafac9..4c127b392138 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -1441,6 +1441,10 @@ OLD_LIBS+=${DEBUG_LIBS}
.endif
.endif
+.if ${MK_DETECT_TZ_CHANGES} == no
+OLD_FILES+=tests/lib/libc/stdtime/detect_tz_changes_test
+.endif
+
.if ${MK_DIALOG} == no
OLD_FILES+=usr/bin/dialog
OLD_FILES+=usr/bin/dpv
@@ -1683,9 +1687,6 @@ OLD_FILES+=usr/share/examples/diskless/README.BOOTP
OLD_FILES+=usr/share/examples/diskless/README.TEMPLATING
OLD_FILES+=usr/share/examples/diskless/clone_root
OLD_FILES+=usr/share/examples/dma/mailer.conf
-OLD_FILES+=usr/share/examples/drivers/README
-OLD_FILES+=usr/share/examples/drivers/make_device_driver.sh
-OLD_FILES+=usr/share/examples/drivers/make_pseudo_driver.sh
OLD_FILES+=usr/share/examples/dwatch/profile_template
OLD_FILES+=usr/share/examples/etc/README.examples
OLD_FILES+=usr/share/examples/etc/bsd-style-copyright
@@ -1912,7 +1913,6 @@ OLD_DIRS+=usr/share/examples/bsdconfig
OLD_DIRS+=usr/share/examples/csh
OLD_DIRS+=usr/share/examples/diskless
OLD_DIRS+=usr/share/examples/dma
-OLD_DIRS+=usr/share/examples/drivers
OLD_DIRS+=usr/share/examples/dwatch
OLD_DIRS+=usr/share/examples/etc
OLD_DIRS+=usr/share/examples/etc/defaults
@@ -4950,7 +4950,6 @@ OLD_FILES+=usr/lib/libhx509.so
OLD_LIBS+=usr/lib/libhx509.so.11
OLD_FILES+=usr/lib/libhx509_p.a
OLD_FILES+=usr/lib/libkadm5clnt.a
-OLD_FILES+=usr/lib/libkadm5clnt.so
OLD_LIBS+=usr/lib/libkadm5clnt.so.11
OLD_FILES+=usr/lib/libkadm5clnt_p.a
OLD_FILES+=usr/lib/libkadm5srv.a
diff --git a/tools/build/options/WITH_RUN_TESTS b/tools/build/options/WITH_RUN_TESTS
new file mode 100644
index 000000000000..91b30522a3d3
--- /dev/null
+++ b/tools/build/options/WITH_RUN_TESTS
@@ -0,0 +1 @@
+Run tests as part of the build.
diff --git a/tools/test/stress2/misc/all.exclude b/tools/test/stress2/misc/all.exclude
index f8a5ea4a91f1..54524c92eac0 100644
--- a/tools/test/stress2/misc/all.exclude
+++ b/tools/test/stress2/misc/all.exclude
@@ -16,8 +16,6 @@ fsck12.sh Waiting for fix 20230319
fsync.sh panic: Journal overflow 20190208
fuse.sh https://people.freebsd.org/~pho/stress/log/log0546.txt 20240828
fuse2.sh https://people.freebsd.org/~pho/stress/log/log0547.txt 20240828
-getrandom.sh Known DoS issue 20201107
-getrandom2.sh Known DoS issue 20200302
gjournal.sh panic: Journal overflow 20190626
gjournal2.sh panic: Journal overflow 20180125
gjournal3.sh panic: Bio not on queue 20171225
@@ -34,6 +32,7 @@ maxvnodes2.sh https://people.freebsd.org/~pho/stress/log/log0083.txt 20210329
memguard.sh https://people.freebsd.org/~pho/stress/log/log0088.txt 20210402
memguard2.sh Waiting for fix commit
memguard3.sh Waiting for fix commit
+mount7.sh https://people.freebsd.org/~pho/stress/log/log0549.txt 20240912
mlockall2.sh Unrecoverable OOM killing seen 20190203
mlockall6.sh https://people.freebsd.org/~pho/stress/log/log0430.txt 20230403
mlockall7.sh Needs further investigation 20210123
@@ -46,6 +45,7 @@ nfs16.sh panic: Failed to register NFS lock locally - error=11 20160608
nullfs28.sh Hang in "mount drain" seen 20220111
oom2.sh Hang in pfault 20180324
overcommit2.sh CAM stuck in vmwait seen 20200112
+pmc4.sh https://people.freebsd.org/~pho/stress/log/log0548.txt 20240904
pmc8.sh panic: [pmc,2749] (ri21, rc1) waiting too long for pmc to ... 20210621
rename14.sh https://people.freebsd.org/~pho/stress/log/log0433.txt 20230409
sctp2.sh panic: Queues are not empty when handling SHUTDOWN-COMPLETE 20210211
@@ -71,8 +71,12 @@ syzkaller59.sh Page fault 20220625
syzkaller65.sh panic: in_pcblookup_hash_locked: invalid local address 20230318
syzkaller66.sh panic: in_pcbconnect: inp is already connected 20230621
syzkaller67.sh panic: ASan: Invalid access, 8-byte read at ... 20230621
+syzkaller80.sh panic 20250711
+syzkaller81.sh panic 20250711
quota6.sh https://people.freebsd.org/~pho/stress/log/log0456.txt 20240707
truss3.sh WiP 20200915
+zfs18.sh https://people.freebsd.org/~pho/stress/log/log0560.txt 20241118
+zfs9.sh panic: sacked_bytes < 0 20250711
# Test not to run for other reasons:
diff --git a/tools/test/stress2/misc/fullpath2.sh b/tools/test/stress2/misc/fullpath2.sh
index e4024c32f317..413f832420d4 100755
--- a/tools/test/stress2/misc/fullpath2.sh
+++ b/tools/test/stress2/misc/fullpath2.sh
@@ -123,7 +123,7 @@ static volatile u_int *share;
#define NB 1024
#define RUNTIME 300
-/* dtrace -w -n 'fbt::*vn_fullpath1:entry {@rw[execname,probefunc] = count(); }' */
+/* dtrace -n 'fbt::vn_fullpath:entry {@rw[execname,probefunc] = count(); }' */
static void
getfiles(pid_t pid)
diff --git a/tools/test/stress2/misc/syzkaller80.sh b/tools/test/stress2/misc/syzkaller80.sh
new file mode 100755
index 000000000000..31eae210d5b3
--- /dev/null
+++ b/tools/test/stress2/misc/syzkaller80.sh
@@ -0,0 +1,320 @@
+#!/bin/sh
+
+# panic: ../../../kern/uipc_usrreq.c:1256: uipc_sosend_stream_or_seqpacket: Empty stailq 0xfffffe00ffe5fc88->stqh_last is 0xfffffe00ffe5fcd0, not head's first field address
+# cpuid = 5
+# time = 1749593630
+# KDB: stack backtrace:
+# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe00ffe5fab0
+# vpanic() at vpanic+0x136/frame 0xfffffe00ffe5fbe0
+# panic() at panic+0x43/frame 0xfffffe00ffe5fc40
+# uipc_sosend_stream_or_seqpacket() at uipc_sosend_stream_or_seqpacket+0xa39/frame 0xfffffe00ffe5fd10
+# sousrsend() at sousrsend+0x79/frame 0xfffffe00ffe5fd70
+# dofilewrite() at dofilewrite+0x81/frame 0xfffffe00ffe5fdc0
+# sys_writev() at sys_writev+0x69/frame 0xfffffe00ffe5fe00
+# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe00ffe5ff30
+# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe00ffe5ff30
+# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x82330181a, rsp = 0x8238dbf68, rbp = 0x8238dbf90 ---
+# KDB: enter: panic
+# [ thread pid 4484 tid 101524 ]
+# Stopped at kdb_enter+0x33: movq $0,0x122ebc2(%rip)
+# db> x/s version
+# version: FreeBSD 15.0-CURRENT #0 main-n277833-948078b65c27-dirty: Tue Jun 10 06:01:36 CEST 2025
+# pho@mercat1.netperf.freebsd.org:/usr/src/sys/amd64/compile/PHO
+# db>
+
+[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
+
+. ../default.cfg
+set -u
+prog=$(basename "$0" .sh)
+cat > /tmp/$prog.c <<EOF
+// https://syzkaller.appspot.com/bug?id=210ae0bfcef6324abfffbfaf10120b767106a990
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+// syzbot+cfcb8520b0071b548fba@syzkaller.appspotmail.com
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/endian.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static unsigned long long procid;
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(pid, SIGKILL);
+ while (waitpid(-1, status, 0) != pid) {
+ }
+}
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i = 0;
+ for (; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ pthread_mutex_t mu;
+ pthread_cond_t cv;
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ if (pthread_mutex_init(&ev->mu, 0))
+ exit(1);
+ if (pthread_cond_init(&ev->cv, 0))
+ exit(1);
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ pthread_mutex_lock(&ev->mu);
+ if (ev->state)
+ exit(1);
+ ev->state = 1;
+ pthread_mutex_unlock(&ev->mu);
+ pthread_cond_broadcast(&ev->cv);
+}
+
+static void event_wait(event_t* ev)
+{
+ pthread_mutex_lock(&ev->mu);
+ while (!ev->state)
+ pthread_cond_wait(&ev->cv, &ev->mu);
+ pthread_mutex_unlock(&ev->mu);
+}
+
+static int event_isset(event_t* ev)
+{
+ pthread_mutex_lock(&ev->mu);
+ int res = ev->state;
+ pthread_mutex_unlock(&ev->mu);
+ return res;
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ pthread_mutex_lock(&ev->mu);
+ for (;;) {
+ if (ev->state)
+ break;
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ pthread_cond_timedwait(&ev->cv, &ev->mu, &ts);
+ now = current_time_ms();
+ if (now - start > timeout)
+ break;
+ }
+ int res = ev->state;
+ pthread_mutex_unlock(&ev->mu);
+ return res;
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
+ }
+ int i, call, thread;
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (call == 2)
+ break;
+ event_timedwait(&th->done, 50);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS 0
+
+static void loop(void)
+{
+ int iter = 0;
+ for (;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ sleep_ms(10);
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ if (current_time_ms() - start < 5000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res = 0;
+ switch (call) {
+ case 0:
+ res = syscall(SYS_socketpair, /*domain=*/1ul, /*type=SOCK_STREAM*/ 1ul,
+ /*proto=*/0, /*fds=*/0x200000000040ul);
+ if (res != -1) {
+ r[0] = *(uint32_t*)0x200000000040;
+ r[1] = *(uint32_t*)0x200000000044;
+ }
+ break;
+ case 1:
+ memcpy((void*)0x200000000100, "\x09\x00\x10\x00", 4);
+ syscall(SYS_setsockopt, /*fd=*/r[1], /*level=*/0, /*optname=*/3,
+ /*optval=*/0x200000000100ul, /*optlen=*/4ul);
+ break;
+ case 2:
+ *(uint64_t*)0x2000000018c0 = 0;
+ *(uint32_t*)0x2000000018c8 = 0;
+ *(uint64_t*)0x2000000018d0 = 0;
+ *(uint64_t*)0x2000000018d8 = 0;
+ *(uint64_t*)0x2000000018e0 = 0x200000001880;
+ memcpy((void*)0x200000001880, "\x10\x00\x00\x00\xff\xff\x00\x00\x06", 9);
+ *(uint64_t*)0x2000000018e8 = 0x10;
+ *(uint32_t*)0x2000000018f0 = 0;
+ syscall(SYS_sendmsg, /*fd=*/r[0], /*msg=*/0x2000000018c0ul, /*f=*/0ul);
+ for (int i = 0; i < 64; i++) {
+ syscall(SYS_sendmsg, /*fd=*/r[0], /*msg=*/0x2000000018c0ul, /*f=*/0ul);
+ }
+ break;
+ case 3:
+ syscall(SYS_writev, /*fd=*/r[0], /*vec=*/0ul, /*vlen=*/0ul);
+ for (int i = 0; i < 64; i++) {
+ syscall(SYS_writev, /*fd=*/r[0], /*vec=*/0ul, /*vlen=*/0ul);
+ }
+ break;
+ case 4:
+ syscall(SYS_setsockopt, /*fd=*/(intptr_t)-1, /*level=*/0, /*optname=*/0xa,
+ /*optval=*/0ul, /*optlen=*/0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(SYS_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul,
+ /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
+ /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x1012ul,
+ /*fd=*/(intptr_t)-1, /*offset=*/0ul);
+ const char* reason;
+ (void)reason;
+ for (procid = 0; procid < 4; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
+EOF
+mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c -lpthread || exit 1
+
+work=/tmp/$prog.dir
+rm -rf $work
+mkdir $work
+cd /tmp/$prog.dir
+timeout 3m /tmp/$prog > /dev/null 2>&1
+
+rm -rf /tmp/$prog /tmp/$prog.c /tmp/$prog.core /tmp/$prog.?????? $work
+exit 0
diff --git a/tools/test/stress2/misc/syzkaller81.sh b/tools/test/stress2/misc/syzkaller81.sh
new file mode 100755
index 000000000000..e3e4ec50aeea
--- /dev/null
+++ b/tools/test/stress2/misc/syzkaller81.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# panic: kern_clock_gettime: 22
+# cpuid = 1
+# time = 1750181240
+# KDB: stack backtrace:
+# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe01a6084ba0
+# vpanic() at vpanic+0x136/frame 0xfffffe01a6084cd0
+# panic() at panic+0x43/frame 0xfffffe01a6084d30
+# kern_clock_nanosleep() at kern_clock_nanosleep+0x38f/frame 0xfffffe01a6084db0
+# sys_clock_nanosleep() at sys_clock_nanosleep+0x49/frame 0xfffffe01a6084e00
+# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe01a6084f30
+# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe01a6084f30
+# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x8233d281a, rsp = 0x820bfb2b8, rbp = 0x820bfb2e0 ---
+# KDB: enter: panic
+# [ thread pid 26119 tid 104417 ]
+# Stopped at kdb_enter+0x33: movq $0,0x122a7b2(%rip)
+# db> x/s version
+# version: FreeBSD 15.0-CURRENT #1 ufs-n278031-3296ff02387b: Tue Jun 17 16:40:44 CEST 2025
+# pho@mercat1.netperf.freebsd.org:/var/tmp/deviant3/sys/amd64/compile/PHO
+# db>
+
+[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
+
+. ../default.cfg
+set -u
+prog=$(basename "$0" .sh)
+cat > /tmp/$prog.c <<EOF
+// https://syzkaller.appspot.com/bug?id=5eb7636bc26fcbd20412de35ec10944233b8577d
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+// syzbot+e17e46b1f0b65027b005@syzkaller.appspotmail.com
+
+#define _GNU_SOURCE
+
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/endian.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+int main(void)
+{
+ syscall(SYS_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul,
+ /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
+ /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x1012ul,
+ /*fd=*/(intptr_t)-1, /*offset=*/0ul);
+ const char* reason;
+ (void)reason;
+ if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
+ }
+ *(uint64_t*)0x200000000040 = 0x10000000000;
+ *(uint64_t*)0x200000000048 = 0x4000000;
+ syscall(SYS_clock_nanosleep, /*id=*/0x10ul, /*flags=TIMER_ABSTIME*/ 1ul,
+ /*rqtp=*/0x200000000040ul, /*rmtp=*/0ul);
+ return 0;
+}
+EOF
+mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1
+
+work=/tmp/$prog.dir
+rm -rf $work
+mkdir $work
+cd /tmp/$prog.dir
+timeout 3m /tmp/$prog > /dev/null 2>&1
+
+rm -rf /tmp/$prog /tmp/$prog.c /tmp/$prog.core /tmp/$prog.?????? $work
+exit 0
diff --git a/tools/tools/git/git-arc.sh b/tools/tools/git/git-arc.sh
index d953a30cb90d..22df0c61293a 100644
--- a/tools/tools/git/git-arc.sh
+++ b/tools/tools/git/git-arc.sh
@@ -545,7 +545,7 @@ find_author()
# don't know if the prior _ are _ or + or any number of other characters.
# Since there's issues here, prompt
a=$(printf "%s <%s>\n" "${name}" $(echo "$addr" | sed -e 's/\(.*\)_/\1@/'))
- echo "Making best guess: Turning ${addr} to ${a}"
+ echo "Making best guess: Turning ${addr} to ${a}" >&2
if ! prompt; then
echo "ABORT"
return
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index b69d25480479..512f75b5d093 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -133,7 +133,6 @@ SUBDIR= alias \
sdiff \
sed \
seq \
- shar \
showmount \
sockstat \
soelim \
diff --git a/usr.bin/bmake/Makefile.config b/usr.bin/bmake/Makefile.config
index 78babc2f1382..8ff6c81b8c78 100644
--- a/usr.bin/bmake/Makefile.config
+++ b/usr.bin/bmake/Makefile.config
@@ -6,7 +6,7 @@ SRCTOP?= ${.CURDIR:H:H}
# things set by configure
-_MAKE_VERSION?=20250618
+_MAKE_VERSION?=20250707
prefix?= /usr
srcdir= ${SRCTOP}/contrib/bmake
diff --git a/usr.bin/bmake/unit-tests/Makefile b/usr.bin/bmake/unit-tests/Makefile
index 1b9a47febe11..d4ee6f33f862 100644
--- a/usr.bin/bmake/unit-tests/Makefile
+++ b/usr.bin/bmake/unit-tests/Makefile
@@ -1,9 +1,9 @@
# This is a generated file, do NOT edit!
# See contrib/bmake/bsd.after-import.mk
#
-# $Id: Makefile,v 1.239 2025/06/15 21:32:16 sjg Exp $
+# $Id: Makefile,v 1.240 2025/06/30 18:40:54 sjg Exp $
#
-# $NetBSD: Makefile,v 1.367 2025/06/13 20:23:16 rillig Exp $
+# $NetBSD: Makefile,v 1.369 2025/06/29 09:40:13 rillig Exp $
#
# Unit tests for make(1)
#
@@ -61,6 +61,7 @@ rm-tmpdir: .NOMETA
# src/tests/usr.bin/make/t_make.sh as well.
#TESTS+= archive
#TESTS+= archive-suffix
+TESTS+= char-005c-reverse-solidus
TESTS+= cmd-errors
TESTS+= cmd-errors-jobs
TESTS+= cmd-errors-lint
@@ -416,6 +417,7 @@ TESTS+= varmod-to-upper
TESTS+= varmod-undefined
TESTS+= varmod-unique
TESTS+= varname
+TESTS+= varname-circumflex
TESTS+= varname-dollar
TESTS+= varname-dot-alltargets
TESTS+= varname-dot-curdir
@@ -544,7 +546,6 @@ TESTS:= ${TESTS:${BROKEN_TESTS:S,^,N,:ts:}}
# Ideas for more tests:
# char-0020-space.mk
-# char-005C-backslash.mk
# escape-cond-str.mk
# escape-cond-func-arg.mk
# escape-varmod.mk
diff --git a/usr.bin/calendar/calendars/calendar.freebsd b/usr.bin/calendar/calendars/calendar.freebsd
index 0b1a37f43723..1ca63b371f65 100644
--- a/usr.bin/calendar/calendars/calendar.freebsd
+++ b/usr.bin/calendar/calendars/calendar.freebsd
@@ -259,6 +259,7 @@
06/11 Alonso Cardenas Marquez <acm@FreeBSD.org> born in Arequipa, Peru, 1979
06/14 Josh Paetzel <jpaetzel@FreeBSD.org> born in Minneapolis, Minnesota, United States, 1973
06/15 Second quarterly status reports are due on 06/30
+06/15 Aymeric Wibo <obiwac@FreeBSD.org> born in Plaistow, London, United Kingdom, 2004
06/17 Tilman Linneweh <arved@FreeBSD.org> born in Weinheim, Baden-Wuerttemberg, Germany, 1978
06/18 Li-Wen Hsu <lwhsu@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1984
06/18 Roman Bogorodskiy <novel@FreeBSD.org> born in Saratov, Russian Federation, 1986
diff --git a/usr.bin/clang/Makefile b/usr.bin/clang/Makefile
index a0cc015590f0..e2debfb8c582 100644
--- a/usr.bin/clang/Makefile
+++ b/usr.bin/clang/Makefile
@@ -5,6 +5,10 @@ SUBDIR+= clang
.endif
.if !defined(TOOLS_PREFIX)
+.if ${MK_CLANG} != "no"
+SUBDIR+= clang-scan-deps
+.endif
+
# LLVM binutils are needed to support features such as LTO, so we build them
# by default if clang is enabled. If MK_LLVM_BINUTILS is set, we also use them
# as the default binutils (ar,nm,addr2line, etc.).
diff --git a/usr.bin/clang/clang-scan-deps/Makefile b/usr.bin/clang/clang-scan-deps/Makefile
new file mode 100644
index 000000000000..16fecdb88867
--- /dev/null
+++ b/usr.bin/clang/clang-scan-deps/Makefile
@@ -0,0 +1,26 @@
+.include <src.opts.mk>
+
+PROG_CXX= clang-scan-deps
+MAN=
+
+SRCDIR= clang/tools/clang-scan-deps
+SRCS+= ClangScanDeps.cpp \
+ clang-scan-deps-driver.cpp
+
+.include "${SRCTOP}/lib/clang/clang.pre.mk"
+
+CFLAGS+= -I${.OBJDIR}
+TDFILE= Opts.td
+INCFILE= ${TDFILE:.td=.inc}
+GENOPT= -gen-opt-parser-defs
+
+${INCFILE}: ${TDFILE}
+ ${LLVM_TBLGEN} ${GENOPT} -I ${LLVM_SRCS}/include -d ${.TARGET:C/$/.d/} \
+ -o ${.TARGET} ${.ALLSRC}
+TGHDRS+= ${INCFILE}
+
+DEPENDFILES+= ${TGHDRS:C/$/.d/}
+DPSRCS+= ${TGHDRS}
+CLEANFILES+= ${TGHDRS} ${TGHDRS:C/$/.d/}
+
+.include "../clang.prog.mk"
diff --git a/usr.bin/clang/clang-scan-deps/clang-scan-deps-driver.cpp b/usr.bin/clang/clang-scan-deps/clang-scan-deps-driver.cpp
new file mode 100644
index 000000000000..f941cc434ff6
--- /dev/null
+++ b/usr.bin/clang/clang-scan-deps/clang-scan-deps-driver.cpp
@@ -0,0 +1,18 @@
+//===-- driver-template.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/LLVMDriver.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/InitLLVM.h"
+
+int clang_scan_deps_main(int argc, char **, const llvm::ToolContext &);
+
+int main(int argc, char **argv) {
+ llvm::InitLLVM X(argc, argv);
+ return clang_scan_deps_main(argc, argv, {argv[0], nullptr, false});
+}
diff --git a/usr.bin/du/du.1 b/usr.bin/du/du.1
index 37f7d7837b11..1b6d800b0285 100644
--- a/usr.bin/du/du.1
+++ b/usr.bin/du/du.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 29, 2024
+.Dd July 16, 2025
.Dt DU 1
.Os
.Sh NAME
@@ -58,7 +58,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl A
Display the apparent size instead of the disk usage.
@@ -225,7 +225,7 @@ Also display a grand total at the end:
.Xr chflags 2 ,
.Xr fts 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr symlink 7 ,
.Xr quot 8
.Sh STANDARDS
diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1
index eb3fd4d0dbde..8c2d8624a82a 100644
--- a/usr.bin/find/find.1
+++ b/usr.bin/find/find.1
@@ -1156,7 +1156,7 @@ and was removed in
.At v3 .
It was rewritten for
.At v5
-and later be enhanced for the Programmer's Workbench (PWB).
+and was later enhanced for the Programmer's Workbench (PWB).
These changes were later incorporated in
.At v7 .
.Sh BUGS
diff --git a/usr.bin/fortune/datfiles/freebsd-tips b/usr.bin/fortune/datfiles/freebsd-tips
index 1e9501e3a6fb..6a2b59ff5fa7 100644
--- a/usr.bin/fortune/datfiles/freebsd-tips
+++ b/usr.bin/fortune/datfiles/freebsd-tips
@@ -555,7 +555,7 @@ Use "sysrc name=value" to add an entry and "sysrc -x name" to delete an entry.
You can upload the dmesg of your system to help developers get an overview of commonly
used hardware and peripherals for FreeBSD. Use the curl package to upload it like this:
curl -v -d "nickname=$USER" -d "description=FreeBSD/$(uname -m) on \
-$(kenv smbios.system.maker) $(kenv smbios.system.product)" -d "do=addd" \
+$(kenv smbios.system.maker) $(kenv smbios.system.product)" -d "do=add" \
--data-urlencode 'dmesg@/var/run/dmesg.boot' http://dmesgd.nycbug.org/index.cgi
%
Want to know how much memory (in bytes) your machine has installed? Let
diff --git a/usr.bin/iscsictl/iscsictl.8 b/usr.bin/iscsictl/iscsictl.8
index 74394063a007..88c79c297848 100644
--- a/usr.bin/iscsictl/iscsictl.8
+++ b/usr.bin/iscsictl/iscsictl.8
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 27, 2018
+.Dd July 16, 2025
.Dt ISCSICTL 8
.Os
.Sh NAME
@@ -88,7 +88,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl A
Add session.
@@ -190,7 +190,7 @@ Disconnect all iSCSI sessions:
.Dl Nm Fl Ra
.Sh SEE ALSO
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr iscsi 4 ,
.Xr iscsi.conf 5 ,
.Xr iscsid 8
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index 9cc22d382de5..17ed43b55c5a 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -46,6 +46,7 @@
#include <sys/ktrace.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
+#include <sys/inotify.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -105,6 +106,7 @@ static void ktrcsw(struct ktr_csw *);
static void ktrcsw_old(struct ktr_csw_old *);
static void ktruser(int, void *);
static void ktrcaprights(cap_rights_t *);
+static void ktrinotify(struct inotify_event *);
static void ktritimerval(struct itimerval *it);
static void ktrsockaddr(struct sockaddr *);
static void ktrsplice(struct splice *);
@@ -1861,6 +1863,14 @@ ktrtimeval(struct timeval *tv)
}
static void
+ktrinotify(struct inotify_event *ev)
+{
+ printf(
+ "inotify { .wd = %d, .mask = %#x, .cookie = %u, .len = %u, .name = %s }\n",
+ ev->wd, ev->mask, ev->cookie, ev->len, ev->name);
+}
+
+static void
ktritimerval(struct itimerval *it)
{
@@ -2128,6 +2138,17 @@ ktrstruct(char *buf, size_t buflen)
goto invalid;
memcpy(&rights, data, datalen);
ktrcaprights(&rights);
+ } else if (strcmp(name, "inotify") == 0) {
+ struct inotify_event *ev;
+
+ if (datalen < sizeof(struct inotify_event) ||
+ datalen > sizeof(struct inotify_event) + NAME_MAX + 1)
+ goto invalid;
+ ev = malloc(datalen);
+ if (ev == NULL)
+ err(1, "malloc");
+ memcpy(ev, data, datalen);
+ ktrinotify(ev);
} else if (strcmp(name, "itimerval") == 0) {
if (datalen != sizeof(struct itimerval))
goto invalid;
diff --git a/usr.bin/kyua/Makefile b/usr.bin/kyua/Makefile
index d3a7b9b61f64..a4f95f1106d9 100644
--- a/usr.bin/kyua/Makefile
+++ b/usr.bin/kyua/Makefile
@@ -32,7 +32,7 @@ MAN= kyua-about.1 \
CFLAGS+= -I${KYUA_SRCDIR} -I${.CURDIR}
CFLAGS+= -I${SRCTOP}/contrib/lutok/include
-CFLAGS+= -I${SRCTOP}/contrib/sqlite3
+CFLAGS+= -I${SYSROOT:U${DESTDIR}}/${INCLUDEDIR}/private/sqlite3
CFLAGS+= -DHAVE_CONFIG_H
# We compile the kyua libraries as part of the main executable as this saves
diff --git a/usr.bin/last/last.1 b/usr.bin/last/last.1
index f3ccc6e772af..b026ed6a7921 100644
--- a/usr.bin/last/last.1
+++ b/usr.bin/last/last.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 9, 2021
+.Dd July 16, 2025
.Dt LAST 1
.Os
.Sh NAME
@@ -75,7 +75,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl d Ar date
Specify the snapshot date and time.
@@ -223,7 +223,7 @@ alice ttyv0 Mon Dec 7 19:18 - 22:27 (03:09)
.Xr lastcomm 1 ,
.Xr getutxent 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr ac 8 ,
.Xr lastlogin 8
.Sh HISTORY
diff --git a/usr.bin/lockf/lockf.1 b/usr.bin/lockf/lockf.1
index d73033101632..40b4497bc80c 100644
--- a/usr.bin/lockf/lockf.1
+++ b/usr.bin/lockf/lockf.1
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 25, 2023
+.Dd June 24, 2025
.Dt LOCKF 1
.Os
.Sh NAME
@@ -30,7 +30,7 @@
.Nd execute a command while holding a file lock
.Sh SYNOPSIS
.Nm
-.Op Fl knsw
+.Op Fl knpsTw
.Op Fl t Ar seconds
.Ar file
.Ar command
@@ -126,6 +126,32 @@ is not specified,
will create
.Ar file
if necessary.
+.It Fl p
+Write the pid of the
+.Ar command
+to
+.Ar file .
+This option will cause
+.Nm
+to open
+.Ar file
+for writing rather than reading.
+.It Fl T
+Upon receipt of a
+.Dv SIGTERM ,
+forward a
+.Dv SIGTERM
+along to the
+.Ar command
+before cleaning up the
+.Ar file
+and exiting.
+By default,
+.Nm
+effectively orphans the
+.Ar command
+after cleaning up the
+.Ar file .
.It Fl t Ar seconds
Specifies a timeout for waiting for the lock.
By default,
diff --git a/usr.bin/lockf/lockf.c b/usr.bin/lockf/lockf.c
index 7f88753d1743..16bae36a21e0 100644
--- a/usr.bin/lockf/lockf.c
+++ b/usr.bin/lockf/lockf.c
@@ -34,6 +34,8 @@
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
+#include <stdatomic.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -50,39 +52,45 @@ union lock_subject {
static int acquire_lock(union lock_subject *subj, int flags, int silent);
static void cleanup(void);
static void killed(int sig);
+static void sigchld(int sig);
static void timeout(int sig);
static void usage(void) __dead2;
static void wait_for_lock(const char *name);
static const char *lockname;
+_Static_assert(sizeof(sig_atomic_t) >= sizeof(pid_t),
+ "PIDs cannot be managed safely from a signal handler on this platform.");
+static sig_atomic_t child = -1;
static int lockfd = -1;
-static int keep;
-static int fdlock;
-static volatile sig_atomic_t timed_out;
+static bool keep;
+static bool fdlock;
+static int status;
+static bool termchild;
+static sig_atomic_t timed_out;
/*
* Check if fdlock is implied by the given `lockname`. We'll write the fd that
* is represented by it out to ofd, and the caller is expected to do any
* necessary validation on it.
*/
-static int
+static bool
fdlock_implied(const char *name, long *ofd)
{
char *endp;
long fd;
if (strncmp(name, FDLOCK_PREFIX, sizeof(FDLOCK_PREFIX) - 1) != 0)
- return (0);
+ return (false);
/* Skip past the prefix. */
name += sizeof(FDLOCK_PREFIX) - 1;
errno = 0;
fd = strtol(name, &endp, 10);
if (errno != 0 || *endp != '\0')
- return (0);
+ return (false);
*ofd = fd;
- return (1);
+ return (true);
}
/*
@@ -91,35 +99,44 @@ fdlock_implied(const char *name, long *ofd)
int
main(int argc, char **argv)
{
- int ch, flags, silent, status;
+ struct sigaction sa_chld = {
+ .sa_handler = sigchld,
+ .sa_flags = SA_NOCLDSTOP,
+ }, sa_prev;
+ sigset_t mask, omask;
long long waitsec;
- pid_t child;
+ const char *errstr;
union lock_subject subj;
+ int ch, flags;
+ bool silent, writepid;
- silent = keep = 0;
+ silent = writepid = false;
flags = O_CREAT | O_RDONLY;
waitsec = -1; /* Infinite. */
- while ((ch = getopt(argc, argv, "knst:w")) != -1) {
+ while ((ch = getopt(argc, argv, "knpsTt:w")) != -1) {
switch (ch) {
case 'k':
- keep = 1;
+ keep = true;
break;
case 'n':
flags &= ~O_CREAT;
break;
case 's':
- silent = 1;
+ silent = true;
+ break;
+ case 'T':
+ termchild = true;
break;
case 't':
- {
- const char *errstr;
-
waitsec = strtonum(optarg, 0, UINT_MAX, &errstr);
if (errstr != NULL)
errx(EX_USAGE,
"invalid timeout \"%s\"", optarg);
- }
break;
+ case 'p':
+ writepid = true;
+ flags |= O_TRUNC;
+ /* FALLTHROUGH */
case 'w':
flags = (flags & ~O_RDONLY) | O_WRONLY;
break;
@@ -143,7 +160,7 @@ main(int argc, char **argv)
* If there aren't any arguments left, then we must be in fdlock mode.
*/
if (argc == 0 && *lockname != '/') {
- fdlock = 1;
+ fdlock = true;
subj.subj_fd = -1;
} else {
fdlock = fdlock_implied(lockname, &subj.subj_fd);
@@ -208,13 +225,16 @@ main(int argc, char **argv)
*/
lockfd = acquire_lock(&subj, flags | O_NONBLOCK, silent);
while (lockfd == -1 && !timed_out && waitsec != 0) {
- if (keep || fdlock)
+ if (keep || fdlock) {
lockfd = acquire_lock(&subj, flags, silent);
- else {
+ } else {
wait_for_lock(lockname);
lockfd = acquire_lock(&subj, flags | O_NONBLOCK,
silent);
}
+
+ /* timed_out */
+ atomic_signal_fence(memory_order_acquire);
}
if (waitsec > 0)
alarm(0);
@@ -234,9 +254,30 @@ main(int argc, char **argv)
if (atexit(cleanup) == -1)
err(EX_OSERR, "atexit failed");
+
+ /*
+ * Block SIGTERM while SIGCHLD is being processed, so that we can safely
+ * waitpid(2) for the child without a concurrent termination observing
+ * an invalid pid (i.e., waited-on). If our setup between here and the
+ * sigsuspend loop gets any more complicated, we should rewrite it to
+ * just use a pipe to signal the child onto execvp().
+ *
+ * We're blocking SIGCHLD and SIGTERM here so that we don't do any
+ * cleanup before we're ready to (after the pid is written out).
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigaddset(&mask, SIGTERM);
+ (void)sigprocmask(SIG_BLOCK, &mask, &omask);
+
+ memcpy(&sa_chld.sa_mask, &omask, sizeof(omask));
+ sigaddset(&sa_chld.sa_mask, SIGTERM);
+ (void)sigaction(SIGCHLD, &sa_chld, &sa_prev);
+
if ((child = fork()) == -1)
err(EX_OSERR, "cannot fork");
if (child == 0) { /* The child process. */
+ (void)sigprocmask(SIG_SETMASK, &omask, NULL);
close(lockfd);
execvp(argv[0], argv);
warn("%s", argv[0]);
@@ -246,11 +287,24 @@ main(int argc, char **argv)
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGTERM, killed);
+
fclose(stdin);
fclose(stdout);
fclose(stderr);
- if (waitpid(child, &status, 0) == -1)
- exit(EX_OSERR);
+
+ /* Write out the pid before we sleep on it. */
+ if (writepid)
+ (void)dprintf(lockfd, "%d\n", (int)child);
+
+ /* Just in case they were blocked on entry. */
+ sigdelset(&omask, SIGCHLD);
+ sigdelset(&omask, SIGTERM);
+ while (child >= 0) {
+ (void)sigsuspend(&omask);
+ /* child */
+ atomic_signal_fence(memory_order_acquire);
+ }
+
return (WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE);
}
@@ -308,13 +362,35 @@ static void
killed(int sig)
{
+ if (termchild && child >= 0)
+ kill(child, sig);
cleanup();
signal(sig, SIG_DFL);
- if (kill(getpid(), sig) == -1)
+ if (raise(sig) == -1)
_Exit(EX_OSERR);
}
/*
+ * Signal handler for SIGCHLD. Simply waits for the child and ensures that we
+ * don't end up in a sticky situation if we receive a SIGTERM around the same
+ * time.
+ */
+static void
+sigchld(int sig __unused)
+{
+ int ostatus;
+
+ while (waitpid(child, &ostatus, 0) != child) {
+ if (errno != EINTR)
+ _exit(EX_OSERR);
+ }
+
+ status = ostatus;
+ child = -1;
+ atomic_signal_fence(memory_order_release);
+}
+
+/*
* Signal handler for SIGALRM.
*/
static void
@@ -322,6 +398,7 @@ timeout(int sig __unused)
{
timed_out = 1;
+ atomic_signal_fence(memory_order_release);
}
static void
diff --git a/usr.bin/lockf/tests/lockf_test.sh b/usr.bin/lockf/tests/lockf_test.sh
index d73c7590653d..823b5673a176 100644
--- a/usr.bin/lockf/tests/lockf_test.sh
+++ b/usr.bin/lockf/tests/lockf_test.sh
@@ -31,6 +31,24 @@
: ${EX_CANTCREAT:=73}
: ${EX_TEMPFAIL:=75}
+waitlock()
+{
+ local cur lockfile tmo
+
+ lockfile="$1"
+
+ cur=0
+ tmo=20
+
+ while [ "$cur" -lt "$tmo" -a ! -f "$lockfile" ]; do
+ sleep 0.1
+ cur=$((cur + 1))
+ done
+
+ atf_check_not_equal "$cur" "$tmo"
+}
+
+
atf_test_case badargs
badargs_body()
{
@@ -62,6 +80,13 @@ basic_body()
atf_check test ! -e "testlock"
}
+atf_test_case bubble_error
+bubble_error_body()
+{
+ # Ensure that lockf bubbles up the error as expected.
+ atf_check -s exit:9 lockf testlock sh -c 'exit 9'
+}
+
atf_test_case fdlock
fdlock_body()
{
@@ -189,6 +214,52 @@ needfile_body()
atf_check test "$tpass" -lt 10
}
+atf_test_case termchild
+termchild_body()
+{
+ lockf -kp testlock sleep 30 &
+ lpid=$!
+
+ waitlock testlock
+
+ atf_check -o file:testlock pgrep -F testlock
+
+ start=$(date +"%s")
+ atf_check kill -TERM "$lpid"
+ wait "$lpid"
+ end=$(date +"%s")
+ elapsed=$((end - start))
+
+ if [ "$elapsed" -gt 5 ]; then
+ atf_fail "lockf seems to have dodged the SIGTERM ($elapsed passed)"
+ fi
+
+ # We didn't start lockf with -T this time, so the process should not
+ # have been terminated.
+ atf_check -o file:testlock pgrep -F testlock
+
+ lockf -kpT testlock sleep 30 &
+ lpid=$!
+
+ waitlock testlock
+
+ atf_check -o file:testlock pgrep -F testlock
+
+ start=$(date +"%s")
+ atf_check kill -TERM "$lpid"
+ wait "$lpid"
+ end=$(date +"%s")
+ elapsed=$((end - start))
+
+ if [ "$elapsed" -gt 5 ]; then
+ atf_fail "lockf -T seems to have dodged the SIGTERM ($elapsed passed)"
+ fi
+
+ # This time, it should have terminated (notably much earlier than our
+ # 30 second timeout).
+ atf_check -o empty -e not-empty -s not-exit:0 pgrep -F testlock
+}
+
atf_test_case timeout
timeout_body()
{
@@ -212,6 +283,34 @@ timeout_body()
wait "$lpid" || true
}
+atf_test_case writepid
+writepid_body()
+{
+ lockf -p "testlock" sleep 10 &
+ lpid=$!
+
+ waitlock "testlock"
+
+ atf_check test -s testlock
+ atf_check -o file:testlock pgrep -F testlock
+ atf_check -o file:testlock pgrep -F testlock -fx "sleep 10"
+ atf_check pkill -TERM -F testlock
+
+ wait
+
+ atf_check test ! -f testlock
+}
+
+atf_test_case writepid_keep
+writepid_keep_body()
+{
+ # Check that we'll clobber any existing contents (a pid, usually)
+ # once we acquire the lock.
+ jot -b A -s "" 64 > testlock
+ atf_check lockf -kp testlock sleep 0
+ atf_check -o not-match:"A" cat testlock
+}
+
atf_test_case wrlock
wrlock_head()
{
@@ -233,9 +332,13 @@ atf_init_test_cases()
{
atf_add_test_case badargs
atf_add_test_case basic
+ atf_add_test_case bubble_error
atf_add_test_case fdlock
atf_add_test_case keep
atf_add_test_case needfile
+ atf_add_test_case termchild
atf_add_test_case timeout
+ atf_add_test_case writepid
+ atf_add_test_case writepid_keep
atf_add_test_case wrlock
}
diff --git a/usr.bin/man/man.sh b/usr.bin/man/man.sh
index ec20fc813bf4..18595042da5f 100755
--- a/usr.bin/man/man.sh
+++ b/usr.bin/man/man.sh
@@ -313,6 +313,8 @@ manpath_warnings() {
# redirected to another source file.
man_check_for_so() {
local IFS line tstr
+ local counter_so=0
+ local counter_so_limit=32
unset IFS
if [ -n "$catpage" ]; then
@@ -320,13 +322,16 @@ man_check_for_so() {
fi
# We need to loop to accommodate multiple .so directives.
- while true
+ while [ $counter_so -lt $counter_so_limit ]
do
+ counter_so=$((counter_so + 1))
+
line=$($cattool "$manpage" 2>/dev/null | grep -E -m1 -v '^\.\\"[ ]*|^[ ]*$')
case "$line" in
'.so /'*) break ;; # ignore absolute path
'.so '*) trim "${line#.so}"
- decho "$manpage includes $tstr"
+ decho "$manpage includes $tstri level=$counter_so"
+
# Glob and check for the file.
if ! check_man "$1/$tstr" ""; then
decho " Unable to find $tstr"
@@ -337,6 +342,10 @@ man_check_for_so() {
esac
done
+ if [ $counter_so -ge $counter_so_limit ]; then
+ decho ".so include limit of $counter_so_limit reached, stop"
+ fi
+
return 0
}
diff --git a/usr.bin/mkimg/mkimg.1 b/usr.bin/mkimg/mkimg.1
index f6b151d2d5c7..ae48904eb16c 100644
--- a/usr.bin/mkimg/mkimg.1
+++ b/usr.bin/mkimg/mkimg.1
@@ -41,7 +41,7 @@
.Op Fl f Ar format
.Op Fl o Ar outfile
.Op Fl a Ar active
-.Op Fl R
+.Op Fl t Ar timestamp
.Op Fl v
.Op Fl y
.Op Fl s Ar scheme Op Fl p Ar partition ...
@@ -139,9 +139,9 @@ option is a shorthand to specify the minimum and maximum capacity at the
same time.
.Pp
The
-.Fl R
-option enables reproducible mode: any timestamps or random identifiers will
-be fixed so as to ensure consistent output.
+.Fl t
+option causes any timestamps embedded in the output file to be set to the
+given time, specified in seconds since the epoch.
.Pp
The
.Fl v
diff --git a/usr.bin/mkimg/mkimg.c b/usr.bin/mkimg/mkimg.c
index c8872ebb1bc6..a7409b686560 100644
--- a/usr.bin/mkimg/mkimg.c
+++ b/usr.bin/mkimg/mkimg.c
@@ -61,7 +61,8 @@ static struct option longopts[] = {
static uint64_t min_capacity = 0;
static uint64_t max_capacity = 0;
-bool reproducible = false;
+/* Fixed timestamp for reproducible builds. */
+time_t timestamp = (time_t)-1;
struct partlisthead partlist = TAILQ_HEAD_INITIALIZER(partlist);
u_int nparts = 0;
@@ -563,7 +564,7 @@ main(int argc, char *argv[])
bcfd = -1;
outfd = 1; /* Write to stdout by default */
- while ((c = getopt_long(argc, argv, "a:b:c:C:f:o:p:s:vyH:P:RS:T:",
+ while ((c = getopt_long(argc, argv, "a:b:c:C:f:o:p:s:t:vyH:P:S:T:",
longopts, NULL)) != -1) {
switch (c) {
case 'a': /* ACTIVE PARTITION, if supported */
@@ -608,9 +609,6 @@ main(int argc, char *argv[])
if (error)
errc(EX_DATAERR, error, "partition");
break;
- case 'R':
- reproducible = true;
- break;
case 's': /* SCHEME */
if (scheme_selected() != NULL)
usage("multiple schemes given");
@@ -618,6 +616,19 @@ main(int argc, char *argv[])
if (error)
errc(EX_DATAERR, error, "scheme");
break;
+ case 't': {
+ char *ep;
+ long long val;
+
+ errno = 0;
+ val = strtoll(optarg, &ep, 0);
+ if (ep == optarg || *ep != '\0')
+ errno = EINVAL;
+ if (errno != 0)
+ errc(EX_DATAERR, errno, "timestamp");
+ timestamp = (time_t)val;
+ break;
+ }
case 'y':
unit_testing++;
break;
@@ -680,9 +691,6 @@ main(int argc, char *argv[])
if (max_capacity != 0 && min_capacity > max_capacity)
usage("minimum capacity cannot be larger than the maximum one");
- if (reproducible)
- srandom(42);
-
if (secsz > blksz) {
if (blksz != 0)
errx(EX_DATAERR, "the physical block size cannot "
diff --git a/usr.bin/mkimg/mkimg.h b/usr.bin/mkimg/mkimg.h
index 608de458e83c..aa0ec2a8d944 100644
--- a/usr.bin/mkimg/mkimg.h
+++ b/usr.bin/mkimg/mkimg.h
@@ -29,9 +29,9 @@
#include <sys/queue.h>
#include <sys/types.h>
-#include <stdbool.h>
+#include <time.h>
-extern bool reproducible; /* Generate reproducible output. */
+extern time_t timestamp;
struct part {
TAILQ_ENTRY(part) link;
diff --git a/usr.bin/mkimg/uuid.c b/usr.bin/mkimg/uuid.c
index f3415a8c1111..885a6c36b522 100644
--- a/usr.bin/mkimg/uuid.c
+++ b/usr.bin/mkimg/uuid.c
@@ -57,9 +57,10 @@ osdep_uuidgen(mkimg_uuid_t *uuid)
u_int i;
uint16_t seq;
- if (reproducible)
- memset(&tv, 0, sizeof(tv));
- else if (gettimeofday(&tv, NULL) == -1)
+ if (timestamp != (time_t)-1) {
+ tv.tv_sec = timestamp;
+ tv.tv_usec = 0;
+ } else if (gettimeofday(&tv, NULL) == -1)
abort();
time += (uint64_t)tv.tv_sec * 10000000LL;
diff --git a/usr.bin/mkimg/vhd.c b/usr.bin/mkimg/vhd.c
index 1e1f1e7f3c3e..c0fe45ab416e 100644
--- a/usr.bin/mkimg/vhd.c
+++ b/usr.bin/mkimg/vhd.c
@@ -188,7 +188,7 @@ vhd_timestamp(void)
time_t t;
if (!unit_testing) {
- t = time(NULL);
+ t = timestamp != (time_t)-1 ? timestamp : time(NULL);
return (t - 0x386d4380);
}
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index 1a2c786e90aa..1931c38a1fad 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 30, 2025
+.Dd July 16, 2025
.Dt NETSTAT 1
.Os
.Sh NAME
@@ -166,7 +166,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl 4
Show IPv4 only.
@@ -416,7 +416,8 @@ When used with
or
.Fl 6 ,
limit the output to IPv4 or IPv6 routes respectively.
-This option provides details about individual nexthop addresses used in routing decisions.
+This option provides details about individual nexthop addresses
+used in routing decisions.
.It Xo
.Bk -words
.Nm netstat
@@ -430,7 +431,8 @@ When used with
or
.Fl 6 ,
restrict the output to IPv4 or IPv6 nexthop groups respectively.
-This option shows grouped nexthop entries for multipath or load-balanced routing setups.
+This option shows grouped nexthop entries for multipath or
+load-balanced routing setups.
.It Xo
.Bk -words
.Nm
@@ -926,25 +928,25 @@ binary is not available in the
.Sh EXAMPLES
Show packet traffic information (packets, bytes, errors, packet drops, etc) for
interface re0 updated every 2 seconds and exit after 5 outputs:
-.Bd -literal -offset indent
-$ netstat -w 2 -q 5 -I re0
-.Ed
+.Pp
+.Dl netstat -w 2 -q 5 -I re0
.Pp
Show statistics for ICMP on any interface:
-.Bd -literal -offset indent
-$ netstat -s -p icmp
-.Ed
+.Pp
+.Dl netstat -s -p icmp
.Pp
Show routing tables:
-.Bd -literal -offset indent
-$ netstat -r
-.Ed
+.Pp
+.Dl netstat -r
.Pp
Same as above, but without resolving numeric addresses and port numbers to
names:
-.Bd -literal -offset indent
-$ netstat -rn
-.Ed
+.Pp
+.Dl netstat -rn
+.Pp
+Show IPv4 listening sockets:
+.Pp
+.Dl netstat -4l
.Sh SEE ALSO
.Xr fstat 1 ,
.Xr nfsstat 1 ,
@@ -952,7 +954,7 @@ $ netstat -rn
.Xr ps 1 ,
.Xr sockstat 1 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr bpf 4 ,
.Xr inet 4 ,
.Xr route 4 ,
diff --git a/usr.bin/nfsstat/nfsstat.1 b/usr.bin/nfsstat/nfsstat.1
index 7d641b50f1ac..a4a00586f21b 100644
--- a/usr.bin/nfsstat/nfsstat.1
+++ b/usr.bin/nfsstat/nfsstat.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 28, 2023
+.Dd July 16, 2025
.Dt NFSSTAT 1
.Os
.Sh NAME
@@ -123,7 +123,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.El
.Sh SEE ALSO
diff --git a/usr.bin/procstat/procstat.1 b/usr.bin/procstat/procstat.1
index cc775ffe133b..b810abf66da7 100644
--- a/usr.bin/procstat/procstat.1
+++ b/usr.bin/procstat/procstat.1
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 7, 2022
+.Dd July 16, 2025
.Dt PROCSTAT 1
.Os
.Sh NAME
@@ -136,7 +136,7 @@ flag is specified the output is generated via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.Pp
The following commands are available for
@@ -377,6 +377,8 @@ eventfd
fifo
.It h
shared memory
+.It i
+inotify descriptor
.It k
kqueue
.It m
@@ -862,12 +864,13 @@ procstat: procstat_getprocs()
.Xr sockstat 1 ,
.Xr cap_enter 2 ,
.Xr cap_rights_limit 2 ,
+.Xr inotify 2 ,
.Xr mlock 2 ,
.Xr mlockall 2 ,
.Xr libprocstat 3 ,
.Xr libxo 3 ,
.Xr signal 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr ddb 4 ,
.Xr divert 4 ,
.Xr icmp 4 ,
diff --git a/usr.bin/procstat/procstat_files.c b/usr.bin/procstat/procstat_files.c
index d61cf1693053..aa4850632aa7 100644
--- a/usr.bin/procstat/procstat_files.c
+++ b/usr.bin/procstat/procstat_files.c
@@ -226,6 +226,10 @@ static struct cap_desc {
{ CAP_BINDAT, "ba" },
{ CAP_CONNECTAT, "ca" },
+ /* Inotify descriptor rights. */
+ { CAP_INOTIFY_ADD, "ina" },
+ { CAP_INOTIFY_RM, "inr" },
+
/* Aliases and defines that combine multiple rights. */
{ CAP_PREAD, "prd" },
{ CAP_PWRITE, "pwr" },
@@ -416,6 +420,11 @@ procstat_files(struct procstat *procstat, struct kinfo_proc *kipp)
xo_emit("{eq:fd_type/eventfd}");
break;
+ case PS_FST_TYPE_INOTIFY:
+ str = "i";
+ xo_emit("{eq:fd_type/inotify}");
+ break;
+
case PS_FST_TYPE_NONE:
str = "?";
xo_emit("{eq:fd_type/none}");
diff --git a/usr.bin/sed/sed.1 b/usr.bin/sed/sed.1
index 345f673310d8..5fd894eaf78b 100644
--- a/usr.bin/sed/sed.1
+++ b/usr.bin/sed/sed.1
@@ -1,3 +1,6 @@
+.\"
+.\" SPDX-License-Identifier: BSD-3-Clause
+.\"
.\" Copyright (c) 1992, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -28,7 +31,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 17, 2024
+.Dd June 14, 2025
.Dt SED 1
.Os
.Sh NAME
@@ -597,17 +600,17 @@ with
.Ql baz
when piped from another command:
.Bd -literal -offset indent
-echo "An alternate word, like bar, is sometimes used in examples." | sed 's/bar/baz/'
+echo "use bar in examples" | sed 's/bar/baz/'
.Ed
.Pp
Using backlashes can sometimes be hard to read and follow:
.Bd -literal -offset indent
-echo "/home/example" | sed 's/\\/home\\/example/\\/usr\\/local\\/example/'
+echo "/bin/bash" | sed 's/\\/bin\\/bash/\\/bin\\/sh/'
.Ed
.Pp
Using a different separator can be handy when working with paths:
.Bd -literal -offset indent
-echo "/home/example" | sed 's#/home/example#/usr/local/example#'
+echo "/bin/bash" | sed 's#/bin/bash#/bin/sh#'
.Ed
.Pp
Replace all occurrences of
diff --git a/usr.bin/shar/Makefile b/usr.bin/shar/Makefile
deleted file mode 100644
index fc940c06d463..000000000000
--- a/usr.bin/shar/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-SCRIPTS=shar.sh
-MAN= shar.1
-
-.include <bsd.prog.mk>
diff --git a/usr.bin/shar/Makefile.depend b/usr.bin/shar/Makefile.depend
deleted file mode 100644
index 11aba52f82cf..000000000000
--- a/usr.bin/shar/Makefile.depend
+++ /dev/null
@@ -1,10 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DIRDEPS = \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/usr.bin/shar/shar.1 b/usr.bin/shar/shar.1
deleted file mode 100644
index 6beb1e84ceab..000000000000
--- a/usr.bin/shar/shar.1
+++ /dev/null
@@ -1,121 +0,0 @@
-.\" Copyright (c) 1990, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.Dd January 1, 2025
-.Dt SHAR 1
-.Os
-.Sh NAME
-.Nm shar
-.Nd create a shell archive of files
-.Sh DEPRECATION NOTICE
-.Nm
-is obsolete and may not be present in
-.Fx 15
-and later.
-Because shell archives are simultaneously data and code and are typically
-interpreted by
-.Xr sh 1 ,
-they can easily be trojan-horsed and pose a significant security risk to users.
-The
-.Xr tar 1
-utility can still produce shar encodings of files if needed.
-The
-.Pa sysutils/freebsd-shar
-port has been created to maintain this version of
-.Nm
-past its deprecation in base.
-.Sh SYNOPSIS
-.Nm
-.Ar
-.Sh DESCRIPTION
-The
-.Nm
-command writes a
-.Xr sh 1
-shell script to the standard output which will recreate the file
-hierarchy specified by the command line operands.
-Directories will be recreated and must be specified before the
-files they contain (the
-.Xr find 1
-utility does this correctly).
-.Pp
-The
-.Nm
-command is normally used for distributing files by
-.Xr ftp 1
-or
-.Xr mail 1 .
-.Sh EXAMPLES
-To create a shell archive of the program
-.Xr ls 1
-and mail it to Rick:
-.Bd -literal -offset indent
-cd ls
-shar `find . -print` \&| mail -s "ls source" rick
-.Ed
-.Pp
-To recreate the program directory:
-.Bd -literal -offset indent
-mkdir ls
-cd ls
-\&...
-<delete header lines and examine mailed archive>
-\&...
-sh archive
-.Ed
-.Sh SEE ALSO
-.Xr compress 1 ,
-.Xr mail 1 ,
-.Xr tar 1 ,
-.Xr uuencode 1
-.Sh HISTORY
-The
-.Nm
-command appeared in
-.Bx 4.4 .
-.Sh BUGS
-The
-.Nm
-command makes no provisions for special types of files or files containing
-magic characters.
-The
-.Nm
-command cannot handle files without a newline ('\\n')
-as the last character.
-.Pp
-It is easy to insert trojan horses into
-.Nm
-files.
-It is strongly recommended that all shell archive files be examined
-before running them through
-.Xr sh 1 .
-Archives produced using this implementation of
-.Nm
-may be easily examined with the command:
-.Bd -literal -offset indent
-egrep -av '^[X#]' shar.file
-.Ed
diff --git a/usr.bin/shar/shar.sh b/usr.bin/shar/shar.sh
deleted file mode 100644
index 52c31b419fc4..000000000000
--- a/usr.bin/shar/shar.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/sh -
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-# Copyright (c) 1990, 1993
-# The Regents of the University of California. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. Neither the name of the University nor the names of its contributors
-# may be used to endorse or promote products derived from this software
-# without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-
-if [ $# -eq 0 ]; then
- echo 'usage: shar file ...' 1>&2
- exit 64 # EX_USAGE
-fi
-
-for i
-do
- if [ ! \( -d $i -o -r $i \) ]; then
- echo "$i inaccessible or not exist" 1>&2
- exit 66 # EX_NOINPUT
- fi
-done
-
-cat << EOF
-# This is a shell archive. Save it in a file, remove anything before
-# this line, and then unpack it by entering "sh file". Note, it may
-# create directories; files and directories will be owned by you and
-# have default permissions.
-#
-# This archive contains:
-#
-EOF
-
-for i
-do
- echo "# $i"
-done
-
-echo "#"
-
-for i
-do
- if [ -d "$i" ]; then
- echo "echo c - '$i'"
- echo "mkdir -p '$i' > /dev/null 2>&1"
- else
- md5sum=`echo -n "$i" | md5`
- echo "echo x - '$i'"
- echo "sed 's/^X//' >'$i' << '$md5sum'"
- sed 's/^/X/' "$i" || exit 1
- echo "$md5sum"
- fi
-done
-echo exit
-echo ""
-
-exit 0
diff --git a/usr.bin/sockstat/sockstat.1 b/usr.bin/sockstat/sockstat.1
index da658e33e542..4832a09764fd 100644
--- a/usr.bin/sockstat/sockstat.1
+++ b/usr.bin/sockstat/sockstat.1
@@ -25,7 +25,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd June 27, 2025
+.Dd June 30, 2025
.Dt SOCKSTAT 1
.Os
.Sh NAME
@@ -33,7 +33,7 @@
.Nd list open sockets
.Sh SYNOPSIS
.Nm
-.Op Fl 46ACcfIiLlnqSsUuv
+.Op Fl 46ACcfIiLlnqSsUuvw
.Op Fl j Ar jail
.Op Fl p Ar ports
.Op Fl P Ar protocols
@@ -119,6 +119,8 @@ Show
sockets.
.It Fl v
Verbose mode.
+.It Fl w
+Automatically size the columns.
.El
.Pp
If neither
diff --git a/usr.bin/sockstat/sockstat.c b/usr.bin/sockstat/sockstat.c
index 52243910a31c..d0540c54a1aa 100644
--- a/usr.bin/sockstat/sockstat.c
+++ b/usr.bin/sockstat/sockstat.c
@@ -97,6 +97,7 @@ static bool opt_s; /* Show protocol state if applicable */
static bool opt_U; /* Show remote UDP encapsulation port number */
static bool opt_u; /* Show Unix domain sockets */
static u_int opt_v; /* Verbose mode */
+static bool opt_w; /* Automatically size the columns */
/*
* Default protocols to use if no -P was defined.
@@ -951,7 +952,7 @@ formataddr(struct sockaddr_storage *ss, char *buf, size_t bufsize)
}
if (addrstr[0] == '\0') {
error = cap_getnameinfo(capnet, sstosa(ss), ss->ss_len,
- addrstr, sizeof(addrstr), buf, bufsize, NI_NUMERICHOST);
+ addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST);
if (error)
errx(1, "cap_getnameinfo()");
}
@@ -1101,7 +1102,7 @@ format_unix_faddr(struct addr *faddr, char *buf, size_t bufsize) {
/* Remote peer we connect(2) to, if any. */
if (faddr->conn != 0) {
struct sock *p;
- pos += strlcpy(buf, "-> ", bufsize);
+ pos += strlcpy(SAFEBUF, "-> ", SAFESIZE);
p = RB_FIND(pcbs_t, &pcbs,
&(struct sock){ .pcb = faddr->conn });
if (__predict_false(p == NULL)) {
@@ -1132,8 +1133,7 @@ format_unix_faddr(struct addr *faddr, char *buf, size_t bufsize) {
while ((p = RB_FIND(pcbs_t, &pcbs,
&(struct sock){ .pcb = ref })) != 0) {
f = RB_FIND(files_t, &ftree,
- &(struct file){ .xf_data =
- p->socket });
+ &(struct file){ .xf_data = p->socket });
if (f != NULL) {
pos += snprintf(SAFEBUF, SAFESIZE,
"%s[%lu %d]", fref ? "" : ",",
@@ -1178,13 +1178,10 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
len = strlen(s->protoname);
if (s->vflag & (INP_IPV4 | INP_IPV6))
len += 1;
- if (laddr != NULL && faddr != NULL && s->family == AF_UNIX &&
- laddr->address.ss_len == 0 && faddr->conn == 0)
- len += strlen(" (not connected)");
cw->proto = MAX(cw->proto, len);
while (laddr != NULL || faddr != NULL) {
- if (s->family == AF_UNIX) {
+ if (opt_w && s->family == AF_UNIX) {
if ((laddr == NULL) || (faddr == NULL))
errx(1, "laddr = %p or faddr = %p is NULL",
(void *)laddr, (void *)faddr);
@@ -1193,7 +1190,7 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
cw->local_addr = MAX(cw->local_addr, len);
len = format_unix_faddr(faddr, NULL, 0);
cw->foreign_addr = MAX(cw->foreign_addr, len);
- } else {
+ } else if (opt_w) {
if (laddr != NULL) {
len = formataddr(&laddr->address, NULL, 0);
cw->local_addr = MAX(cw->local_addr, len);
@@ -1296,23 +1293,6 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
static void
calculate_column_widths(struct col_widths *cw)
{
- cw->user = 4;
- cw->command = 10;
- cw->pid = 3;
- cw->fd = 2;
- cw->proto = 5;
- cw->local_addr = 13;
- cw->foreign_addr = 15;
- cw->pcb_kva = 18;
- cw->fib = 3;
- cw->splice_address = 14;
- cw->inp_gencnt = 2;
- cw->encaps = 6;
- cw->path_state = 10;
- cw->conn_state = 10;
- cw->stack = 5;
- cw->cc = 2;
-
int n, len;
struct file *xf;
struct sock *s;
@@ -1366,13 +1346,10 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
faddr = s->faddr;
first = true;
- snprintf(buf, bufsize, "%s%s%s%s",
+ snprintf(buf, bufsize, "%s%s%s",
s->protoname,
s->vflag & INP_IPV4 ? "4" : "",
- s->vflag & INP_IPV6 ? "6" : "",
- (laddr != NULL && faddr != NULL &&
- s->family == AF_UNIX && laddr->address.ss_len == 0 &&
- faddr->conn == 0) ? " (not connected)" : "");
+ s->vflag & INP_IPV6 ? "6" : "");
printf(" %-*s", cw->proto, buf);
while (laddr != NULL || faddr != NULL) {
if (s->family == AF_UNIX) {
@@ -1381,23 +1358,27 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
(void *)laddr, (void *)faddr);
if (laddr->address.ss_len > 0)
formataddr(&laddr->address, buf, bufsize);
+ else if (laddr->address.ss_len == 0 && faddr->conn == 0)
+ strlcpy(buf, "(not connected)", bufsize);
else
strlcpy(buf, "??", bufsize);
- printf(" %-*s", cw->local_addr, buf);
+ printf(" %-*.*s", cw->local_addr, cw->local_addr, buf);
if (format_unix_faddr(faddr, buf, bufsize) == 0)
strlcpy(buf, "??", bufsize);
- printf(" %-*s", cw->foreign_addr, buf);
+ printf(" %-*.*s", cw->foreign_addr,
+ cw->foreign_addr, buf);
} else {
if (laddr != NULL)
formataddr(&laddr->address, buf, bufsize);
else
strlcpy(buf, "??", bufsize);
- printf(" %-*s", cw->local_addr, buf);
+ printf(" %-*.*s", cw->local_addr, cw->local_addr, buf);
if (faddr != NULL)
formataddr(&faddr->address, buf, bufsize);
else
strlcpy(buf, "??", bufsize);
- printf(" %-*s", cw->foreign_addr, buf);
+ printf(" %-*.*s", cw->foreign_addr,
+ cw->foreign_addr, buf);
}
if (opt_A)
printf(" %#*" PRIx64, cw->pcb_kva, s->pcb);
@@ -1411,6 +1392,8 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
if (sp != NULL)
formataddr(&sp->laddr->address,
buf, bufsize);
+ else
+ strlcpy(buf, "??", bufsize);
} else
strlcpy(buf, "??", bufsize);
printf(" %-*s", cw->splice_address, buf);
@@ -1510,6 +1493,25 @@ display(void)
err(1, "malloc()");
return;
}
+
+ cw = (struct col_widths) {
+ .user = strlen("USER"),
+ .command = 10,
+ .pid = strlen("PID"),
+ .fd = strlen("FD"),
+ .proto = strlen("PROTO"),
+ .local_addr = opt_w ? strlen("LOCAL ADDRESS") : 21,
+ .foreign_addr = opt_w ? strlen("FOREIGN ADDRESS") : 21,
+ .pcb_kva = 18,
+ .fib = strlen("FIB"),
+ .splice_address = strlen("SPLICE ADDRESS"),
+ .inp_gencnt = strlen("ID"),
+ .encaps = strlen("ENCAPS"),
+ .path_state = strlen("PATH STATE"),
+ .conn_state = strlen("CONN STATE"),
+ .stack = strlen("STACK"),
+ .cc = strlen("CC"),
+ };
calculate_column_widths(&cw);
if (!opt_q) {
@@ -1642,7 +1644,7 @@ static void
usage(void)
{
errx(1,
- "usage: sockstat [-46ACcfIiLlnqSsUuv] [-j jid] [-p ports] [-P protocols]");
+ "usage: sockstat [-46ACcfIiLlnqSsUuvw] [-j jid] [-p ports] [-P protocols]");
}
int
@@ -1721,7 +1723,7 @@ main(int argc, char *argv[])
++opt_v;
break;
case 'w':
- /* left for backward compatibility. */
+ opt_w = true;
break;
default:
usage();
diff --git a/usr.bin/top/top.1 b/usr.bin/top/top.1
index d8ef763e7a34..53b078839526 100644
--- a/usr.bin/top/top.1
+++ b/usr.bin/top/top.1
@@ -1,4 +1,4 @@
-.Dd April 1, 2025
+.Dd June 9, 2025
.Dt TOP 1
.Os
.Sh NAME
@@ -398,6 +398,7 @@ ID corresponding to the process,
USERNAME is the name of the process's owner (if
.Fl u
is specified, a UID column will be substituted for USERNAME),
+THR is the thread count, showing the number of threads a process has,
PRI is the current priority of the process,
NICE is the
.Xr nice 1
diff --git a/usr.bin/truncate/truncate.1 b/usr.bin/truncate/truncate.1
index f6b8b0cc37c9..aa70943b889f 100644
--- a/usr.bin/truncate/truncate.1
+++ b/usr.bin/truncate/truncate.1
@@ -1,4 +1,6 @@
.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
.\" Copyright (c) 2000 Sheldon Hearn <sheldonh@FreeBSD.org>.
.\" All rights reserved.
.\" Copyright (c) 2021 The FreeBSD Foundation
@@ -27,12 +29,12 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 6, 2025
+.Dd July 9, 2025
.Dt TRUNCATE 1
.Os
.Sh NAME
.Nm truncate
-.Nd truncate, extend the length of files, or perform space management in files
+.Nd resize files or manage file space
.Sh SYNOPSIS
.Nm
.Op Fl c
@@ -132,7 +134,8 @@ file system space deallocation may be performed in the operation region.
The space management operation is performed at the given
.Ar offset
bytes in the file.
-If this option is not specified, the operation is performed at the beginning of the file.
+If this option is not specified,
+the operation is performed at the beginning of the file.
.It Fl l Ar length
The length of the operation range in bytes.
This option must always be specified if option
@@ -195,9 +198,9 @@ truncate -c -s 10M test_file
.Pp
Same as above but create the file if it does not exist:
.Bd -literal -offset indent
-truncate -s 10M test_file
-ls -l test_file
--rw-r--r-- 1 root wheel 10485760 Jul 22 18:48 test_file
+truncate -s +10M test_file
+ls -lh test_file
+-rw-r--r-- 1 root wheel 10M Jul 22 18:48 test_file
.Ed
.Pp
Adjust the size of
@@ -207,10 +210,10 @@ to the size of the kernel and create another file
with the same size:
.Bd -literal -offset indent
truncate -r /boot/kernel/kernel test_file test_file2
-ls -l /boot/kernel/kernel test_file*
--r-xr-xr-x 1 root wheel 31352552 May 15 14:18 /boot/kernel/kernel
--rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file
--rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file2
+ls -lh /boot/kernel/kernel test_file*
+-r--r--r-- 1 root wheel 30M May 15 14:18 /boot/kernel/kernel
+-rw-r--r-- 1 root wheel 30M Jul 22 19:15 test_file
+-rw-r--r-- 1 root wheel 30M Jul 22 19:15 test_file2
.Ed
.Pp
Increase the size of the file
@@ -228,9 +231,9 @@ Reduce the size of the file
by 5 megabytes:
.Bd -literal -offset indent
truncate -s -5M test_file
-ls -l test_file*
--rw-r--r-- 1 root wheel 31352552 Jul 22 19:19 test_file
--rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file2
+ls -lh test_file*
+-rw-r--r-- 1 root wheel 25M Jul 22 19:17 test_file
+-rw-r--r-- 1 root wheel 30M Jul 22 19:15 test_file2
.Ed
.Sh SEE ALSO
.Xr dd 1 ,
@@ -247,6 +250,7 @@ The
utility first appeared in
.Fx 4.2 .
.Sh AUTHORS
+.An -nosplit
The
.Nm
utility was written by
diff --git a/usr.bin/truss/syscall.h b/usr.bin/truss/syscall.h
index d79ef882cff0..47d973326dfb 100644
--- a/usr.bin/truss/syscall.h
+++ b/usr.bin/truss/syscall.h
@@ -99,6 +99,7 @@ enum Argtype {
Getfsstatmode,
Idtype,
Ioctl,
+ Inotifyflags,
Itimerwhich,
Kldsymcmd,
Kldunloadflags,
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c
index 47d6aef8f6ff..656d642e1f19 100644
--- a/usr.bin/truss/syscalls.c
+++ b/usr.bin/truss/syscalls.c
@@ -31,7 +31,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
/*
* This file has routines used to print out system calls and their
* arguments.
@@ -316,6 +315,9 @@ static const struct syscall_decode decoded_syscalls[] = {
{ Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
{ .name = "gettimeofday", .ret_type = 1, .nargs = 2,
.args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
+ { .name = "inotify_add_watch_at", .ret_type = 1, .nargs = 4,
+ .args = { { Int, 0 }, { Atfd, 1 }, { Name | IN, 2 },
+ { Inotifyflags, 3 } } },
{ .name = "ioctl", .ret_type = 1, .nargs = 3,
.args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
{ .name = "kevent", .ret_type = 1, .nargs = 6,
@@ -2447,6 +2449,9 @@ print_arg(struct syscall_arg *sc, syscallarg_t *args, syscallarg_t *retval,
print_integer_arg(sysdecode_getfsstat_mode, fp,
args[sc->offset]);
break;
+ case Inotifyflags:
+ print_mask_arg(sysdecode_inotifyflags, fp, args[sc->offset]);
+ break;
case Itimerwhich:
print_integer_arg(sysdecode_itimer, fp, args[sc->offset]);
break;
diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8
index de4176c9361c..80facb05cc35 100644
--- a/usr.bin/vmstat/vmstat.8
+++ b/usr.bin/vmstat/vmstat.8
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 21, 2021
+.Dd July 16, 2025
.Dt VMSTAT 8
.Os
.Sh NAME
@@ -71,7 +71,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl a
When used with
@@ -371,7 +371,7 @@ statistics every second.
.Xr systat 1 ,
.Xr libmemstat 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr gstat 8 ,
.Xr iostat 8 ,
.Xr pstat 8 ,
diff --git a/usr.bin/w/w.1 b/usr.bin/w/w.1
index a92edc6f0059..159eb3370c8c 100644
--- a/usr.bin/w/w.1
+++ b/usr.bin/w/w.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 24, 2020
+.Dd July 16, 2025
.Dt W 1
.Os
.Sh NAME
@@ -61,7 +61,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl d
dumps out the entire process list on a per controlling
@@ -145,7 +145,7 @@ flags are no longer supported.
.Xr uptime 1 ,
.Xr who 1 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3
+.Xr xo_options 7
.Sh HISTORY
The
.Nm
diff --git a/usr.bin/wc/wc.1 b/usr.bin/wc/wc.1
index 482145c8f01f..656408794950 100644
--- a/usr.bin/wc/wc.1
+++ b/usr.bin/wc/wc.1
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 11, 2020
+.Dd July 16, 2025
.Dt WC 1
.Os
.Sh NAME
@@ -70,7 +70,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl L
Write the length of the line containing the most bytes (default) or characters
@@ -196,7 +196,7 @@ utility.
.Sh SEE ALSO
.Xr iswspace 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3
+.Xr xo_options 7
.Sh STANDARDS
The
.Nm
diff --git a/usr.sbin/arp/arp.8 b/usr.sbin/arp/arp.8
index d31b2b482ba3..0a171c9e36be 100644
--- a/usr.sbin/arp/arp.8
+++ b/usr.sbin/arp/arp.8
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 13, 2020
+.Dd July 16, 2025
.Dt ARP 8
.Os
.Sh NAME
@@ -80,7 +80,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl a
The program displays or, if it is used with the
@@ -183,7 +183,7 @@ character will mark the rest of the line as a comment.
.Sh SEE ALSO
.Xr inet 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr arp 4 ,
.Xr ifconfig 8 ,
.Xr ndp 8
diff --git a/usr.sbin/bluetooth/bluetooth-config/bluetooth-config.sh b/usr.sbin/bluetooth/bluetooth-config/bluetooth-config.sh
index 48a399a82fc7..148325fcecbc 100755
--- a/usr.sbin/bluetooth/bluetooth-config/bluetooth-config.sh
+++ b/usr.sbin/bluetooth/bluetooth-config/bluetooth-config.sh
@@ -17,7 +17,7 @@ main() {
unset node device started bdaddresses retry
# Only one command at the moment is scan (+ add)
-[ "$#" -eq 1 -a "$1" = "scan" ] || print_syntax
+[ "$1" = "scan" ] || print_syntax
shift
# Get command line options
@@ -28,6 +28,12 @@ while getopts :d:n: arg; do
?) print_syntax;;
esac
done
+shift "$((OPTIND-1))"
+
+# If there's leftover parameters, print usage
+[ "$#" -eq 0 ] || print_syntax
+shift
+
# No use running without super user rights
if [ $( id -u ) -ne 0 ]; then
diff --git a/usr.sbin/bsdinstall/scripts/pkgbase.in b/usr.sbin/bsdinstall/scripts/pkgbase.in
index 1ff93afe817b..cf8e84de6923 100755
--- a/usr.sbin/bsdinstall/scripts/pkgbase.in
+++ b/usr.sbin/bsdinstall/scripts/pkgbase.in
@@ -234,12 +234,17 @@ local function pkgbase()
local chroot = assert(os.getenv("BSDINSTALL_CHROOT"))
assert(os.execute("mkdir -p " .. chroot))
+ -- Always install the default FreeBSD-base.conf file to the chroot, even
+ -- if we don't actually fetch the packages from the repository specified
+ -- there (e.g. because we are performing an offline installation).
+ local chroot_repos_dir = chroot .. "/usr/local/etc/pkg/repos/"
+ assert(os.execute("mkdir -p " .. chroot_repos_dir))
+ assert(os.execute("cp /usr/share/bsdinstall/FreeBSD-base.conf " ..
+ chroot_repos_dir))
+
local repos_dir = os.getenv("BSDINSTALL_PKG_REPOS_DIR")
if not repos_dir then
- repos_dir = chroot .. "/usr/local/etc/pkg/repos/"
- assert(os.execute("mkdir -p " .. repos_dir))
- assert(os.execute("cp /usr/share/bsdinstall/FreeBSD-base.conf " .. repos_dir))
-
+ repos_dir = chroot_repos_dir
-- Since pkg always interprets fingerprints paths as relative to
-- the --rootdir we must copy the key from the host.
assert(os.execute("mkdir -p " .. chroot .. "/usr/share/keys"))
diff --git a/usr.sbin/bsdinstall/scripts/wlanconfig b/usr.sbin/bsdinstall/scripts/wlanconfig
index 8ac64858eaba..33d94a933f45 100755
--- a/usr.sbin/bsdinstall/scripts/wlanconfig
+++ b/usr.sbin/bsdinstall/scripts/wlanconfig
@@ -92,7 +92,7 @@ dialog_country_select()
sub(/.*domains:/, ""), /[^[:alnum:][[:space:]]/ {
n = split($0, domains)
for (i = 1; i <= n; i++)
- printf "'\''%s'\'' '\'\''", domains[i]
+ printf "'\''%s'\'' '\'\''\n", domains[i]
}
' | sort )
countries=$( echo "$input" | awk '
@@ -200,6 +200,12 @@ fi
while :; do
SCANSSID=0
+ # While wpa_supplicant may IFF_UP the interface, we do not want to rely
+ # in this. In case the script is run manually (outside the installer,
+ # e.g., for testing) wpa_supplicant may be running and the wlanN
+ # interface may be down (especially if dialog_country_select is not
+ # run successfully either) and scanning will not work.
+ f_eval_catch -d wlanconfig ifconfig "ifconfig $WLAN_IFACE up"
f_eval_catch -d wlanconfig wpa_cli "wpa_cli scan"
f_dialog_title "Scanning"
f_dialog_pause "Waiting 5 seconds to scan for wireless networks..." 5 ||
diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
index 9d5a693c7c68..9252e63749bb 100644
--- a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
+++ b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
@@ -1179,8 +1179,10 @@ main(int argc, char ** argv)
/* On -h (help) exit without error. */
if (opt_num == -2)
exit(0);
- else
+ else {
+ fprintf(stderr, "Error: %s\n", snmp_client.error);
exit(1);
+ }
}
oid_cnt = argc - opt_num - 1;
@@ -1239,7 +1241,7 @@ main(int argc, char ** argv)
}
if (snmp_open(NULL, NULL, NULL, NULL)) {
- warn("Failed to open snmp session");
+ fprintf(stderr, "snmp_open(3): %s\n", snmp_client.error);
snmp_tool_freeall(&snmptoolctx);
exit(1);
}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
index fb09e1ac785e..b4613763fff5 100644
--- a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
@@ -790,15 +790,6 @@ parse_server(char *opt_arg)
if (snmp_parse_server(&snmp_client, opt_arg) < 0)
return (-1);
- if (snmp_client.trans > SNMP_TRANS_UDP && snmp_client.chost == NULL) {
- if ((snmp_client.chost = malloc(strlen(SNMP_DEFAULT_LOCAL) + 1))
- == NULL) {
- syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
- return (-1);
- }
- strcpy(snmp_client.chost, SNMP_DEFAULT_LOCAL);
- }
-
return (2);
}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
index 2874f311fbd0..54a087491a4f 100644
--- a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
@@ -43,7 +43,6 @@
#define MAX_BUFF_SIZE (ASN_MAXOCTETSTRING + 50)
#define SNMP_DEFS_DIR "/usr/share/snmp/defs/"
-#define SNMP_DEFAULT_LOCAL "/var/run/snmpd.sock"
#define SNMP_MAX_REPETITIONS 10
diff --git a/usr.sbin/certctl/certctl.8 b/usr.sbin/certctl/certctl.8
index 286072c1b4d6..7e49bb89e2ac 100644
--- a/usr.sbin/certctl/certctl.8
+++ b/usr.sbin/certctl/certctl.8
@@ -24,7 +24,7 @@
.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd October 10, 2023
+.Dd July 17, 2025
.Dt CERTCTL 8
.Os
.Sh NAME
@@ -38,15 +38,15 @@
.Op Fl v
.Ic untrusted
.Nm
-.Op Fl nUv
+.Op Fl cnUv
.Op Fl D Ar destdir
.Op Fl M Ar metalog
.Ic rehash
.Nm
-.Op Fl nv
+.Op Fl cnv
.Ic untrust Ar file
.Nm
-.Op Fl nv
+.Op Fl cnv
.Ic trust Ar file
.Sh DESCRIPTION
The
@@ -56,6 +56,8 @@ applications that use OpenSSL.
.Pp
Flags:
.Bl -tag -width 4n
+.It Fl c
+Copy certificates instead of linking to them.
.It Fl D Ar destdir
Specify the DESTDIR (overriding values from the environment).
.It Fl d Ar distbase
diff --git a/usr.sbin/certctl/certctl.sh b/usr.sbin/certctl/certctl.sh
index 458f5c53682f..2bde651de126 100755
--- a/usr.sbin/certctl/certctl.sh
+++ b/usr.sbin/certctl/certctl.sh
@@ -36,6 +36,7 @@ set -u
############################################################ GLOBALS
SCRIPTNAME="${0##*/}"
+LINK=-lrs
ERRORS=0
NOOP=false
UNPRIV=false
@@ -110,7 +111,6 @@ create_trusted()
{
local hash certhash otherfile otherhash
local suffix
- local link=${2:+-lrs}
hash=$(do_hash "$1") || return
certhash=$(openssl x509 -sha1 -in "$1" -noout -fingerprint)
@@ -130,7 +130,7 @@ create_trusted()
done
suffix=$(get_decimal "$CERTDESTDIR" "$hash")
verbose "Adding $hash.$suffix to trust store"
- perform install ${INSTALLFLAGS} -m 0444 ${link} \
+ perform install ${INSTALLFLAGS} -m 0444 ${LINK} \
"$(realpath "$1")" "$CERTDESTDIR/$hash.$suffix"
}
@@ -159,7 +159,6 @@ resolve_certname()
create_untrusted()
{
local srcfile filename
- local link=${2:+-lrs}
set -- $(resolve_certname "$1")
srcfile=$1
@@ -170,7 +169,7 @@ create_untrusted()
fi
verbose "Adding $filename to untrusted list"
- perform install ${INSTALLFLAGS} -m 0444 ${link} \
+ perform install ${INSTALLFLAGS} -m 0444 ${LINK} \
"$srcfile" "$UNTRUSTDESTDIR/$filename"
}
@@ -190,7 +189,7 @@ do_scan()
0)
;;
1)
- "$CFUNC" "$CFILE" link
+ "$CFUNC" "$CFILE"
;;
*)
verbose "Multiple certificates found, splitting..."
@@ -303,19 +302,20 @@ usage()
echo " List trusted certificates"
echo " $SCRIPTNAME [-v] untrusted"
echo " List untrusted certificates"
- echo " $SCRIPTNAME [-nUv] [-D <destdir>] [-d <distbase>] [-M <metalog>] rehash"
- echo " Generate hash links for all certificates"
- echo " $SCRIPTNAME [-nv] untrust <file>"
+ echo " $SCRIPTNAME [-cnUv] [-D <destdir>] [-d <distbase>] [-M <metalog>] rehash"
+ echo " Rehash all trusted and untrusted certificates"
+ echo " $SCRIPTNAME [-cnv] untrust <file>"
echo " Add <file> to the list of untrusted certificates"
- echo " $SCRIPTNAME [-nv] trust <file>"
+ echo " $SCRIPTNAME [-cnv] trust <file>"
echo " Remove <file> from the list of untrusted certificates"
exit 64
}
############################################################ MAIN
-while getopts D:d:M:nUv flag; do
+while getopts cD:d:M:nUv flag; do
case "$flag" in
+ c) LINK=-c ;;
D) DESTDIR=${OPTARG} ;;
d) DISTBASE=${OPTARG} ;;
M) METALOG=${OPTARG} ;;
@@ -334,7 +334,7 @@ fi
: ${METALOG:=${DESTDIR}/METALOG}
INSTALLFLAGS=
if "$UNPRIV" ; then
- INSTALLFLAGS="-U -M ${METALOG} -D ${DESTDIR} -o root -g wheel"
+ INSTALLFLAGS="-U -M ${METALOG} -D ${DESTDIR:-/} -o root -g wheel"
fi
: ${LOCALBASE:=$(sysctl -n user.localbase)}
: ${TRUSTPATH:=${DESTDIR}${DISTBASE}/usr/share/certs/trusted:${DESTDIR}${LOCALBASE}/share/certs:${DESTDIR}${LOCALBASE}/etc/ssl/certs}
diff --git a/usr.sbin/crunch/examples/really-big.conf b/usr.sbin/crunch/examples/really-big.conf
index 12c08b73936f..9c227a7b8d29 100644
--- a/usr.sbin/crunch/examples/really-big.conf
+++ b/usr.sbin/crunch/examples/really-big.conf
@@ -52,7 +52,7 @@ progs tty ul uname unexpand unifdef uniq units unvis users uudecode uuencode
progs vacation vgrind vi vis vmstat w wall wc what whatis whereis who
progs whois window write xargs xinstall xstr yacc yes ypcat ypmatch ypwhich
-# shell scripts: lorder mkdep shar which
+# shell scripts: lorder mkdep which
# problems: rdist uses libcompat.a(regex.o), which conflicts with
# libedit(readline.o) over regerror().
diff --git a/usr.sbin/efitable/efitable.8 b/usr.sbin/efitable/efitable.8
index d1f4cedcdea8..52949abcb853 100644
--- a/usr.sbin/efitable/efitable.8
+++ b/usr.sbin/efitable/efitable.8
@@ -1,4 +1,6 @@
.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
.\" Copyright (c) 2021 3mdeb Embedded Systems Consulting <contact@3mdeb.com>
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -22,12 +24,12 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 10, 2021
+.Dd July 16, 2025
.Dt EFITABLE 8
.Os
.Sh NAME
.Nm efitable
-.Nd Dump UEFI tables
+.Nd dump UEFI tables
.Sh SYNOPSIS
.Nm
.Op Fl u Ar uuid | Fl t Ar name
@@ -39,28 +41,29 @@ This program prints data from
tables.
.Pp
The following options are available:
-.Bl -tag -width 20m
+.Bl -tag -width "-t name | --table name"
.It Fl -libxo
Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
-.It Fl t Ar name Fl -table Ar name
+.It Fl t Ar name | Fl -table Ar name
Specify the name of the table to print.
Currently supported tables:
.Pp
.Bl -tag -width indent -compact
.It Cm esrt
EFI System Resource Table
+.It Cm memory
+EFI Memory Attributes Table
.It Cm prop
EFI Properties Table
.El
-.It Fl u Ar uuid Fl -uuid Ar uuid
+.It Fl u Ar uuid | Fl -uuid Ar uuid
Specify the UUID of the table to print.
.El
-.Pp
.Sh HISTORY
The
.Nm
diff --git a/usr.sbin/efitable/efitable.c b/usr.sbin/efitable/efitable.c
index 0eee72801592..a506b4dea311 100644
--- a/usr.sbin/efitable/efitable.c
+++ b/usr.sbin/efitable/efitable.c
@@ -44,6 +44,7 @@
static void efi_table_print_esrt(const void *data);
static void efi_table_print_prop(const void *data);
+static void efi_table_print_memory(const void *data);
static void usage(void) __dead2;
struct efi_table_op {
@@ -56,7 +57,9 @@ static const struct efi_table_op efi_table_ops[] = {
{ .name = "esrt", .parse = efi_table_print_esrt,
.guid = EFI_TABLE_ESRT },
{ .name = "prop", .parse = efi_table_print_prop,
- .guid = EFI_PROPERTIES_TABLE }
+ .guid = EFI_PROPERTIES_TABLE },
+ { .name = "memory", .parse = efi_table_print_memory,
+ .guid = EFI_MEMORY_ATTRIBUTES_TABLE }
};
int
@@ -239,6 +242,51 @@ efi_table_print_prop(const void *data)
xo_err(EX_IOERR, "stdout");
}
+static void
+efi_table_print_memory(const void *data)
+{
+ const struct efi_memory_attribute_table *attr =
+ (const struct efi_memory_attribute_table *)data;
+ const struct efi_memory_descriptor *desc;
+ int i, nentries;
+
+ nentries = attr->num_ents;
+ desc = attr->tables;
+
+ xo_set_version(EFITABLE_XO_VERSION);
+
+ xo_open_container("memory");
+ xo_emit("{Lwc:Version}{:version/%#x}\n", attr->version);
+ xo_emit("{Lwc:Length}{:length/%u}\n", attr->descriptor_size);
+ xo_emit("{Lwc:Entries}{:entries/%u}\n", attr->num_ents);
+
+ xo_open_container("attributes");
+
+ /*
+ * According to https://forum.osdev.org/viewtopic.php?t=32953, the size
+ * of records into the attribute table never equals to
+ * sizeof(efi_memory_descriptor). The correct one for indexing the array
+ * resides in the attributet table.
+ */
+ for (i = 0; i < nentries; i++) {
+ xo_emit("{Lwc:ID}{:id/%#x}\n", i);
+ xo_emit("{Lwc:Attributes}{:attributes/%#x}\n", desc->attrs);
+ xo_emit("{Lwc:Type}{:type/%#x}\n", desc->type);
+ xo_emit("{Lwc:Pages}{:pages/%#x}\n", desc->pages);
+ xo_emit("{Lwc:Phyaddr}{:phyaddr/%#p}\n", desc->phy_addr);
+ xo_emit("{Lwc:Virtaddr}{:virtaddr/%#p}\n", desc->virt_addr);
+ desc = (const struct efi_memory_descriptor *)(const void *)
+ ((const char *)desc + attr->descriptor_size);
+ }
+
+ xo_close_container("attributes");
+
+ xo_close_container("memory");
+
+ if (xo_finish() < 0)
+ xo_err(EX_IOERR, "stdout");
+}
+
static void usage(void)
{
xo_error("usage: efitable [-g guid | -t name] [--libxo]\n");
diff --git a/usr.sbin/fwget/Makefile b/usr.sbin/fwget/Makefile
index 1cdf0f18230d..4c934aee3413 100644
--- a/usr.sbin/fwget/Makefile
+++ b/usr.sbin/fwget/Makefile
@@ -2,6 +2,6 @@ PACKAGE= fwget
SCRIPTS= fwget
MAN= fwget.8
-SUBDIR= pci
+SUBDIR= pci usb
.include <bsd.prog.mk>
diff --git a/usr.sbin/fwget/fwget.8 b/usr.sbin/fwget/fwget.8
index 7b8b606cc591..86e304775e2d 100644
--- a/usr.sbin/fwget/fwget.8
+++ b/usr.sbin/fwget/fwget.8
@@ -23,7 +23,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd June 27, 2024
+.Dd July 7, 2025
.Dt FWGET 8
.Os
.Sh NAME
@@ -47,7 +47,11 @@ Dry run, only show needed packages
.It Fl v
Be more verbose
.It Ar subsystem
-Hardware subsystem, default pci
+Hardware subsystem(s), default is all supported subsystems.
+Space separated hardware subsystems, accepts
+.Cm pci
+and
+.Cm usb
.El
.Sh SEE ALSO
.Xr firmware 9
@@ -64,4 +68,8 @@ utility and this manual page were written by
.An Emmanuel Vadot Aq Mt manu@FreeBSD.org
for Beckhoff Automation GmbH & Co\. KG.
.Sh CAVEATS
-This utility currently only supports the pci subsystem.
+This utility currently only supports the
+.Xr pci 4
+and
+.Xr usb 4
+subsystems.
diff --git a/usr.sbin/fwget/fwget.sh b/usr.sbin/fwget/fwget.sh
index 138a2a26bfb1..de1e6fa51f0f 100755
--- a/usr.sbin/fwget/fwget.sh
+++ b/usr.sbin/fwget/fwget.sh
@@ -35,7 +35,7 @@ usage()
Usage: $(basename "$0") [options] [subsystem]
Supported subsystems
- pci
+ pci, usb
Options:
-n -- Do not install packages, only print the results
@@ -100,9 +100,9 @@ done
shift $(($OPTIND - 1))
subsystems="$@"
-# Default searching PCI subsystem
+# Default searching PCI and USB subsystem
if [ -z "${subsystems}" ]; then
- subsystems="pci"
+ subsystems="pci usb"
fi
# Fail early on unsupported subsystem
diff --git a/usr.sbin/fwget/usb/Makefile b/usr.sbin/fwget/usb/Makefile
new file mode 100644
index 000000000000..315e9c743cc8
--- /dev/null
+++ b/usr.sbin/fwget/usb/Makefile
@@ -0,0 +1,10 @@
+PACKAGE= fwget
+
+SCRIPTS=usb \
+ usb_ralink
+
+BINDIR= ${LIBEXECDIR}/fwget
+
+MAN=
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/fwget/usb/usb b/usr.sbin/fwget/usb/usb
new file mode 100755
index 000000000000..fef6bc76ba89
--- /dev/null
+++ b/usr.sbin/fwget/usb/usb
@@ -0,0 +1,43 @@
+#
+# Copyright 2023 Beckhoff Automation GmbH & Co. KG
+# Copyright 2023 Bjoern A. Zeeb
+# Copyright 2025 Jesper Schmitz Mouridsen
+
+# SPDX-License-Identifier: BSD-2-Clause
+
+
+usb_get_vendor()
+{
+ local hexvendor=$(echo $1 | sed 's/.*idVendor=\(0x[0-9a-z]*\).*/\1/')
+ case "${hexvendor}" in
+ 0x148f) echo "ralink" ;;
+ esac
+}
+
+usb_get_device()
+{
+ local hexdevice=$(echo $1 | sed 's/.*idProduct=\(0x[0-9a-z]*\).*/\1/')
+ echo "${hexdevice}"
+
+}
+
+usb_search_packages()
+{
+ local IFS
+
+ oldifs=$IFS
+ IFS=$'\n'
+ for fulldevice in $(usbconfig -l dump_device_desc); do
+ vendor=$(usb_get_vendor "${fulldevice}")
+ if [ -z "${vendor}" ]; then
+ continue
+ fi
+ device=$(usb_get_device "${fulldevice}")
+ log_verbose "Trying to match device ${device} and vendor ${vendor} with usb_${vendor}"
+ if [ -f ${LIBEXEC_PATH}/usb_${vendor} ]; then
+ . ${LIBEXEC_PATH}/usb_${vendor}
+ usb_${vendor} ${device}
+ fi
+ done
+ IFS=${oldifs}
+}
diff --git a/usr.sbin/fwget/usb/usb_ralink b/usr.sbin/fwget/usb/usb_ralink
new file mode 100755
index 000000000000..8d3135063011
--- /dev/null
+++ b/usr.sbin/fwget/usb/usb_ralink
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2025 Jesper Schmitz Mouridsen
+#
+# SPDX-License-Identifier: BSD-2-Clause
+
+usb_ralink()
+{
+
+ case "$1" in
+ 0x7601) addpkg "wifi-firmware-mt7601u-kmod"; return 1 ;;
+ esac
+}
diff --git a/usr.sbin/gstat/gstat.8 b/usr.sbin/gstat/gstat.8
index 02dbbbc54a3d..e882aa75b8d7 100644
--- a/usr.sbin/gstat/gstat.8
+++ b/usr.sbin/gstat/gstat.8
@@ -122,6 +122,9 @@ Quit
.El
.Sh EXIT STATUS
.Ex -std
+.Sh EXAMPLES
+To filter the output to only physical disks named ada0 through ada4:
+.Dl # gstat -f ada[0-4]$
.Sh SEE ALSO
.Xr systat 1 ,
.Xr geom 4 ,
diff --git a/usr.sbin/inetd/inetd.conf b/usr.sbin/inetd/inetd.conf
index 40f1e1285af6..a8359ea793f5 100644
--- a/usr.sbin/inetd/inetd.conf
+++ b/usr.sbin/inetd/inetd.conf
@@ -7,8 +7,8 @@
#
#ftp stream tcp nowait root /usr/libexec/ftpd ftpd -l
#ftp stream tcp6 nowait root /usr/libexec/ftpd ftpd -l
-#ssh stream tcp nowait root /usr/sbin/sshd sshd -i -4
-#ssh stream tcp6 nowait root /usr/sbin/sshd sshd -i -6
+#ssh stream tcp nowait root /usr/sbin/sshd sshd -i
+#ssh stream tcp6 nowait root /usr/sbin/sshd sshd -i
#telnet stream tcp nowait root /usr/local/libexec/telnetd telnetd
#telnet stream tcp6 nowait root /usr/local/libexec/telnetd telnetd
#shell stream tcp nowait root /usr/local/sbin/rshd rshd
diff --git a/usr.sbin/lastlogin/lastlogin.8 b/usr.sbin/lastlogin/lastlogin.8
index 3b2d47fdaf76..9fd5c88d02cd 100644
--- a/usr.sbin/lastlogin/lastlogin.8
+++ b/usr.sbin/lastlogin/lastlogin.8
@@ -73,7 +73,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl f Ar file
Open last login database
@@ -93,7 +93,7 @@ last login database
.Xr last 1 ,
.Xr getutxent 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr ac 8
.Sh AUTHORS
.An -nosplit
diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c
index 4efcd20ad91a..c0fcadf11fba 100644
--- a/usr.sbin/makefs/ffs.c
+++ b/usr.sbin/makefs/ffs.c
@@ -1056,7 +1056,7 @@ ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
reclen = DIRSIZ_SWAP(0, &de, needswap);
de.d_reclen = ufs_rw16(reclen, needswap);
- dp = (struct direct *)(dbuf->buf + dbuf->cur);
+ dp = dbuf->buf == NULL ? NULL : (struct direct *)(dbuf->buf + dbuf->cur);
llen = 0;
if (dp != NULL)
llen = DIRSIZ_SWAP(0, dp, needswap);
diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8
index a11eaf8206e9..d20f69d87559 100644
--- a/usr.sbin/makefs/makefs.8
+++ b/usr.sbin/makefs/makefs.8
@@ -33,8 +33,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd January 19, 2024
-
+.Dd July 19, 2025
.Dt MAKEFS 8
.Os
.Sh NAME
@@ -551,6 +550,12 @@ This option allows the default heuristic to be overridden.
.It verify-txgs
Prompt OpenZFS to verify pool metadata during import.
This is disabled by default as it may significantly increase import times.
+.It poolguid
+Use the specified 64-bit integer as the pool GUID.
+If this option is not specified, the pool GUID will be random but fixed
+across multiple identical invocations of
+.Nm .
+This option is useful for testing but not required for reproducibility.
.It poolname
The name of the ZFS pool.
This option must be specified.
@@ -596,10 +601,17 @@ The following properties may be set for a dataset:
.Bl -tag -compact -offset indent
.It atime
.It canmount
+.It compression
.It exec
.It mountpoint
.It setuid
.El
+Note that
+.Nm
+does not implement compression of files included in the image,
+regardless of the value of the
+.Dv compression
+property.
.El
.Sh SEE ALSO
.Xr mtree 5 ,
diff --git a/usr.sbin/makefs/tests/Makefile b/usr.sbin/makefs/tests/Makefile
index 345b728651d6..748bafa06211 100644
--- a/usr.sbin/makefs/tests/Makefile
+++ b/usr.sbin/makefs/tests/Makefile
@@ -7,10 +7,6 @@ ATF_TESTS_SH+= makefs_msdos_tests
TEST_METADATA.makefs_msdos_tests+= required_files="/sbin/mount_msdosfs"
.if ${MK_ZFS} != "no"
ATF_TESTS_SH+= makefs_zfs_tests
-# ZFS pools created by makefs always have the same GUID, so OpenZFS
-# refuses to import more than one at a time. Thus the ZFS tests cannot
-# be run in parallel for now.
-TEST_METADATA.makefs_zfs_tests+= is_exclusive="true"
.endif
BINDIR= ${TESTSDIR}
diff --git a/usr.sbin/makefs/tests/makefs_msdos_tests.sh b/usr.sbin/makefs/tests/makefs_msdos_tests.sh
index b36b43b3abf6..fb94429b477b 100644
--- a/usr.sbin/makefs/tests/makefs_msdos_tests.sh
+++ b/usr.sbin/makefs/tests/makefs_msdos_tests.sh
@@ -4,7 +4,7 @@
# Copyright (c) 2025 The FreeBSD Foundation
#
# This software was developed by Klara, Inc.
-# under sponsorship from the FreeBSD Foundation and the Sovereign Tech Agency.
+# under sponsorship from the FreeBSD Foundation.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
diff --git a/usr.sbin/makefs/tests/makefs_zfs_tests.sh b/usr.sbin/makefs/tests/makefs_zfs_tests.sh
index 520d1f211ac3..2fafce85b347 100644
--- a/usr.sbin/makefs/tests/makefs_zfs_tests.sh
+++ b/usr.sbin/makefs/tests/makefs_zfs_tests.sh
@@ -28,7 +28,7 @@
# SUCH DAMAGE.
#
-MAKEFS="makefs -t zfs -o verify-txgs=true"
+MAKEFS="makefs -t zfs -o verify-txgs=true -o poolguid=$$"
ZFS_POOL_NAME="makefstest$$"
TEST_ZFS_POOL_NAME="$TMPDIR/poolname"
@@ -124,6 +124,95 @@ basic_cleanup()
common_cleanup
}
+#
+# Try configuring various compression algorithms.
+#
+atf_test_case compression cleanup
+compression_body()
+{
+ create_test_inputs
+
+ cd $TEST_INPUTS_DIR
+ mkdir dir
+ mkdir dir2
+ cd -
+
+ for alg in off on lzjb gzip gzip-1 gzip-2 gzip-3 gzip-4 \
+ gzip-5 gzip-6 gzip-7 gzip-8 gzip-9 zle lz4 zstd; do
+ atf_check $MAKEFS -s 1g -o rootpath=/ \
+ -o poolname=$ZFS_POOL_NAME \
+ -o fs=${ZFS_POOL_NAME}\;compression=$alg \
+ -o fs=${ZFS_POOL_NAME}/dir \
+ -o fs=${ZFS_POOL_NAME}/dir2\;compression=off \
+ $TEST_IMAGE $TEST_INPUTS_DIR
+
+ import_image
+
+ check_image_contents
+
+ if [ $alg = gzip-6 ]; then
+ # ZFS reports gzip-6 as just gzip since it uses
+ # a default compression level of 6.
+ alg=gzip
+ fi
+ # The "dir" dataset's compression algorithm should be
+ # inherited from the root dataset.
+ atf_check -o inline:$alg\\n -e empty -s exit:0 \
+ zfs get -H -o value compression ${ZFS_POOL_NAME}
+ atf_check -o inline:$alg\\n -e empty -s exit:0 \
+ zfs get -H -o value compression ${ZFS_POOL_NAME}/dir
+ atf_check -o inline:off\\n -e empty -s exit:0 \
+ zfs get -H -o value compression ${ZFS_POOL_NAME}/dir2
+
+ atf_check -e ignore dd if=/dev/random \
+ of=${TEST_MOUNT_DIR}/dir/random bs=1M count=10
+ atf_check -e ignore dd if=/dev/zero \
+ of=${TEST_MOUNT_DIR}/dir/zero bs=1M count=10
+ atf_check -e ignore dd if=/dev/zero \
+ of=${TEST_MOUNT_DIR}/dir2/zero bs=1M count=10
+
+ # Export and reimport to ensure that everything is
+ # flushed to disk.
+ atf_check zpool export ${ZFS_POOL_NAME}
+ atf_check -o ignore -e empty -s exit:0 \
+ zdb -e -p /dev/$(cat $TEST_MD_DEVICE_FILE) -mmm -ddddd \
+ $ZFS_POOL_NAME
+ atf_check zpool import -R $TEST_MOUNT_DIR $ZFS_POOL_NAME
+
+ if [ $alg = off ]; then
+ # If compression is off, the files should be the
+ # same size as the input.
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/random" \
+ du -m ${TEST_MOUNT_DIR}/dir/random
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir/zero
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir2/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir2/zero
+ else
+ # If compression is on, the dir/zero file ought
+ # to be smaller.
+ atf_check -o match:"^1[[:space:]]+${TEST_MOUNT_DIR}/dir/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir/zero
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/random" \
+ du -m ${TEST_MOUNT_DIR}/dir/random
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir2/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir2/zero
+ fi
+
+ atf_check zpool destroy ${ZFS_POOL_NAME}
+ atf_check rm -f ${TEST_ZFS_POOL_NAME}
+ atf_check mdconfig -d -u $(cat ${TEST_MD_DEVICE_FILE})
+ atf_check rm -f ${TEST_MD_DEVICE_FILE}
+ done
+}
+compression_cleanup()
+{
+ common_cleanup
+}
+
+#
+# Try destroying a dataset that was created by makefs.
+#
atf_test_case dataset_removal cleanup
dataset_removal_body()
{
@@ -939,6 +1028,7 @@ atf_init_test_cases()
{
atf_add_test_case autoexpand
atf_add_test_case basic
+ atf_add_test_case compression
atf_add_test_case dataset_removal
atf_add_test_case devfs
atf_add_test_case empty_dir
diff --git a/usr.sbin/makefs/zfs.c b/usr.sbin/makefs/zfs.c
index 66e7f8dafc9c..8d50c450541b 100644
--- a/usr.sbin/makefs/zfs.c
+++ b/usr.sbin/makefs/zfs.c
@@ -38,6 +38,7 @@
#include <stdalign.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -85,6 +86,8 @@ zfs_prep_opts(fsinfo_t *fsopts)
0, 0, "Bootable dataset" },
{ '\0', "mssize", &zfs->mssize, OPT_INT64,
MINMSSIZE, MAXMSSIZE, "Metaslab size" },
+ { '\0', "poolguid", &zfs->poolguid, OPT_INT64,
+ 0, INT64_MAX, "ZFS pool GUID" },
{ '\0', "poolname", &zfs->poolname, OPT_STRPTR,
0, 0, "ZFS pool name" },
{ '\0', "rootpath", &zfs->rootpath, OPT_STRPTR,
@@ -547,7 +550,8 @@ pool_init(zfs_opt_t *zfs)
{
uint64_t dnid;
- zfs->poolguid = randomguid();
+ if (zfs->poolguid == 0)
+ zfs->poolguid = randomguid();
zfs->vdevguid = randomguid();
zfs->mos = objset_alloc(zfs, DMU_OST_META);
diff --git a/usr.sbin/makefs/zfs/dsl.c b/usr.sbin/makefs/zfs/dsl.c
index f7264b9d2ca7..8a8cee7c82b2 100644
--- a/usr.sbin/makefs/zfs/dsl.c
+++ b/usr.sbin/makefs/zfs/dsl.c
@@ -193,6 +193,39 @@ dsl_dir_set_prop(zfs_opt_t *zfs, zfs_dsl_dir_t *dir, const char *key,
nvlist_add_uint64(nvl, key, 0);
else
errx(1, "invalid value `%s' for %s", val, key);
+ } else if (strcmp(key, "compression") == 0) {
+ size_t i;
+
+ const struct zfs_compression_algorithm {
+ const char *name;
+ enum zio_compress alg;
+ } compression_algorithms[] = {
+ { "off", ZIO_COMPRESS_OFF },
+ { "on", ZIO_COMPRESS_ON },
+ { "lzjb", ZIO_COMPRESS_LZJB },
+ { "gzip", ZIO_COMPRESS_GZIP_6 },
+ { "gzip-1", ZIO_COMPRESS_GZIP_1 },
+ { "gzip-2", ZIO_COMPRESS_GZIP_2 },
+ { "gzip-3", ZIO_COMPRESS_GZIP_3 },
+ { "gzip-4", ZIO_COMPRESS_GZIP_4 },
+ { "gzip-5", ZIO_COMPRESS_GZIP_5 },
+ { "gzip-6", ZIO_COMPRESS_GZIP_6 },
+ { "gzip-7", ZIO_COMPRESS_GZIP_7 },
+ { "gzip-8", ZIO_COMPRESS_GZIP_8 },
+ { "gzip-9", ZIO_COMPRESS_GZIP_9 },
+ { "zle", ZIO_COMPRESS_ZLE },
+ { "lz4", ZIO_COMPRESS_LZ4 },
+ { "zstd", ZIO_COMPRESS_ZSTD },
+ };
+ for (i = 0; i < nitems(compression_algorithms); i++) {
+ if (strcmp(val, compression_algorithms[i].name) == 0) {
+ nvlist_add_uint64(nvl, key,
+ compression_algorithms[i].alg);
+ break;
+ }
+ }
+ if (i == nitems(compression_algorithms))
+ errx(1, "invalid compression algorithm `%s'", val);
} else {
errx(1, "unknown property `%s'", key);
}
@@ -236,9 +269,6 @@ dsl_init(zfs_opt_t *zfs)
zfs->rootdsldir = dsl_dir_alloc(zfs, NULL);
- nvlist_add_uint64(zfs->rootdsldir->propsnv, "compression",
- ZIO_COMPRESS_OFF);
-
zfs->rootds = dsl_dataset_alloc(zfs, zfs->rootdsldir);
zfs->rootdsldir->headds = zfs->rootds;
@@ -288,9 +318,13 @@ dsl_init(zfs_opt_t *zfs)
}
/*
- * Set the root dataset's mount point if the user didn't override the
- * default.
+ * Set the root dataset's mount point and compression strategy if the
+ * user didn't override the defaults.
*/
+ if (nvpair_find(zfs->rootdsldir->propsnv, "compression") == NULL) {
+ nvlist_add_uint64(zfs->rootdsldir->propsnv, "compression",
+ ZIO_COMPRESS_OFF);
+ }
if (nvpair_find(zfs->rootdsldir->propsnv, "mountpoint") == NULL) {
nvlist_add_string(zfs->rootdsldir->propsnv, "mountpoint",
zfs->rootpath);
diff --git a/usr.sbin/mfiutil/Makefile b/usr.sbin/mfiutil/Makefile
index da1c9249f8cd..85b66d4b6f49 100644
--- a/usr.sbin/mfiutil/Makefile
+++ b/usr.sbin/mfiutil/Makefile
@@ -9,7 +9,7 @@ MLINKS= mfiutil.8 mrsasutil.8
CFLAGS.gcc+= -fno-builtin-strftime
-LIBADD= util
+LIBADD= sbuf util
# Here be dragons
.ifdef DEBUG
diff --git a/usr.sbin/mfiutil/mfi_bbu.c b/usr.sbin/mfiutil/mfi_bbu.c
index e97227d47c70..3e78e791dfc2 100644
--- a/usr.sbin/mfiutil/mfi_bbu.c
+++ b/usr.sbin/mfiutil/mfi_bbu.c
@@ -40,41 +40,23 @@
/* The autolearn period is given in seconds. */
void
-mfi_autolearn_period(uint32_t period, char *buf, size_t sz)
+mfi_autolearn_period(FILE *fp, uint32_t period)
{
unsigned int d, h;
- char *tmp;
d = period / (24 * 3600);
h = (period % (24 * 3600)) / 3600;
- tmp = buf;
if (d != 0) {
- int fmt_len;
- fmt_len = snprintf(buf, sz, "%u day%s", d, d == 1 ? "" : "s");
- if (fmt_len < 0) {
- *buf = 0;
- return;
- }
- if ((size_t)fmt_len >= sz) {
- return;
- }
- tmp += fmt_len;
- sz -= tmp - buf;
- if (h != 0) {
- fmt_len = snprintf(tmp, sz, ", ");
- if (fmt_len < 0 || (size_t)fmt_len >= sz) {
- return;
- }
- tmp += fmt_len;
- sz -= 2;
- }
+ fprintf(fp, "%u day%s", d, d == 1 ? "" : "s");
+ if (h != 0)
+ fprintf(fp, ", ");
}
if (h != 0)
- snprintf(tmp, sz, "%u hour%s", h, h == 1 ? "" : "s");
+ fprintf(fp, "%u hour%s", h, h == 1 ? "" : "s");
if (d == 0 && h == 0)
- snprintf(tmp, sz, "less than 1 hour");
+ fprintf(fp, "less than 1 hour");
}
/* The time to the next relearn is given in seconds since 1/1/2000. */
@@ -89,28 +71,28 @@ mfi_next_learn_time(uint32_t next_learn_time, char *buf, size_t sz)
tm.tm_year = 100;
basetime = timegm(&tm);
basetime += (time_t)next_learn_time;
- len = snprintf(buf, sz, "%s", ctime(&basetime));
- if (len > 0)
+ len = strlcpy(buf, ctime(&basetime), sz);
+ if (len < sz)
/* Get rid of the newline added by ctime(3). */
buf[len - 1] = '\0';
}
void
-mfi_autolearn_mode(uint8_t mode, char *buf, size_t sz)
+mfi_autolearn_mode(FILE *fp, uint8_t mode)
{
switch (mode) {
case 0:
- snprintf(buf, sz, "enabled");
+ fprintf(fp, "enabled");
break;
case 1:
- snprintf(buf, sz, "disabled");
+ fprintf(fp, "disabled");
break;
case 2:
- snprintf(buf, sz, "warn via event");
+ fprintf(fp, "warn via event");
break;
default:
- snprintf(buf, sz, "mode 0x%02x", mode);
+ fprintf(fp, "mode 0x%02x", mode);
break;
}
}
diff --git a/usr.sbin/mfiutil/mfi_drive.c b/usr.sbin/mfiutil/mfi_drive.c
index e8e945c566c4..c7c5aeb02f14 100644
--- a/usr.sbin/mfiutil/mfi_drive.c
+++ b/usr.sbin/mfiutil/mfi_drive.c
@@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/errno.h>
+#include <sys/sbuf.h>
#include <ctype.h>
#include <err.h>
#include <fcntl.h>
@@ -56,9 +57,9 @@ const char *
mfi_drive_name(struct mfi_pd_info *pinfo, uint16_t device_id, uint32_t def)
{
struct mfi_pd_info info;
+ struct sbuf sb;
static char buf[16];
- char *p;
- int error, fd, len;
+ int fd;
if ((def & MFI_DNAME_HONOR_OPTS) != 0 &&
(mfi_opts & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID)) != 0)
@@ -89,40 +90,29 @@ mfi_drive_name(struct mfi_pd_info *pinfo, uint16_t device_id, uint32_t def)
pinfo = &info;
}
- p = buf;
- len = sizeof(buf);
+ sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
if (def & MFI_DNAME_DEVICE_ID) {
if (device_id == 0xffff)
- error = snprintf(p, len, "MISSING");
+ sbuf_printf(&sb, "MISSING");
else
- error = snprintf(p, len, "%2u", device_id);
- if (error >= 0) {
- p += error;
- len -= error;
- }
+ sbuf_printf(&sb, "%2u", device_id);
}
if ((def & (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID)) ==
- (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID) && len >= 2) {
- *p++ = ' ';
- len--;
- *p = '\0';
- len--;
+ (MFI_DNAME_ES|MFI_DNAME_DEVICE_ID)) {
+ sbuf_cat(&sb, " ");
}
if (def & MFI_DNAME_ES) {
if (pinfo->encl_device_id == 0xffff)
- error = snprintf(p, len, "S%u",
+ sbuf_printf(&sb, "S%u",
pinfo->slot_number);
else if (pinfo->encl_device_id == pinfo->ref.v.device_id)
- error = snprintf(p, len, "E%u",
+ sbuf_printf(&sb, "E%u",
pinfo->encl_index);
else
- error = snprintf(p, len, "E%u:S%u",
+ sbuf_printf(&sb, "E%u:S%u",
pinfo->encl_index, pinfo->slot_number);
- if (error >= 0) {
- p += error;
- len -= error;
- }
}
+ sbuf_finish(&sb);
return (buf);
}
diff --git a/usr.sbin/mfiutil/mfi_show.c b/usr.sbin/mfiutil/mfi_show.c
index bf85c8b82d69..2d413f2a46b4 100644
--- a/usr.sbin/mfiutil/mfi_show.c
+++ b/usr.sbin/mfiutil/mfi_show.c
@@ -218,8 +218,9 @@ show_battery(int ac, char **av __unused)
printf(" Current Voltage: %d mV\n", stat.voltage);
printf(" Temperature: %d C\n", stat.temperature);
if (show_props) {
- mfi_autolearn_period(props.auto_learn_period, buf, sizeof(buf));
- printf(" Autolearn period: %s\n", buf);
+ printf(" Autolearn period: ");
+ mfi_autolearn_period(stdout, props.auto_learn_period);
+ printf("\n");
if (props.auto_learn_mode != 0)
snprintf(buf, sizeof(buf), "never");
else
@@ -229,8 +230,9 @@ show_battery(int ac, char **av __unused)
printf(" Learn delay interval: %u hour%s\n",
props.learn_delay_interval,
props.learn_delay_interval != 1 ? "s" : "");
- mfi_autolearn_mode(props.auto_learn_mode, buf, sizeof(buf));
- printf(" Autolearn mode: %s\n", buf);
+ printf(" Autolearn mode: ");
+ mfi_autolearn_mode(stdout, props.auto_learn_mode);
+ printf("\n");
if (props.bbu_mode != 0)
printf(" BBU Mode: %d\n", props.bbu_mode);
}
diff --git a/usr.sbin/mfiutil/mfiutil.h b/usr.sbin/mfiutil/mfiutil.h
index 34b423098862..86b03998163c 100644
--- a/usr.sbin/mfiutil/mfiutil.h
+++ b/usr.sbin/mfiutil/mfiutil.h
@@ -175,9 +175,9 @@ int mfi_bbu_get_props(int fd, struct mfi_bbu_properties *props,
uint8_t *statusp);
int mfi_bbu_set_props(int fd, struct mfi_bbu_properties *props,
uint8_t *statusp);
-void mfi_autolearn_period(uint32_t, char *, size_t);
+void mfi_autolearn_period(FILE *, uint32_t);
void mfi_next_learn_time(uint32_t, char *, size_t);
-void mfi_autolearn_mode(uint8_t, char *, size_t);
+void mfi_autolearn_mode(FILE *, uint8_t);
int get_mfi_unit(const char *dev);
char *get_mfi_type(const char *dev);
diff --git a/usr.sbin/rip6query/rip6query.8 b/usr.sbin/rip6query/rip6query.8
index 856a59138bc1..92e49f5ade58 100644
--- a/usr.sbin/rip6query/rip6query.8
+++ b/usr.sbin/rip6query/rip6query.8
@@ -29,13 +29,19 @@
.\"
.\" $Id: rip6query.8,v 1.2 2000/01/19 06:24:55 itojun Exp $
.\"
-.Dd October 7, 1999
+.Dd May 20, 2025
.Dt RIP6QUERY 8
.Os
.Sh NAME
.Nm rip6query
.Nd RIPng debugging tool
.\"
+.Sh DEPRECATION NOTICE
+The
+.Nm
+utility is deprecated and will be removed in
+.Fx 16.0 .
+.\"
.Sh SYNOPSIS
.Nm
.Op Fl I Ar interface
diff --git a/usr.sbin/route6d/route6d.8 b/usr.sbin/route6d/route6d.8
index 3a7bc8721923..e9ad3266ba26 100644
--- a/usr.sbin/route6d/route6d.8
+++ b/usr.sbin/route6d/route6d.8
@@ -14,12 +14,17 @@
.\" LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
.\" A PARTICULAR PURPOSE.
.\"
-.Dd November 18, 2012
+.Dd May 20, 2025
.Dt ROUTE6D 8
.Os
.Sh NAME
.Nm route6d
.Nd RIP6 Routing Daemon
+.Sh DEPRECATION NOTICE
+The
+.Nm
+utility is deprecated and will be removed in
+.Fx 16.0 .
.Sh SYNOPSIS
.Nm
.Op Fl adDhlnqsS
diff --git a/usr.sbin/sesutil/sesutil.8 b/usr.sbin/sesutil/sesutil.8
index 664dcab593e9..d4960b3ec6bf 100644
--- a/usr.sbin/sesutil/sesutil.8
+++ b/usr.sbin/sesutil/sesutil.8
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 5, 2022
+.Dd July 16, 2025
.Dt SESUTIL 8
.Os
.Sh NAME
@@ -129,7 +129,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
.El
.Sh EXAMPLES
Turn off all locate LEDs:
@@ -146,7 +146,7 @@ Turn on the fault LED for a drive bay not associated with a device:
.Dl Nm Cm fault -u /dev/ses2 7 on
.Sh SEE ALSO
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr ses 4
.Sh HISTORY
The
diff --git a/usr.sbin/trim/trim.8 b/usr.sbin/trim/trim.8
index 1ac10d7e3d46..a4874c54c183 100644
--- a/usr.sbin/trim/trim.8
+++ b/usr.sbin/trim/trim.8
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 18, 2019
+.Dd July 20, 2025
.Dt TRIM 8
.Os
.Sh NAME
@@ -36,7 +36,7 @@
.Bk -words
.Sm off
.Ar offset
-.Op Cm K | k | M | m | G | g | T | t ]
+.Op Cm K | k | M | m | G | g | T | t | P | p | E | e ]
.Sm on
.Xc
.Ek
@@ -68,13 +68,13 @@ Overrides
.It Fl l Xo
.Sm off
.Ar offset
-.Op Cm K | k | M | m | G | g | T | t
+.Op Cm K | k | M | m | G | g | T | t | P | p | E | e
.Sm on
.Xc
.It Fl o Xo
.Sm off
.Ar offset
-.Op Cm K | k | M | m | G | g | T | t
+.Op Cm K | k | M | m | G | g | T | t | P | p | E | e
.Sm on
.Xc
Specify the length
@@ -88,12 +88,14 @@ unless one or both of these options are presented.
The argument may be suffixed with one of
.Cm K ,
.Cm M ,
-.Cm G
+.Cm G ,
+.Cm T ,
+.Cm P
or
-.Cm T
+.Cm E
(either upper or lower case) to indicate a multiple of
-Kilobytes, Megabytes, Gigabytes or Terabytes
-respectively.
+Kilobytes, Megabytes, Gigabytes, Terabytes, Petabytes or
+Exabytes, respectively.
.It Fl q
Do not output anything except of possible error messages (quiet mode).
Overrides
diff --git a/usr.sbin/trim/trim.c b/usr.sbin/trim/trim.c
index 3e187faa0fb3..27f57ac2fb72 100644
--- a/usr.sbin/trim/trim.c
+++ b/usr.sbin/trim/trim.c
@@ -114,7 +114,7 @@ main(int argc, char **argv)
*
* trim -f -- /dev/da0 -r rfile
*/
-
+
if (strcmp(argv[optind-1], "--") != 0) {
for (ch = optind; ch < argc; ch++)
if (argv[ch][0] == '-')
@@ -127,6 +127,9 @@ main(int argc, char **argv)
if (argc < 1)
usage(name);
+ if (dryrun)
+ printf("dry run: add -f to actually perform the operation\n");
+
while ((fname = *argv++) != NULL)
if (trim(fname, offset, length, dryrun, verbose) < 0)
error++;
@@ -213,10 +216,8 @@ trim(const char *path, off_t offset, off_t length, bool dryrun, bool verbose)
printf("trim %s offset %ju length %ju\n",
path, (uintmax_t)offset, (uintmax_t)length);
- if (dryrun) {
- printf("dry run: add -f to actually perform the operation\n");
+ if (dryrun)
return (0);
- }
fd = opendev(path, O_RDWR | O_DIRECT);
arg[0] = offset;
@@ -237,7 +238,7 @@ static void
usage(const char *name)
{
(void)fprintf(stderr,
- "usage: %s [-[lo] offset[K|k|M|m|G|g|T|t]] [-r rfile] [-Nfqv] device ...\n",
+ "usage: %s [-[lo] offset[K|k|M|m|G|g|T|t|P|p|E|e]] [-r rfile] [-Nfqv] device ...\n",
name);
exit(EX_USAGE);
}